blob: 047c47224dba5eee24de524334fcc24844198331 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux INET6 implementation
3 * FIB front-end.
4 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14/* Changes:
15 *
16 * YOSHIFUJI Hideaki @USAGI
17 * reworked default router selection.
18 * - respect outgoing interface
19 * - select from (probably) reachable routers (i.e.
20 * routers in REACHABLE, STALE, DELAY or PROBE states).
21 * - always select the same router if it is (probably)
22 * reachable. otherwise, round-robin the list.
YOSHIFUJI Hideakic0bece92006-08-23 17:23:25 -070023 * Ville Nuorvala
24 * Fixed routing subtrees.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
26
Joe Perchesf3213832012-05-15 14:11:53 +000027#define pr_fmt(fmt) "IPv6: " fmt
28
Randy Dunlap4fc268d2006-01-11 12:17:47 -080029#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040031#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/types.h>
33#include <linux/times.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/net.h>
37#include <linux/route.h>
38#include <linux/netdevice.h>
39#include <linux/in6.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <linux/mroute6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/if_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/proc_fs.h>
44#include <linux/seq_file.h>
Daniel Lezcano5b7c9312008-03-03 23:28:58 -080045#include <linux/nsproxy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090046#include <linux/slab.h>
Wei Wang35732d02017-10-06 12:05:57 -070047#include <linux/jhash.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020048#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/snmp.h>
50#include <net/ipv6.h>
51#include <net/ip6_fib.h>
52#include <net/ip6_route.h>
53#include <net/ndisc.h>
54#include <net/addrconf.h>
55#include <net/tcp.h>
56#include <linux/rtnetlink.h>
57#include <net/dst.h>
Jiri Benc904af042015-08-20 13:56:31 +020058#include <net/dst_metadata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070060#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070061#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000062#include <net/nexthop.h>
Roopa Prabhu19e42e42015-07-21 10:43:48 +020063#include <net/lwtunnel.h>
Jiri Benc904af042015-08-20 13:56:31 +020064#include <net/ip_tunnels.h>
David Ahernca254492015-10-12 11:47:10 -070065#include <net/l3mdev.h>
Roopa Prabhueacb9382018-05-22 14:03:28 -070066#include <net/ip.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080067#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#ifdef CONFIG_SYSCTL
70#include <linux/sysctl.h>
71#endif
72
David Ahern30d444d2018-05-23 17:08:48 -070073static int ip6_rt_type_to_error(u8 fib6_type);
74
75#define CREATE_TRACE_POINTS
76#include <trace/events/fib6.h>
77EXPORT_TRACEPOINT_SYMBOL_GPL(fib6_table_lookup);
78#undef CREATE_TRACE_POINTS
79
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020080enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010081 RT6_NUD_FAIL_HARD = -3,
82 RT6_NUD_FAIL_PROBE = -2,
83 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020084 RT6_NUD_SUCCEED = 1
85};
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080088static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000089static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static struct dst_entry *ip6_negative_advice(struct dst_entry *);
91static void ip6_dst_destroy(struct dst_entry *);
92static void ip6_dst_ifdown(struct dst_entry *,
93 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080094static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050097static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053098static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050099static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -0700101static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
102 struct sk_buff *skb, u32 mtu);
103static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
104 struct sk_buff *skb);
David Ahern8d1c8022018-04-17 17:33:26 -0700105static int rt6_score_route(struct fib6_info *rt, int oif, int strict);
106static size_t rt6_nlmsg_size(struct fib6_info *rt);
David Ahernd4ead6b2018-04-17 17:33:16 -0700107static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -0700108 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -0700109 struct in6_addr *dest, struct in6_addr *src,
David Ahern16a16cd2017-02-02 12:37:11 -0800110 int iif, int type, u32 portid, u32 seq,
111 unsigned int flags);
David Ahern8d1c8022018-04-17 17:33:26 -0700112static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -0700113 struct in6_addr *daddr,
114 struct in6_addr *saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800116#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -0700117static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000118 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700119 const struct in6_addr *gwaddr,
120 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000121 unsigned int pref);
David Ahern8d1c8022018-04-17 17:33:26 -0700122static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000123 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700124 const struct in6_addr *gwaddr,
125 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800126#endif
127
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700128struct uncached_list {
129 spinlock_t lock;
130 struct list_head head;
131};
132
133static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
134
Xin Long510c3212018-02-14 19:06:02 +0800135void rt6_uncached_list_add(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700136{
137 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
138
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700139 rt->rt6i_uncached_list = ul;
140
141 spin_lock_bh(&ul->lock);
142 list_add_tail(&rt->rt6i_uncached, &ul->head);
143 spin_unlock_bh(&ul->lock);
144}
145
Xin Long510c3212018-02-14 19:06:02 +0800146void rt6_uncached_list_del(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700147{
148 if (!list_empty(&rt->rt6i_uncached)) {
149 struct uncached_list *ul = rt->rt6i_uncached_list;
Wei Wang81eb8442017-10-06 12:06:11 -0700150 struct net *net = dev_net(rt->dst.dev);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700151
152 spin_lock_bh(&ul->lock);
153 list_del(&rt->rt6i_uncached);
Wei Wang81eb8442017-10-06 12:06:11 -0700154 atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700155 spin_unlock_bh(&ul->lock);
156 }
157}
158
159static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
160{
161 struct net_device *loopback_dev = net->loopback_dev;
162 int cpu;
163
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500164 if (dev == loopback_dev)
165 return;
166
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700167 for_each_possible_cpu(cpu) {
168 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
169 struct rt6_info *rt;
170
171 spin_lock_bh(&ul->lock);
172 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
173 struct inet6_dev *rt_idev = rt->rt6i_idev;
174 struct net_device *rt_dev = rt->dst.dev;
175
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500176 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700177 rt->rt6i_idev = in6_dev_get(loopback_dev);
178 in6_dev_put(rt_idev);
179 }
180
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500181 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700182 rt->dst.dev = loopback_dev;
183 dev_hold(rt->dst.dev);
184 dev_put(rt_dev);
185 }
186 }
187 spin_unlock_bh(&ul->lock);
188 }
189}
190
David Ahernf8a1b432018-04-17 17:33:21 -0700191static inline const void *choose_neigh_daddr(const struct in6_addr *p,
David S. Millerf894cbf2012-07-02 21:52:24 -0700192 struct sk_buff *skb,
193 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500194{
David S. Millera7563f32012-01-26 16:29:16 -0500195 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500196 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700197 else if (skb)
198 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500199 return daddr;
200}
201
David Ahernf8a1b432018-04-17 17:33:21 -0700202struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
203 struct net_device *dev,
204 struct sk_buff *skb,
205 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700206{
David S. Miller39232972012-01-26 15:22:32 -0500207 struct neighbour *n;
208
David Ahernf8a1b432018-04-17 17:33:21 -0700209 daddr = choose_neigh_daddr(gw, skb, daddr);
210 n = __ipv6_neigh_lookup(dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500211 if (n)
212 return n;
Stefano Brivio7adf3242019-01-02 13:29:27 +0100213
214 n = neigh_create(&nd_tbl, daddr, dev);
215 return IS_ERR(n) ? NULL : n;
David Ahernf8a1b432018-04-17 17:33:21 -0700216}
217
218static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
219 struct sk_buff *skb,
220 const void *daddr)
221{
222 const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
223
224 return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500225}
226
Julian Anastasov63fca652017-02-06 23:14:15 +0200227static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
228{
229 struct net_device *dev = dst->dev;
230 struct rt6_info *rt = (struct rt6_info *)dst;
231
David Ahernf8a1b432018-04-17 17:33:21 -0700232 daddr = choose_neigh_daddr(&rt->rt6i_gateway, NULL, daddr);
Julian Anastasov63fca652017-02-06 23:14:15 +0200233 if (!daddr)
234 return;
235 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
236 return;
237 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
238 return;
239 __ipv6_confirm_neigh(dev, daddr);
240}
241
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800242static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 .gc = ip6_dst_gc,
245 .gc_thresh = 1024,
246 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800247 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000248 .mtu = ip6_mtu,
David Ahernd4ead6b2018-04-17 17:33:16 -0700249 .cow_metrics = dst_cow_metrics_generic,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 .destroy = ip6_dst_destroy,
251 .ifdown = ip6_dst_ifdown,
252 .negative_advice = ip6_negative_advice,
253 .link_failure = ip6_link_failure,
254 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700255 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500256 .local_out = __ip6_local_out,
David Ahernf8a1b432018-04-17 17:33:21 -0700257 .neigh_lookup = ip6_dst_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200258 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259};
260
Steffen Klassertebb762f2011-11-23 02:12:51 +0000261static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800262{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000263 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
264
265 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800266}
267
David S. Miller6700c272012-07-17 03:29:28 -0700268static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
269 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700270{
271}
272
David S. Miller6700c272012-07-17 03:29:28 -0700273static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
274 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700275{
276}
277
David S. Miller14e50e52007-05-24 18:17:54 -0700278static struct dst_ops ip6_dst_blackhole_ops = {
279 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700280 .destroy = ip6_dst_destroy,
281 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000282 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800283 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700284 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700285 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700286 .cow_metrics = dst_cow_metrics_generic,
David Ahernf8a1b432018-04-17 17:33:21 -0700287 .neigh_lookup = ip6_dst_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700288};
289
David S. Miller62fa8a82011-01-26 20:51:05 -0800290static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800291 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800292};
293
David Ahern8d1c8022018-04-17 17:33:26 -0700294static const struct fib6_info fib6_null_entry_template = {
David Ahern93c2fb22018-04-18 15:38:59 -0700295 .fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
296 .fib6_protocol = RTPROT_KERNEL,
297 .fib6_metric = ~(u32)0,
298 .fib6_ref = ATOMIC_INIT(1),
David Ahern421842e2018-04-17 17:33:18 -0700299 .fib6_type = RTN_UNREACHABLE,
300 .fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
301};
302
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000303static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700304 .dst = {
305 .__refcnt = ATOMIC_INIT(1),
306 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000307 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700308 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700309 .input = ip6_pkt_discard,
310 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 },
312 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313};
314
Thomas Graf101367c2006-08-04 03:39:02 -0700315#ifdef CONFIG_IPV6_MULTIPLE_TABLES
316
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000317static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700318 .dst = {
319 .__refcnt = ATOMIC_INIT(1),
320 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000321 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700322 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700323 .input = ip6_pkt_prohibit,
324 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700325 },
326 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700327};
328
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000329static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700330 .dst = {
331 .__refcnt = ATOMIC_INIT(1),
332 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000333 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700334 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700335 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500336 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700337 },
338 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700339};
340
341#endif
342
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700343static void rt6_info_init(struct rt6_info *rt)
344{
345 struct dst_entry *dst = &rt->dst;
346
347 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700348 INIT_LIST_HEAD(&rt->rt6i_uncached);
349}
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/* allocate dst with ip6_dst_ops */
David Ahern93531c62018-04-17 17:33:25 -0700352struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
353 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
David S. Miller97bab732012-06-09 22:36:36 -0700355 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700356 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700357
Wei Wang81eb8442017-10-06 12:06:11 -0700358 if (rt) {
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700359 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -0700360 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
361 }
Steffen Klassert81048912012-07-05 23:37:09 +0000362
David S. Millercf911662011-04-28 14:31:47 -0700363 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
David Ahern9ab179d2016-04-07 11:10:06 -0700365EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367static void ip6_dst_destroy(struct dst_entry *dst)
368{
369 struct rt6_info *rt = (struct rt6_info *)dst;
David Aherna68886a2018-04-20 15:38:02 -0700370 struct fib6_info *from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700371 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
David Ahern1620a332018-10-04 20:07:54 -0700373 ip_dst_metrics_put(dst);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700374 rt6_uncached_list_del(rt);
375
376 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500377 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 rt->rt6i_idev = NULL;
379 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900380 }
Gao feng1716a962012-04-06 00:13:10 +0000381
David Aherna68886a2018-04-20 15:38:02 -0700382 rcu_read_lock();
383 from = rcu_dereference(rt->from);
384 rcu_assign_pointer(rt->from, NULL);
David Ahern93531c62018-04-17 17:33:25 -0700385 fib6_info_release(from);
David Aherna68886a2018-04-20 15:38:02 -0700386 rcu_read_unlock();
David S. Millerb3419362010-11-30 12:27:11 -0800387}
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
390 int how)
391{
392 struct rt6_info *rt = (struct rt6_info *)dst;
393 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800394 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900395 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Wei Wange5645f52017-08-14 10:44:59 -0700397 if (idev && idev->dev != loopback_dev) {
398 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
399 if (loopback_idev) {
400 rt->rt6i_idev = loopback_idev;
401 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
404}
405
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800406static bool __rt6_check_expired(const struct rt6_info *rt)
407{
408 if (rt->rt6i_flags & RTF_EXPIRES)
409 return time_after(jiffies, rt->dst.expires);
410 else
411 return false;
412}
413
Eric Dumazeta50feda2012-05-18 18:57:34 +0000414static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
David Aherna68886a2018-04-20 15:38:02 -0700416 struct fib6_info *from;
417
418 from = rcu_dereference(rt->from);
419
Gao feng1716a962012-04-06 00:13:10 +0000420 if (rt->rt6i_flags & RTF_EXPIRES) {
421 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000422 return true;
David Aherna68886a2018-04-20 15:38:02 -0700423 } else if (from) {
Xin Long1e2ea8a2017-08-26 20:10:10 +0800424 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
David Aherna68886a2018-04-20 15:38:02 -0700425 fib6_check_expired(from);
Gao feng1716a962012-04-06 00:13:10 +0000426 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000427 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428}
429
David Ahern3b290a32018-05-09 20:34:20 -0700430struct fib6_info *fib6_multipath_select(const struct net *net,
431 struct fib6_info *match,
432 struct flowi6 *fl6, int oif,
433 const struct sk_buff *skb,
434 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000435{
David Ahern8d1c8022018-04-17 17:33:26 -0700436 struct fib6_info *sibling, *next_sibling;
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 Ahern5e670d82018-04-17 17:33:14 -0700444 if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound))
Ido Schimmel3d709f62018-01-09 16:40:27 +0200445 return match;
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 Ahern5e670d82018-04-17 17:33:14 -0700449 int nh_upper_bound;
450
451 nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound);
452 if (fl6->mp_hash > nh_upper_bound)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200453 continue;
454 if (rt6_score_route(sibling, oif, strict) < 0)
455 break;
456 match = sibling;
457 break;
458 }
459
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000460 return match;
461}
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463/*
Wei Wang66f5d6c2017-10-06 12:06:10 -0700464 * Route lookup. rcu_read_lock() should be held.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 */
466
David Ahern8d1c8022018-04-17 17:33:26 -0700467static inline struct fib6_info *rt6_device_match(struct net *net,
468 struct fib6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000469 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700471 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
David Ahern8d1c8022018-04-17 17:33:26 -0700473 struct fib6_info *sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
David Ahern5e670d82018-04-17 17:33:14 -0700475 if (!oif && ipv6_addr_any(saddr) &&
476 !(rt->fib6_nh.nh_flags & RTNH_F_DEAD))
Ido Schimmel8067bb82018-01-07 12:45:09 +0200477 return rt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900478
David Ahern8fb11a92018-05-04 13:54:24 -0700479 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->fib6_next)) {
David Ahern5e670d82018-04-17 17:33:14 -0700480 const struct net_device *dev = sprt->fib6_nh.nh_dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900481
David Ahern5e670d82018-04-17 17:33:14 -0700482 if (sprt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200483 continue;
484
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900485 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (dev->ifindex == oif)
487 return sprt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900488 } else {
489 if (ipv6_chk_addr(net, saddr, dev,
490 flags & RT6_LOOKUP_F_IFACE))
491 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
David Aherneea68cd2018-04-18 15:39:02 -0700495 if (oif && flags & RT6_LOOKUP_F_IFACE)
496 return net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
David Ahern421842e2018-04-17 17:33:18 -0700498 return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800501#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200502struct __rt6_probe_work {
503 struct work_struct work;
504 struct in6_addr target;
505 struct net_device *dev;
506};
507
508static void rt6_probe_deferred(struct work_struct *w)
509{
510 struct in6_addr mcaddr;
511 struct __rt6_probe_work *work =
512 container_of(w, struct __rt6_probe_work, work);
513
514 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800515 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200516 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100517 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200518}
519
David Ahern8d1c8022018-04-17 17:33:26 -0700520static void rt6_probe(struct fib6_info *rt)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800521{
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200522 struct __rt6_probe_work *work = NULL;
David Ahern5e670d82018-04-17 17:33:14 -0700523 const struct in6_addr *nh_gw;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000524 struct neighbour *neigh;
David Ahern5e670d82018-04-17 17:33:14 -0700525 struct net_device *dev;
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200526 struct inet6_dev *idev;
David Ahern5e670d82018-04-17 17:33:14 -0700527
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800528 /*
529 * Okay, this does not seem to be appropriate
530 * for now, however, we need to check if it
531 * is really so; aka Router Reachability Probing.
532 *
533 * Router Reachability Probe MUST be rate-limited
534 * to no more than one per minute.
535 */
David Ahern93c2fb22018-04-18 15:38:59 -0700536 if (!rt || !(rt->fib6_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000537 return;
David Ahern5e670d82018-04-17 17:33:14 -0700538
539 nh_gw = &rt->fib6_nh.nh_gw;
540 dev = rt->fib6_nh.nh_dev;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000541 rcu_read_lock_bh();
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200542 idev = __in6_dev_get(dev);
David Ahern5e670d82018-04-17 17:33:14 -0700543 neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000544 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700545 if (neigh->nud_state & NUD_VALID)
546 goto out;
547
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000548 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700549 if (!(neigh->nud_state & NUD_VALID) &&
550 time_after(jiffies,
David Aherndcd1f572018-04-18 15:39:05 -0700551 neigh->updated + idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700552 work = kmalloc(sizeof(*work), GFP_ATOMIC);
553 if (work)
554 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200555 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000556 write_unlock(&neigh->lock);
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200557 } else if (time_after(jiffies, rt->last_probe +
558 idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700559 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000560 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700561
562 if (work) {
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200563 rt->last_probe = jiffies;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700564 INIT_WORK(&work->work, rt6_probe_deferred);
David Ahern5e670d82018-04-17 17:33:14 -0700565 work->target = *nh_gw;
566 dev_hold(dev);
567 work->dev = dev;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700568 schedule_work(&work->work);
569 }
570
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700571out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000572 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800573}
574#else
David Ahern8d1c8022018-04-17 17:33:26 -0700575static inline void rt6_probe(struct fib6_info *rt)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800576{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800577}
578#endif
579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800581 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 */
David Ahern8d1c8022018-04-17 17:33:26 -0700583static inline int rt6_check_dev(struct fib6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
David Ahern5e670d82018-04-17 17:33:14 -0700585 const struct net_device *dev = rt->fib6_nh.nh_dev;
586
David S. Miller161980f2007-04-06 11:42:27 -0700587 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800588 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590}
591
David Ahern8d1c8022018-04-17 17:33:26 -0700592static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200594 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
David Ahern5e670d82018-04-17 17:33:14 -0700595 struct neighbour *neigh;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000596
David Ahern93c2fb22018-04-18 15:38:59 -0700597 if (rt->fib6_flags & RTF_NONEXTHOP ||
598 !(rt->fib6_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200599 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000600
601 rcu_read_lock_bh();
David Ahern5e670d82018-04-17 17:33:14 -0700602 neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev,
603 &rt->fib6_nh.nh_gw);
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000604 if (neigh) {
605 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800606 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200607 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800608#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000609 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200610 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100611 else
612 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800613#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000614 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200615 } else {
616 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100617 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000618 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000619 rcu_read_unlock_bh();
620
Paul Marksa5a81f02012-12-03 10:26:54 +0000621 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800622}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
David Ahern8d1c8022018-04-17 17:33:26 -0700624static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800625{
Paul Marksa5a81f02012-12-03 10:26:54 +0000626 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900627
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700628 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700629 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200630 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800631#ifdef CONFIG_IPV6_ROUTER_PREF
David Ahern93c2fb22018-04-18 15:38:59 -0700632 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->fib6_flags)) << 2;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800633#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200634 if (strict & RT6_LOOKUP_F_REACHABLE) {
635 int n = rt6_check_neigh(rt);
636 if (n < 0)
637 return n;
638 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800639 return m;
640}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
David Aherndcd1f572018-04-18 15:39:05 -0700642/* called with rc_read_lock held */
643static inline bool fib6_ignore_linkdown(const struct fib6_info *f6i)
644{
645 const struct net_device *dev = fib6_info_nh_dev(f6i);
646 bool rc = false;
647
648 if (dev) {
649 const struct inet6_dev *idev = __in6_dev_get(dev);
650
651 rc = !!idev->cnf.ignore_routes_with_linkdown;
652 }
653
654 return rc;
655}
656
David Ahern8d1c8022018-04-17 17:33:26 -0700657static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict,
658 int *mpri, struct fib6_info *match,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200659 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800660{
David S. Millerf11e6652007-03-24 20:36:25 -0700661 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200662 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400663
David Ahern5e670d82018-04-17 17:33:14 -0700664 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200665 goto out;
666
David Aherndcd1f572018-04-18 15:39:05 -0700667 if (fib6_ignore_linkdown(rt) &&
David Ahern5e670d82018-04-17 17:33:14 -0700668 rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Ahernd5d32e42016-10-24 12:27:23 -0700669 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400670 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700671
David Ahern14895682018-04-17 17:33:17 -0700672 if (fib6_check_expired(rt))
David S. Millerf11e6652007-03-24 20:36:25 -0700673 goto out;
674
675 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100676 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200677 match_do_rr = true;
678 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100679 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700680 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700681 }
682
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200683 if (strict & RT6_LOOKUP_F_REACHABLE)
684 rt6_probe(rt);
685
Jiri Benc7e980562013-12-11 13:48:20 +0100686 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200687 if (m > *mpri) {
688 *do_rr = match_do_rr;
689 *mpri = m;
690 match = rt;
691 }
David S. Millerf11e6652007-03-24 20:36:25 -0700692out:
693 return match;
694}
695
David Ahern8d1c8022018-04-17 17:33:26 -0700696static struct fib6_info *find_rr_leaf(struct fib6_node *fn,
697 struct fib6_info *leaf,
698 struct fib6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200699 u32 metric, int oif, int strict,
700 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700701{
David Ahern8d1c8022018-04-17 17:33:26 -0700702 struct fib6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800703 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
David S. Millerf11e6652007-03-24 20:36:25 -0700705 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700706 cont = NULL;
David Ahern8fb11a92018-05-04 13:54:24 -0700707 for (rt = rr_head; rt; rt = rcu_dereference(rt->fib6_next)) {
David Ahern93c2fb22018-04-18 15:38:59 -0700708 if (rt->fib6_metric != metric) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700709 cont = rt;
710 break;
711 }
712
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200713 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700714 }
715
Wei Wang66f5d6c2017-10-06 12:06:10 -0700716 for (rt = leaf; rt && rt != rr_head;
David Ahern8fb11a92018-05-04 13:54:24 -0700717 rt = rcu_dereference(rt->fib6_next)) {
David Ahern93c2fb22018-04-18 15:38:59 -0700718 if (rt->fib6_metric != metric) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700719 cont = rt;
720 break;
721 }
722
723 match = find_match(rt, oif, strict, &mpri, match, do_rr);
724 }
725
726 if (match || !cont)
727 return match;
728
David Ahern8fb11a92018-05-04 13:54:24 -0700729 for (rt = cont; rt; rt = rcu_dereference(rt->fib6_next))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200730 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800731
David S. Millerf11e6652007-03-24 20:36:25 -0700732 return match;
733}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800734
David Ahern8d1c8022018-04-17 17:33:26 -0700735static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
Wei Wang8d1040e2017-10-06 12:06:08 -0700736 int oif, int strict)
David S. Millerf11e6652007-03-24 20:36:25 -0700737{
David Ahern8d1c8022018-04-17 17:33:26 -0700738 struct fib6_info *leaf = rcu_dereference(fn->leaf);
739 struct fib6_info *match, *rt0;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200740 bool do_rr = false;
Wei Wang17ecf592017-10-06 12:06:09 -0700741 int key_plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
David Ahern421842e2018-04-17 17:33:18 -0700743 if (!leaf || leaf == net->ipv6.fib6_null_entry)
744 return net->ipv6.fib6_null_entry;
Wei Wang8d1040e2017-10-06 12:06:08 -0700745
Wei Wang66f5d6c2017-10-06 12:06:10 -0700746 rt0 = rcu_dereference(fn->rr_ptr);
David S. Millerf11e6652007-03-24 20:36:25 -0700747 if (!rt0)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700748 rt0 = leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Wei Wang17ecf592017-10-06 12:06:09 -0700750 /* Double check to make sure fn is not an intermediate node
751 * and fn->leaf does not points to its child's leaf
752 * (This might happen if all routes under fn are deleted from
753 * the tree and fib6_repair_tree() is called on the node.)
754 */
David Ahern93c2fb22018-04-18 15:38:59 -0700755 key_plen = rt0->fib6_dst.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700756#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700757 if (rt0->fib6_src.plen)
758 key_plen = rt0->fib6_src.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700759#endif
760 if (fn->fn_bit != key_plen)
David Ahern421842e2018-04-17 17:33:18 -0700761 return net->ipv6.fib6_null_entry;
Wei Wang17ecf592017-10-06 12:06:09 -0700762
David Ahern93c2fb22018-04-18 15:38:59 -0700763 match = find_rr_leaf(fn, leaf, rt0, rt0->fib6_metric, oif, strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200764 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200766 if (do_rr) {
David Ahern8fb11a92018-05-04 13:54:24 -0700767 struct fib6_info *next = rcu_dereference(rt0->fib6_next);
David S. Millerf11e6652007-03-24 20:36:25 -0700768
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800769 /* no entries matched; do round-robin */
David Ahern93c2fb22018-04-18 15:38:59 -0700770 if (!next || next->fib6_metric != rt0->fib6_metric)
Wei Wang8d1040e2017-10-06 12:06:08 -0700771 next = leaf;
David S. Millerf11e6652007-03-24 20:36:25 -0700772
Wei Wang66f5d6c2017-10-06 12:06:10 -0700773 if (next != rt0) {
David Ahern93c2fb22018-04-18 15:38:59 -0700774 spin_lock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700775 /* make sure next is not being deleted from the tree */
David Ahern93c2fb22018-04-18 15:38:59 -0700776 if (next->fib6_node)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700777 rcu_assign_pointer(fn->rr_ptr, next);
David Ahern93c2fb22018-04-18 15:38:59 -0700778 spin_unlock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
781
David Ahern421842e2018-04-17 17:33:18 -0700782 return match ? match : net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783}
784
David Ahern8d1c8022018-04-17 17:33:26 -0700785static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt)
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700786{
David Ahern93c2fb22018-04-18 15:38:59 -0700787 return (rt->fib6_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700788}
789
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800790#ifdef CONFIG_IPV6_ROUTE_INFO
791int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000792 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800793{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900794 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800795 struct route_info *rinfo = (struct route_info *) opt;
796 struct in6_addr prefix_buf, *prefix;
797 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900798 unsigned long lifetime;
David Ahern8d1c8022018-04-17 17:33:26 -0700799 struct fib6_info *rt;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800800
801 if (len < sizeof(struct route_info)) {
802 return -EINVAL;
803 }
804
805 /* Sanity check for prefix_len and length */
806 if (rinfo->length > 3) {
807 return -EINVAL;
808 } else if (rinfo->prefix_len > 128) {
809 return -EINVAL;
810 } else if (rinfo->prefix_len > 64) {
811 if (rinfo->length < 2) {
812 return -EINVAL;
813 }
814 } else if (rinfo->prefix_len > 0) {
815 if (rinfo->length < 1) {
816 return -EINVAL;
817 }
818 }
819
820 pref = rinfo->route_pref;
821 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000822 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800823
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900824 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800825
826 if (rinfo->length == 3)
827 prefix = (struct in6_addr *)rinfo->prefix;
828 else {
829 /* this function is safe */
830 ipv6_addr_prefix(&prefix_buf,
831 (struct in6_addr *)rinfo->prefix,
832 rinfo->prefix_len);
833 prefix = &prefix_buf;
834 }
835
Duan Jiongf104a562013-11-08 09:56:53 +0800836 if (rinfo->prefix_len == 0)
David Ahernafb1d4b52018-04-17 17:33:11 -0700837 rt = rt6_get_dflt_router(net, gwaddr, dev);
Duan Jiongf104a562013-11-08 09:56:53 +0800838 else
839 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700840 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800841
842 if (rt && !lifetime) {
David Ahernafb1d4b52018-04-17 17:33:11 -0700843 ip6_del_rt(net, rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800844 rt = NULL;
845 }
846
847 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700848 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
849 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800850 else if (rt)
David Ahern93c2fb22018-04-18 15:38:59 -0700851 rt->fib6_flags = RTF_ROUTEINFO |
852 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800853
854 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000855 if (!addrconf_finite_timeout(lifetime))
David Ahern14895682018-04-17 17:33:17 -0700856 fib6_clean_expires(rt);
Gao feng1716a962012-04-06 00:13:10 +0000857 else
David Ahern14895682018-04-17 17:33:17 -0700858 fib6_set_expires(rt, jiffies + HZ * lifetime);
Gao feng1716a962012-04-06 00:13:10 +0000859
David Ahern93531c62018-04-17 17:33:25 -0700860 fib6_info_release(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800861 }
862 return 0;
863}
864#endif
865
David Ahernae90d862018-04-17 17:33:12 -0700866/*
867 * Misc support functions
868 */
869
870/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -0700871static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt)
David Ahernae90d862018-04-17 17:33:12 -0700872{
David Ahern5e670d82018-04-17 17:33:14 -0700873 struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernae90d862018-04-17 17:33:12 -0700874
David Ahern93c2fb22018-04-18 15:38:59 -0700875 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
David Ahernae90d862018-04-17 17:33:12 -0700876 /* for copies of local routes, dst->dev needs to be the
877 * device if it is a master device, the master device if
878 * device is enslaved, and the loopback as the default
879 */
880 if (netif_is_l3_slave(dev) &&
David Ahern93c2fb22018-04-18 15:38:59 -0700881 !rt6_need_strict(&rt->fib6_dst.addr))
David Ahernae90d862018-04-17 17:33:12 -0700882 dev = l3mdev_master_dev_rcu(dev);
883 else if (!netif_is_l3_master(dev))
884 dev = dev_net(dev)->loopback_dev;
885 /* last case is netif_is_l3_master(dev) is true in which
886 * case we want dev returned to be dev
887 */
888 }
889
890 return dev;
891}
892
David Ahern6edb3c92018-04-17 17:33:15 -0700893static const int fib6_prop[RTN_MAX + 1] = {
894 [RTN_UNSPEC] = 0,
895 [RTN_UNICAST] = 0,
896 [RTN_LOCAL] = 0,
897 [RTN_BROADCAST] = 0,
898 [RTN_ANYCAST] = 0,
899 [RTN_MULTICAST] = 0,
900 [RTN_BLACKHOLE] = -EINVAL,
901 [RTN_UNREACHABLE] = -EHOSTUNREACH,
902 [RTN_PROHIBIT] = -EACCES,
903 [RTN_THROW] = -EAGAIN,
904 [RTN_NAT] = -EINVAL,
905 [RTN_XRESOLVE] = -EINVAL,
906};
907
908static int ip6_rt_type_to_error(u8 fib6_type)
909{
910 return fib6_prop[fib6_type];
911}
912
David Ahern8d1c8022018-04-17 17:33:26 -0700913static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
David Ahern3b6761d2018-04-17 17:33:20 -0700914{
915 unsigned short flags = 0;
916
917 if (rt->dst_nocount)
918 flags |= DST_NOCOUNT;
919 if (rt->dst_nopolicy)
920 flags |= DST_NOPOLICY;
921 if (rt->dst_host)
922 flags |= DST_HOST;
923
924 return flags;
925}
926
David Ahern8d1c8022018-04-17 17:33:26 -0700927static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700928{
929 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type);
930
931 switch (ort->fib6_type) {
932 case RTN_BLACKHOLE:
933 rt->dst.output = dst_discard_out;
934 rt->dst.input = dst_discard;
935 break;
936 case RTN_PROHIBIT:
937 rt->dst.output = ip6_pkt_prohibit_out;
938 rt->dst.input = ip6_pkt_prohibit;
939 break;
940 case RTN_THROW:
941 case RTN_UNREACHABLE:
942 default:
943 rt->dst.output = ip6_pkt_discard_out;
944 rt->dst.input = ip6_pkt_discard;
945 break;
946 }
947}
948
David Ahern8d1c8022018-04-17 17:33:26 -0700949static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700950{
David Ahern93c2fb22018-04-18 15:38:59 -0700951 if (ort->fib6_flags & RTF_REJECT) {
David Ahern6edb3c92018-04-17 17:33:15 -0700952 ip6_rt_init_dst_reject(rt, ort);
953 return;
954 }
955
956 rt->dst.error = 0;
957 rt->dst.output = ip6_output;
958
Hangbin Liud23c4b62018-08-23 11:31:37 +0800959 if (ort->fib6_type == RTN_LOCAL || ort->fib6_type == RTN_ANYCAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700960 rt->dst.input = ip6_input;
David Ahern93c2fb22018-04-18 15:38:59 -0700961 } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700962 rt->dst.input = ip6_mc_input;
963 } else {
964 rt->dst.input = ip6_forward;
965 }
966
967 if (ort->fib6_nh.nh_lwtstate) {
968 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
969 lwtunnel_set_redirect(&rt->dst);
970 }
971
972 rt->dst.lastuse = jiffies;
973}
974
Wei Wange873e4b2018-07-21 20:56:32 -0700975/* Caller must already hold reference to @from */
David Ahern8d1c8022018-04-17 17:33:26 -0700976static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
David Ahernae90d862018-04-17 17:33:12 -0700977{
David Ahernae90d862018-04-17 17:33:12 -0700978 rt->rt6i_flags &= ~RTF_EXPIRES;
David Aherna68886a2018-04-20 15:38:02 -0700979 rcu_assign_pointer(rt->from, from);
David Aherne1255ed2018-10-04 20:07:53 -0700980 ip_dst_init_metrics(&rt->dst, from->fib6_metrics);
David Ahernae90d862018-04-17 17:33:12 -0700981}
982
Wei Wange873e4b2018-07-21 20:56:32 -0700983/* Caller must already hold reference to @ort */
David Ahern8d1c8022018-04-17 17:33:26 -0700984static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
David Ahernae90d862018-04-17 17:33:12 -0700985{
David Aherndcd1f572018-04-18 15:39:05 -0700986 struct net_device *dev = fib6_info_nh_dev(ort);
987
David Ahern6edb3c92018-04-17 17:33:15 -0700988 ip6_rt_init_dst(rt, ort);
989
David Ahern93c2fb22018-04-18 15:38:59 -0700990 rt->rt6i_dst = ort->fib6_dst;
David Aherndcd1f572018-04-18 15:39:05 -0700991 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
David Ahern5e670d82018-04-17 17:33:14 -0700992 rt->rt6i_gateway = ort->fib6_nh.nh_gw;
David Ahern93c2fb22018-04-18 15:38:59 -0700993 rt->rt6i_flags = ort->fib6_flags;
David Ahernae90d862018-04-17 17:33:12 -0700994 rt6_set_from(rt, ort);
David Ahernae90d862018-04-17 17:33:12 -0700995#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700996 rt->rt6i_src = ort->fib6_src;
David Ahernae90d862018-04-17 17:33:12 -0700997#endif
David Ahernae90d862018-04-17 17:33:12 -0700998}
999
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001000static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
1001 struct in6_addr *saddr)
1002{
Wei Wang66f5d6c2017-10-06 12:06:10 -07001003 struct fib6_node *pn, *sn;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001004 while (1) {
1005 if (fn->fn_flags & RTN_TL_ROOT)
1006 return NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001007 pn = rcu_dereference(fn->parent);
1008 sn = FIB6_SUBTREE(pn);
1009 if (sn && sn != fn)
David Ahern64547432018-05-09 20:34:19 -07001010 fn = fib6_node_lookup(sn, NULL, saddr);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001011 else
1012 fn = pn;
1013 if (fn->fn_flags & RTN_RTINFO)
1014 return fn;
1015 }
1016}
Thomas Grafc71099a2006-08-04 23:20:06 -07001017
Wei Wangd3843fe2017-10-06 12:06:06 -07001018static bool ip6_hold_safe(struct net *net, struct rt6_info **prt,
1019 bool null_fallback)
1020{
1021 struct rt6_info *rt = *prt;
1022
1023 if (dst_hold_safe(&rt->dst))
1024 return true;
1025 if (null_fallback) {
1026 rt = net->ipv6.ip6_null_entry;
1027 dst_hold(&rt->dst);
1028 } else {
1029 rt = NULL;
1030 }
1031 *prt = rt;
1032 return false;
1033}
1034
David Aherndec9b0e2018-04-17 17:33:19 -07001035/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -07001036static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt)
David Aherndec9b0e2018-04-17 17:33:19 -07001037{
David Ahern3b6761d2018-04-17 17:33:20 -07001038 unsigned short flags = fib6_info_dst_flags(rt);
David Aherndec9b0e2018-04-17 17:33:19 -07001039 struct net_device *dev = rt->fib6_nh.nh_dev;
1040 struct rt6_info *nrt;
1041
Wei Wange873e4b2018-07-21 20:56:32 -07001042 if (!fib6_info_hold_safe(rt))
1043 return NULL;
1044
David Ahern93531c62018-04-17 17:33:25 -07001045 nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Aherndec9b0e2018-04-17 17:33:19 -07001046 if (nrt)
1047 ip6_rt_copy_init(nrt, rt);
Wei Wange873e4b2018-07-21 20:56:32 -07001048 else
1049 fib6_info_release(rt);
David Aherndec9b0e2018-04-17 17:33:19 -07001050
1051 return nrt;
1052}
1053
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001054static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1055 struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001056 struct flowi6 *fl6,
1057 const struct sk_buff *skb,
1058 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
David Ahern8d1c8022018-04-17 17:33:26 -07001060 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 struct fib6_node *fn;
David Ahern23fb93a2018-04-17 17:33:23 -07001062 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
David Ahernb6cdbc82018-03-29 17:44:57 -07001064 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1065 flags &= ~RT6_LOOKUP_F_IFACE;
1066
Wei Wang66f5d6c2017-10-06 12:06:10 -07001067 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07001068 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -07001069restart:
David Ahern23fb93a2018-04-17 17:33:23 -07001070 f6i = rcu_dereference(fn->leaf);
1071 if (!f6i) {
1072 f6i = net->ipv6.fib6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001073 } else {
David Ahern23fb93a2018-04-17 17:33:23 -07001074 f6i = rt6_device_match(net, f6i, &fl6->saddr,
Wei Wang66f5d6c2017-10-06 12:06:10 -07001075 fl6->flowi6_oif, flags);
David Ahern93c2fb22018-04-18 15:38:59 -07001076 if (f6i->fib6_nsiblings && fl6->flowi6_oif == 0)
David Ahern3b290a32018-05-09 20:34:20 -07001077 f6i = fib6_multipath_select(net, f6i, fl6,
1078 fl6->flowi6_oif, skb,
1079 flags);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001080 }
David Ahern23fb93a2018-04-17 17:33:23 -07001081 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001082 fn = fib6_backtrack(fn, &fl6->saddr);
1083 if (fn)
1084 goto restart;
1085 }
Wei Wang2b760fc2017-10-06 12:06:03 -07001086
David Ahernd4bea422018-05-09 20:34:24 -07001087 trace_fib6_table_lookup(net, f6i, table, fl6);
1088
David S. Miller4c9483b2011-03-12 16:22:43 -05001089 /* Search through exception table */
David Ahern23fb93a2018-04-17 17:33:23 -07001090 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1091 if (rt) {
David Aherndec9b0e2018-04-17 17:33:19 -07001092 if (ip6_hold_safe(net, &rt, true))
1093 dst_use_noref(&rt->dst, jiffies);
David Ahern23fb93a2018-04-17 17:33:23 -07001094 } else if (f6i == net->ipv6.fib6_null_entry) {
David Aherndec9b0e2018-04-17 17:33:19 -07001095 rt = net->ipv6.ip6_null_entry;
1096 dst_hold(&rt->dst);
David Ahern23fb93a2018-04-17 17:33:23 -07001097 } else {
1098 rt = ip6_create_rt_rcu(f6i);
1099 if (!rt) {
1100 rt = net->ipv6.ip6_null_entry;
1101 dst_hold(&rt->dst);
1102 }
David Aherndec9b0e2018-04-17 17:33:19 -07001103 }
Wei Wangd3843fe2017-10-06 12:06:06 -07001104
Wei Wang66f5d6c2017-10-06 12:06:10 -07001105 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -08001106
Thomas Grafc71099a2006-08-04 23:20:06 -07001107 return rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001108}
1109
Ian Morris67ba4152014-08-24 21:53:10 +01001110struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08001111 const struct sk_buff *skb, int flags)
Florian Westphalea6e5742011-09-05 16:05:44 +02001112{
David Ahernb75cc8f2018-03-02 08:32:17 -08001113 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
Florian Westphalea6e5742011-09-05 16:05:44 +02001114}
1115EXPORT_SYMBOL_GPL(ip6_route_lookup);
1116
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +09001117struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
David Ahernb75cc8f2018-03-02 08:32:17 -08001118 const struct in6_addr *saddr, int oif,
1119 const struct sk_buff *skb, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -07001120{
David S. Miller4c9483b2011-03-12 16:22:43 -05001121 struct flowi6 fl6 = {
1122 .flowi6_oif = oif,
1123 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001124 };
1125 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001126 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07001127
Thomas Grafadaa70b2006-10-13 15:01:03 -07001128 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -05001129 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -07001130 flags |= RT6_LOOKUP_F_HAS_SADDR;
1131 }
1132
David Ahernb75cc8f2018-03-02 08:32:17 -08001133 dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -07001134 if (dst->error == 0)
1135 return (struct rt6_info *) dst;
1136
1137 dst_release(dst);
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 return NULL;
1140}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001141EXPORT_SYMBOL(rt6_lookup);
1142
Thomas Grafc71099a2006-08-04 23:20:06 -07001143/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -07001144 * It takes new route entry, the addition fails by any reason the
1145 * route is released.
1146 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 */
1148
David Ahern8d1c8022018-04-17 17:33:26 -07001149static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001150 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
1152 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001153 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
David Ahern93c2fb22018-04-18 15:38:59 -07001155 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001156 spin_lock_bh(&table->tb6_lock);
David Ahernd4ead6b2018-04-17 17:33:16 -07001157 err = fib6_add(&table->tb6_root, rt, info, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001158 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160 return err;
1161}
1162
David Ahern8d1c8022018-04-17 17:33:26 -07001163int ip6_ins_rt(struct net *net, struct fib6_info *rt)
Thomas Graf40e22e82006-08-22 00:00:45 -07001164{
David Ahernafb1d4b52018-04-17 17:33:11 -07001165 struct nl_info info = { .nl_net = net, };
Florian Westphale715b6d2015-01-05 23:57:44 +01001166
David Ahernd4ead6b2018-04-17 17:33:16 -07001167 return __ip6_ins_rt(rt, &info, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001168}
1169
David Ahern8d1c8022018-04-17 17:33:26 -07001170static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001171 const struct in6_addr *daddr,
1172 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
David Ahern4832c302017-08-17 12:17:20 -07001174 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 struct rt6_info *rt;
1176
1177 /*
1178 * Clone the route.
1179 */
1180
Wei Wange873e4b2018-07-21 20:56:32 -07001181 if (!fib6_info_hold_safe(ort))
1182 return NULL;
1183
David Ahern4832c302017-08-17 12:17:20 -07001184 dev = ip6_rt_get_dev_rcu(ort);
David Ahern93531c62018-04-17 17:33:25 -07001185 rt = ip6_dst_alloc(dev_net(dev), dev, 0);
Wei Wange873e4b2018-07-21 20:56:32 -07001186 if (!rt) {
1187 fib6_info_release(ort);
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001188 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001189 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001190
1191 ip6_rt_copy_init(rt, ort);
1192 rt->rt6i_flags |= RTF_CACHE;
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001193 rt->dst.flags |= DST_HOST;
1194 rt->rt6i_dst.addr = *daddr;
1195 rt->rt6i_dst.plen = 128;
1196
1197 if (!rt6_is_gw_or_nonexthop(ort)) {
David Ahern93c2fb22018-04-18 15:38:59 -07001198 if (ort->fib6_dst.plen != 128 &&
1199 ipv6_addr_equal(&ort->fib6_dst.addr, daddr))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001200 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001202 if (rt->rt6i_src.plen && saddr) {
1203 rt->rt6i_src.addr = *saddr;
1204 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001205 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001206#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001209 return rt;
1210}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
David Ahern8d1c8022018-04-17 17:33:26 -07001212static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001213{
David Ahern3b6761d2018-04-17 17:33:20 -07001214 unsigned short flags = fib6_info_dst_flags(rt);
David Ahern4832c302017-08-17 12:17:20 -07001215 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001216 struct rt6_info *pcpu_rt;
1217
Wei Wange873e4b2018-07-21 20:56:32 -07001218 if (!fib6_info_hold_safe(rt))
1219 return NULL;
1220
David Ahern4832c302017-08-17 12:17:20 -07001221 rcu_read_lock();
1222 dev = ip6_rt_get_dev_rcu(rt);
David Ahern93531c62018-04-17 17:33:25 -07001223 pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Ahern4832c302017-08-17 12:17:20 -07001224 rcu_read_unlock();
Wei Wange873e4b2018-07-21 20:56:32 -07001225 if (!pcpu_rt) {
1226 fib6_info_release(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001227 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001228 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001229 ip6_rt_copy_init(pcpu_rt, rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001230 pcpu_rt->rt6i_flags |= RTF_PCPU;
1231 return pcpu_rt;
1232}
1233
Wei Wang66f5d6c2017-10-06 12:06:10 -07001234/* It should be called with rcu_read_lock() acquired */
David Ahern8d1c8022018-04-17 17:33:26 -07001235static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001236{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001237 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001238
1239 p = this_cpu_ptr(rt->rt6i_pcpu);
1240 pcpu_rt = *p;
1241
David Ahernd4ead6b2018-04-17 17:33:16 -07001242 if (pcpu_rt)
1243 ip6_hold_safe(NULL, &pcpu_rt, false);
Wei Wangd3843fe2017-10-06 12:06:06 -07001244
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001245 return pcpu_rt;
1246}
1247
David Ahernafb1d4b52018-04-17 17:33:11 -07001248static struct rt6_info *rt6_make_pcpu_route(struct net *net,
David Ahern8d1c8022018-04-17 17:33:26 -07001249 struct fib6_info *rt)
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001250{
1251 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001252
1253 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1254 if (!pcpu_rt) {
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001255 dst_hold(&net->ipv6.ip6_null_entry->dst);
1256 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001257 }
1258
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001259 dst_hold(&pcpu_rt->dst);
Wei Wanga94b9362017-10-06 12:06:04 -07001260 p = this_cpu_ptr(rt->rt6i_pcpu);
1261 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001262 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001263
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001264 return pcpu_rt;
1265}
1266
Wei Wang35732d02017-10-06 12:05:57 -07001267/* exception hash table implementation
1268 */
1269static DEFINE_SPINLOCK(rt6_exception_lock);
1270
1271/* Remove rt6_ex from hash table and free the memory
1272 * Caller must hold rt6_exception_lock
1273 */
1274static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1275 struct rt6_exception *rt6_ex)
1276{
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001277 struct fib6_info *from;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001278 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001279
Wei Wang35732d02017-10-06 12:05:57 -07001280 if (!bucket || !rt6_ex)
1281 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001282
1283 net = dev_net(rt6_ex->rt6i->dst.dev);
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001284 net->ipv6.rt6_stats->fib_rt_cache--;
1285
1286 /* purge completely the exception to allow releasing the held resources:
1287 * some [sk] cache may keep the dst around for unlimited time
1288 */
1289 from = rcu_dereference_protected(rt6_ex->rt6i->from,
1290 lockdep_is_held(&rt6_exception_lock));
1291 rcu_assign_pointer(rt6_ex->rt6i->from, NULL);
1292 fib6_info_release(from);
1293 dst_dev_put(&rt6_ex->rt6i->dst);
1294
Wei Wang35732d02017-10-06 12:05:57 -07001295 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001296 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001297 kfree_rcu(rt6_ex, rcu);
1298 WARN_ON_ONCE(!bucket->depth);
1299 bucket->depth--;
1300}
1301
1302/* Remove oldest rt6_ex in bucket and free the memory
1303 * Caller must hold rt6_exception_lock
1304 */
1305static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1306{
1307 struct rt6_exception *rt6_ex, *oldest = NULL;
1308
1309 if (!bucket)
1310 return;
1311
1312 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1313 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1314 oldest = rt6_ex;
1315 }
1316 rt6_remove_exception(bucket, oldest);
1317}
1318
1319static u32 rt6_exception_hash(const struct in6_addr *dst,
1320 const struct in6_addr *src)
1321{
1322 static u32 seed __read_mostly;
1323 u32 val;
1324
1325 net_get_random_once(&seed, sizeof(seed));
1326 val = jhash(dst, sizeof(*dst), seed);
1327
1328#ifdef CONFIG_IPV6_SUBTREES
1329 if (src)
1330 val = jhash(src, sizeof(*src), val);
1331#endif
1332 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1333}
1334
1335/* Helper function to find the cached rt in the hash table
1336 * and update bucket pointer to point to the bucket for this
1337 * (daddr, saddr) pair
1338 * Caller must hold rt6_exception_lock
1339 */
1340static struct rt6_exception *
1341__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1342 const struct in6_addr *daddr,
1343 const struct in6_addr *saddr)
1344{
1345 struct rt6_exception *rt6_ex;
1346 u32 hval;
1347
1348 if (!(*bucket) || !daddr)
1349 return NULL;
1350
1351 hval = rt6_exception_hash(daddr, saddr);
1352 *bucket += hval;
1353
1354 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1355 struct rt6_info *rt6 = rt6_ex->rt6i;
1356 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1357
1358#ifdef CONFIG_IPV6_SUBTREES
1359 if (matched && saddr)
1360 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1361#endif
1362 if (matched)
1363 return rt6_ex;
1364 }
1365 return NULL;
1366}
1367
1368/* Helper function to find the cached rt in the hash table
1369 * and update bucket pointer to point to the bucket for this
1370 * (daddr, saddr) pair
1371 * Caller must hold rcu_read_lock()
1372 */
1373static struct rt6_exception *
1374__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1375 const struct in6_addr *daddr,
1376 const struct in6_addr *saddr)
1377{
1378 struct rt6_exception *rt6_ex;
1379 u32 hval;
1380
1381 WARN_ON_ONCE(!rcu_read_lock_held());
1382
1383 if (!(*bucket) || !daddr)
1384 return NULL;
1385
1386 hval = rt6_exception_hash(daddr, saddr);
1387 *bucket += hval;
1388
1389 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1390 struct rt6_info *rt6 = rt6_ex->rt6i;
1391 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1392
1393#ifdef CONFIG_IPV6_SUBTREES
1394 if (matched && saddr)
1395 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1396#endif
1397 if (matched)
1398 return rt6_ex;
1399 }
1400 return NULL;
1401}
1402
David Ahern8d1c8022018-04-17 17:33:26 -07001403static unsigned int fib6_mtu(const struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001404{
David Ahernd4ead6b2018-04-17 17:33:16 -07001405 unsigned int mtu;
1406
David Aherndcd1f572018-04-18 15:39:05 -07001407 if (rt->fib6_pmtu) {
1408 mtu = rt->fib6_pmtu;
1409 } else {
1410 struct net_device *dev = fib6_info_nh_dev(rt);
1411 struct inet6_dev *idev;
1412
1413 rcu_read_lock();
1414 idev = __in6_dev_get(dev);
1415 mtu = idev->cnf.mtu6;
1416 rcu_read_unlock();
1417 }
1418
David Ahernd4ead6b2018-04-17 17:33:16 -07001419 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1420
1421 return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu);
1422}
1423
Wei Wang35732d02017-10-06 12:05:57 -07001424static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern8d1c8022018-04-17 17:33:26 -07001425 struct fib6_info *ort)
Wei Wang35732d02017-10-06 12:05:57 -07001426{
David Ahern5e670d82018-04-17 17:33:14 -07001427 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001428 struct rt6_exception_bucket *bucket;
1429 struct in6_addr *src_key = NULL;
1430 struct rt6_exception *rt6_ex;
1431 int err = 0;
1432
Wei Wang35732d02017-10-06 12:05:57 -07001433 spin_lock_bh(&rt6_exception_lock);
1434
1435 if (ort->exception_bucket_flushed) {
1436 err = -EINVAL;
1437 goto out;
1438 }
1439
1440 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1441 lockdep_is_held(&rt6_exception_lock));
1442 if (!bucket) {
1443 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1444 GFP_ATOMIC);
1445 if (!bucket) {
1446 err = -ENOMEM;
1447 goto out;
1448 }
1449 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1450 }
1451
1452#ifdef CONFIG_IPV6_SUBTREES
1453 /* rt6i_src.plen != 0 indicates ort is in subtree
1454 * and exception table is indexed by a hash of
1455 * both rt6i_dst and rt6i_src.
1456 * Otherwise, the exception table is indexed by
1457 * a hash of only rt6i_dst.
1458 */
David Ahern93c2fb22018-04-18 15:38:59 -07001459 if (ort->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001460 src_key = &nrt->rt6i_src.addr;
1461#endif
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001462 /* rt6_mtu_change() might lower mtu on ort.
1463 * Only insert this exception route if its mtu
1464 * is less than ort's mtu value.
1465 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001466 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(ort)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001467 err = -EINVAL;
1468 goto out;
1469 }
Wei Wang60006a42017-10-06 12:05:58 -07001470
Wei Wang35732d02017-10-06 12:05:57 -07001471 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1472 src_key);
1473 if (rt6_ex)
1474 rt6_remove_exception(bucket, rt6_ex);
1475
1476 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1477 if (!rt6_ex) {
1478 err = -ENOMEM;
1479 goto out;
1480 }
1481 rt6_ex->rt6i = nrt;
1482 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001483 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1484 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001485 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001486
1487 if (bucket->depth > FIB6_MAX_DEPTH)
1488 rt6_exception_remove_oldest(bucket);
1489
1490out:
1491 spin_unlock_bh(&rt6_exception_lock);
1492
1493 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001494 if (!err) {
David Ahern93c2fb22018-04-18 15:38:59 -07001495 spin_lock_bh(&ort->fib6_table->tb6_lock);
David Ahern7aef6852018-04-17 17:33:10 -07001496 fib6_update_sernum(net, ort);
David Ahern93c2fb22018-04-18 15:38:59 -07001497 spin_unlock_bh(&ort->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001498 fib6_force_start_gc(net);
1499 }
Wei Wang35732d02017-10-06 12:05:57 -07001500
1501 return err;
1502}
1503
David Ahern8d1c8022018-04-17 17:33:26 -07001504void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001505{
1506 struct rt6_exception_bucket *bucket;
1507 struct rt6_exception *rt6_ex;
1508 struct hlist_node *tmp;
1509 int i;
1510
1511 spin_lock_bh(&rt6_exception_lock);
1512 /* Prevent rt6_insert_exception() to recreate the bucket list */
1513 rt->exception_bucket_flushed = 1;
1514
1515 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1516 lockdep_is_held(&rt6_exception_lock));
1517 if (!bucket)
1518 goto out;
1519
1520 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1521 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1522 rt6_remove_exception(bucket, rt6_ex);
1523 WARN_ON_ONCE(bucket->depth);
1524 bucket++;
1525 }
1526
1527out:
1528 spin_unlock_bh(&rt6_exception_lock);
1529}
1530
1531/* Find cached rt in the hash table inside passed in rt
1532 * Caller has to hold rcu_read_lock()
1533 */
David Ahern8d1c8022018-04-17 17:33:26 -07001534static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -07001535 struct in6_addr *daddr,
1536 struct in6_addr *saddr)
1537{
1538 struct rt6_exception_bucket *bucket;
1539 struct in6_addr *src_key = NULL;
1540 struct rt6_exception *rt6_ex;
1541 struct rt6_info *res = NULL;
1542
1543 bucket = rcu_dereference(rt->rt6i_exception_bucket);
1544
1545#ifdef CONFIG_IPV6_SUBTREES
1546 /* rt6i_src.plen != 0 indicates rt is in subtree
1547 * and exception table is indexed by a hash of
1548 * both rt6i_dst and rt6i_src.
1549 * Otherwise, the exception table is indexed by
1550 * a hash of only rt6i_dst.
1551 */
David Ahern93c2fb22018-04-18 15:38:59 -07001552 if (rt->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001553 src_key = saddr;
1554#endif
1555 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1556
1557 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1558 res = rt6_ex->rt6i;
1559
1560 return res;
1561}
1562
1563/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001564static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001565{
Wei Wang35732d02017-10-06 12:05:57 -07001566 struct rt6_exception_bucket *bucket;
1567 struct in6_addr *src_key = NULL;
1568 struct rt6_exception *rt6_ex;
David Ahern8a14e462018-04-23 11:32:07 -07001569 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001570 int err;
1571
Eric Dumazet091311d2018-04-24 09:22:49 -07001572 from = rcu_dereference(rt->from);
Wei Wang35732d02017-10-06 12:05:57 -07001573 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001574 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001575 return -EINVAL;
1576
1577 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1578 return -ENOENT;
1579
1580 spin_lock_bh(&rt6_exception_lock);
1581 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1582 lockdep_is_held(&rt6_exception_lock));
1583#ifdef CONFIG_IPV6_SUBTREES
1584 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1585 * and exception table is indexed by a hash of
1586 * both rt6i_dst and rt6i_src.
1587 * Otherwise, the exception table is indexed by
1588 * a hash of only rt6i_dst.
1589 */
David Ahern93c2fb22018-04-18 15:38:59 -07001590 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001591 src_key = &rt->rt6i_src.addr;
1592#endif
1593 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1594 &rt->rt6i_dst.addr,
1595 src_key);
1596 if (rt6_ex) {
1597 rt6_remove_exception(bucket, rt6_ex);
1598 err = 0;
1599 } else {
1600 err = -ENOENT;
1601 }
1602
1603 spin_unlock_bh(&rt6_exception_lock);
1604 return err;
1605}
1606
1607/* Find rt6_ex which contains the passed in rt cache and
1608 * refresh its stamp
1609 */
1610static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1611{
Wei Wang35732d02017-10-06 12:05:57 -07001612 struct rt6_exception_bucket *bucket;
1613 struct in6_addr *src_key = NULL;
1614 struct rt6_exception *rt6_ex;
Paolo Abeni193f3682019-02-21 11:19:41 +01001615 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001616
1617 rcu_read_lock();
Paolo Abeni193f3682019-02-21 11:19:41 +01001618 from = rcu_dereference(rt->from);
1619 if (!from || !(rt->rt6i_flags & RTF_CACHE))
1620 goto unlock;
1621
Wei Wang35732d02017-10-06 12:05:57 -07001622 bucket = rcu_dereference(from->rt6i_exception_bucket);
1623
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_rcu(&bucket,
1635 &rt->rt6i_dst.addr,
1636 src_key);
1637 if (rt6_ex)
1638 rt6_ex->stamp = jiffies;
1639
Paolo Abeni193f3682019-02-21 11:19:41 +01001640unlock:
Wei Wang35732d02017-10-06 12:05:57 -07001641 rcu_read_unlock();
1642}
1643
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001644static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1645 struct rt6_info *rt, int mtu)
1646{
1647 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1648 * lowest MTU in the path: always allow updating the route PMTU to
1649 * reflect PMTU decreases.
1650 *
1651 * If the new MTU is higher, and the route PMTU is equal to the local
1652 * MTU, this means the old MTU is the lowest in the path, so allow
1653 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1654 * handle this.
1655 */
1656
1657 if (dst_mtu(&rt->dst) >= mtu)
1658 return true;
1659
1660 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1661 return true;
1662
1663 return false;
1664}
1665
1666static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001667 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001668{
1669 struct rt6_exception_bucket *bucket;
1670 struct rt6_exception *rt6_ex;
1671 int i;
1672
1673 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1674 lockdep_is_held(&rt6_exception_lock));
1675
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001676 if (!bucket)
1677 return;
1678
1679 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1680 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1681 struct rt6_info *entry = rt6_ex->rt6i;
1682
1683 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001684 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001685 * been updated.
1686 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001687 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001688 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001689 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001690 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001691 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001692 }
1693}
1694
Wei Wangb16cb452017-10-06 12:06:00 -07001695#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1696
David Ahern8d1c8022018-04-17 17:33:26 -07001697static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001698 struct in6_addr *gateway)
1699{
1700 struct rt6_exception_bucket *bucket;
1701 struct rt6_exception *rt6_ex;
1702 struct hlist_node *tmp;
1703 int i;
1704
1705 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1706 return;
1707
1708 spin_lock_bh(&rt6_exception_lock);
1709 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1710 lockdep_is_held(&rt6_exception_lock));
1711
1712 if (bucket) {
1713 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1714 hlist_for_each_entry_safe(rt6_ex, tmp,
1715 &bucket->chain, hlist) {
1716 struct rt6_info *entry = rt6_ex->rt6i;
1717
1718 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1719 RTF_CACHE_GATEWAY &&
1720 ipv6_addr_equal(gateway,
1721 &entry->rt6i_gateway)) {
1722 rt6_remove_exception(bucket, rt6_ex);
1723 }
1724 }
1725 bucket++;
1726 }
1727 }
1728
1729 spin_unlock_bh(&rt6_exception_lock);
1730}
1731
Wei Wangc757faa2017-10-06 12:06:01 -07001732static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1733 struct rt6_exception *rt6_ex,
1734 struct fib6_gc_args *gc_args,
1735 unsigned long now)
1736{
1737 struct rt6_info *rt = rt6_ex->rt6i;
1738
Paolo Abeni1859bac2017-10-19 16:07:11 +02001739 /* we are pruning and obsoleting aged-out and non gateway exceptions
1740 * even if others have still references to them, so that on next
1741 * dst_check() such references can be dropped.
1742 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1743 * expired, independently from their aging, as per RFC 8201 section 4
1744 */
Wei Wang31afeb42018-01-26 11:40:17 -08001745 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1746 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1747 RT6_TRACE("aging clone %p\n", rt);
1748 rt6_remove_exception(bucket, rt6_ex);
1749 return;
1750 }
1751 } else if (time_after(jiffies, rt->dst.expires)) {
1752 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001753 rt6_remove_exception(bucket, rt6_ex);
1754 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001755 }
1756
1757 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001758 struct neighbour *neigh;
1759 __u8 neigh_flags = 0;
1760
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001761 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1762 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001763 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001764
Wei Wangc757faa2017-10-06 12:06:01 -07001765 if (!(neigh_flags & NTF_ROUTER)) {
1766 RT6_TRACE("purging route %p via non-router but gateway\n",
1767 rt);
1768 rt6_remove_exception(bucket, rt6_ex);
1769 return;
1770 }
1771 }
Wei Wang31afeb42018-01-26 11:40:17 -08001772
Wei Wangc757faa2017-10-06 12:06:01 -07001773 gc_args->more++;
1774}
1775
David Ahern8d1c8022018-04-17 17:33:26 -07001776void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001777 struct fib6_gc_args *gc_args,
1778 unsigned long now)
1779{
1780 struct rt6_exception_bucket *bucket;
1781 struct rt6_exception *rt6_ex;
1782 struct hlist_node *tmp;
1783 int i;
1784
1785 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1786 return;
1787
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001788 rcu_read_lock_bh();
1789 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001790 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1791 lockdep_is_held(&rt6_exception_lock));
1792
1793 if (bucket) {
1794 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1795 hlist_for_each_entry_safe(rt6_ex, tmp,
1796 &bucket->chain, hlist) {
1797 rt6_age_examine_exception(bucket, rt6_ex,
1798 gc_args, now);
1799 }
1800 bucket++;
1801 }
1802 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001803 spin_unlock(&rt6_exception_lock);
1804 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001805}
1806
David Ahern1d053da2018-05-09 20:34:21 -07001807/* must be called with rcu lock held */
1808struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
1809 int oif, struct flowi6 *fl6, int strict)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001811 struct fib6_node *fn, *saved_fn;
David Ahern8d1c8022018-04-17 17:33:26 -07001812 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
David Ahern64547432018-05-09 20:34:19 -07001814 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001815 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
David Ahernca254492015-10-12 11:47:10 -07001817 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1818 oif = 0;
1819
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001820redo_rt6_select:
David Ahern23fb93a2018-04-17 17:33:23 -07001821 f6i = rt6_select(net, fn, oif, strict);
David Ahern23fb93a2018-04-17 17:33:23 -07001822 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001823 fn = fib6_backtrack(fn, &fl6->saddr);
1824 if (fn)
1825 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001826 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1827 /* also consider unreachable route */
1828 strict &= ~RT6_LOOKUP_F_REACHABLE;
1829 fn = saved_fn;
1830 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001831 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001832 }
1833
David Ahernd4bea422018-05-09 20:34:24 -07001834 trace_fib6_table_lookup(net, f6i, table, fl6);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001835
David Ahern1d053da2018-05-09 20:34:21 -07001836 return f6i;
1837}
1838
1839struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1840 int oif, struct flowi6 *fl6,
1841 const struct sk_buff *skb, int flags)
1842{
1843 struct fib6_info *f6i;
1844 struct rt6_info *rt;
1845 int strict = 0;
1846
1847 strict |= flags & RT6_LOOKUP_F_IFACE;
1848 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1849 if (net->ipv6.devconf_all->forwarding == 0)
1850 strict |= RT6_LOOKUP_F_REACHABLE;
1851
1852 rcu_read_lock();
1853
1854 f6i = fib6_table_lookup(net, table, oif, fl6, strict);
1855 if (f6i->fib6_nsiblings)
1856 f6i = fib6_multipath_select(net, f6i, fl6, oif, skb, strict);
1857
David Ahern23fb93a2018-04-17 17:33:23 -07001858 if (f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001859 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001860 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001861 dst_hold(&rt->dst);
Wei Wangd3843fe2017-10-06 12:06:06 -07001862 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001863 }
1864
1865 /*Search through exception table */
1866 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1867 if (rt) {
David Ahernd4ead6b2018-04-17 17:33:16 -07001868 if (ip6_hold_safe(net, &rt, true))
Wei Wangd3843fe2017-10-06 12:06:06 -07001869 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001870
Wei Wang66f5d6c2017-10-06 12:06:10 -07001871 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001872 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001873 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahern93c2fb22018-04-18 15:38:59 -07001874 !(f6i->fib6_flags & RTF_GATEWAY))) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001875 /* Create a RTF_CACHE clone which will not be
1876 * owned by the fib6 tree. It is for the special case where
1877 * the daddr in the skb during the neighbor look-up is different
1878 * from the fl6->daddr used to look-up route here.
1879 */
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001880 struct rt6_info *uncached_rt;
1881
David Ahern23fb93a2018-04-17 17:33:23 -07001882 uncached_rt = ip6_rt_cache_alloc(f6i, &fl6->daddr, NULL);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001883
David Ahern4d85cd02018-04-20 15:37:59 -07001884 rcu_read_unlock();
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001885
Wei Wang1cfb71e2017-06-17 10:42:33 -07001886 if (uncached_rt) {
1887 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1888 * No need for another dst_hold()
1889 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001890 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001891 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001892 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001893 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001894 dst_hold(&uncached_rt->dst);
1895 }
David Ahernb8115802015-11-19 12:24:22 -08001896
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001897 return uncached_rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001898 } else {
1899 /* Get a percpu copy */
1900
1901 struct rt6_info *pcpu_rt;
1902
Eric Dumazet951f7882017-10-08 21:07:18 -07001903 local_bh_disable();
David Ahern23fb93a2018-04-17 17:33:23 -07001904 pcpu_rt = rt6_get_pcpu_route(f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001905
David Ahern93531c62018-04-17 17:33:25 -07001906 if (!pcpu_rt)
1907 pcpu_rt = rt6_make_pcpu_route(net, f6i);
1908
Eric Dumazet951f7882017-10-08 21:07:18 -07001909 local_bh_enable();
1910 rcu_read_unlock();
David Ahernd4bea422018-05-09 20:34:24 -07001911
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001912 return pcpu_rt;
1913 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001914}
David Ahern9ff74382016-06-13 13:44:19 -07001915EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001916
David Ahernb75cc8f2018-03-02 08:32:17 -08001917static struct rt6_info *ip6_pol_route_input(struct net *net,
1918 struct fib6_table *table,
1919 struct flowi6 *fl6,
1920 const struct sk_buff *skb,
1921 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001922{
David Ahernb75cc8f2018-03-02 08:32:17 -08001923 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001924}
1925
Mahesh Bandeward409b842016-09-16 12:59:08 -07001926struct dst_entry *ip6_route_input_lookup(struct net *net,
1927 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001928 struct flowi6 *fl6,
1929 const struct sk_buff *skb,
1930 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001931{
1932 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1933 flags |= RT6_LOOKUP_F_IFACE;
1934
David Ahernb75cc8f2018-03-02 08:32:17 -08001935 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001936}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001937EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001938
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001939static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001940 struct flow_keys *keys,
1941 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001942{
1943 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1944 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001945 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001946 const struct ipv6hdr *inner_iph;
1947 const struct icmp6hdr *icmph;
1948 struct ipv6hdr _inner_iph;
Eric Dumazetcea67a22018-04-29 09:54:59 -07001949 struct icmp6hdr _icmph;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001950
1951 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1952 goto out;
1953
Eric Dumazetcea67a22018-04-29 09:54:59 -07001954 icmph = skb_header_pointer(skb, skb_transport_offset(skb),
1955 sizeof(_icmph), &_icmph);
1956 if (!icmph)
1957 goto out;
1958
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001959 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1960 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1961 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1962 icmph->icmp6_type != ICMPV6_PARAMPROB)
1963 goto out;
1964
1965 inner_iph = skb_header_pointer(skb,
1966 skb_transport_offset(skb) + sizeof(*icmph),
1967 sizeof(_inner_iph), &_inner_iph);
1968 if (!inner_iph)
1969 goto out;
1970
1971 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001972 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001973out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001974 if (_flkeys) {
1975 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1976 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1977 keys->tags.flow_label = _flkeys->tags.flow_label;
1978 keys->basic.ip_proto = _flkeys->basic.ip_proto;
1979 } else {
1980 keys->addrs.v6addrs.src = key_iph->saddr;
1981 keys->addrs.v6addrs.dst = key_iph->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02001982 keys->tags.flow_label = ip6_flowlabel(key_iph);
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001983 keys->basic.ip_proto = key_iph->nexthdr;
1984 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001985}
1986
1987/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08001988u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
1989 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001990{
1991 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08001992 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001993
David S. Millerbbfa0472018-03-12 11:09:33 -04001994 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08001995 case 0:
1996 memset(&hash_keys, 0, sizeof(hash_keys));
1997 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1998 if (skb) {
1999 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2000 } else {
2001 hash_keys.addrs.v6addrs.src = fl6->saddr;
2002 hash_keys.addrs.v6addrs.dst = fl6->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02002003 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
David Ahernb4bac172018-03-02 08:32:18 -08002004 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2005 }
2006 break;
2007 case 1:
2008 if (skb) {
2009 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2010 struct flow_keys keys;
2011
2012 /* short-circuit if we already have L4 hash present */
2013 if (skb->l4_hash)
2014 return skb_get_hash_raw(skb) >> 1;
2015
2016 memset(&hash_keys, 0, sizeof(hash_keys));
2017
2018 if (!flkeys) {
2019 skb_flow_dissect_flow_keys(skb, &keys, flag);
2020 flkeys = &keys;
2021 }
2022 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2023 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2024 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2025 hash_keys.ports.src = flkeys->ports.src;
2026 hash_keys.ports.dst = flkeys->ports.dst;
2027 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2028 } else {
2029 memset(&hash_keys, 0, sizeof(hash_keys));
2030 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2031 hash_keys.addrs.v6addrs.src = fl6->saddr;
2032 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2033 hash_keys.ports.src = fl6->fl6_sport;
2034 hash_keys.ports.dst = fl6->fl6_dport;
2035 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2036 }
2037 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002038 }
David Ahern9a2a5372018-03-02 08:32:15 -08002039 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002040
David Ahern9a2a5372018-03-02 08:32:15 -08002041 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002042}
2043
Thomas Grafc71099a2006-08-04 23:20:06 -07002044void ip6_route_input(struct sk_buff *skb)
2045{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002046 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002047 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002048 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002049 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002050 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002051 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002052 .daddr = iph->daddr,
2053 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002054 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002055 .flowi6_mark = skb->mark,
2056 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002057 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002058 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002059
Jiri Benc904af042015-08-20 13:56:31 +02002060 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002061 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002062 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002063
2064 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2065 flkeys = &_flkeys;
2066
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002067 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002068 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002069 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002070 skb_dst_set(skb,
2071 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002072}
2073
David Ahernb75cc8f2018-03-02 08:32:17 -08002074static struct rt6_info *ip6_pol_route_output(struct net *net,
2075 struct fib6_table *table,
2076 struct flowi6 *fl6,
2077 const struct sk_buff *skb,
2078 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002079{
David Ahernb75cc8f2018-03-02 08:32:17 -08002080 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002081}
2082
Paolo Abeni6f21c962016-01-29 12:30:19 +01002083struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2084 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002085{
David Ahernd46a9d62015-10-21 08:42:22 -07002086 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002087
Robert Shearman3ede0bb2018-09-19 13:56:53 +01002088 if (ipv6_addr_type(&fl6->daddr) &
2089 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
David Ahern4c1feac2016-09-10 12:09:56 -07002090 struct dst_entry *dst;
2091
2092 dst = l3mdev_link_scope_lookup(net, fl6);
2093 if (dst)
2094 return dst;
2095 }
David Ahernca254492015-10-12 11:47:10 -07002096
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002097 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002098
David Ahernd46a9d62015-10-21 08:42:22 -07002099 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002100 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002101 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002102 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002103
David Ahernd46a9d62015-10-21 08:42:22 -07002104 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002105 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002106 else if (sk)
2107 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002108
David Ahernb75cc8f2018-03-02 08:32:17 -08002109 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002111EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
David S. Miller2774c132011-03-01 14:59:04 -08002113struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002114{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002115 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002116 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002117 struct dst_entry *new = NULL;
2118
Wei Wang1dbe32522017-06-17 10:42:26 -07002119 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002120 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002121 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002122 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002123 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002124
Changli Gaod8d1f302010-06-10 23:31:35 -07002125 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002126 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002127 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002128 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002129
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002130 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002131
Wei Wang1dbe32522017-06-17 10:42:26 -07002132 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002133 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002134 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002135
2136 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2137#ifdef CONFIG_IPV6_SUBTREES
2138 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2139#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002140 }
2141
David S. Miller69ead7a2011-03-01 14:45:33 -08002142 dst_release(dst_orig);
2143 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002144}
David S. Miller14e50e52007-05-24 18:17:54 -07002145
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146/*
2147 * Destination cache support functions
2148 */
2149
David Ahern8d1c8022018-04-17 17:33:26 -07002150static bool fib6_check(struct fib6_info *f6i, u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002151{
Steffen Klassert36143642017-08-25 09:05:42 +02002152 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002153
David Ahern8ae86972018-04-20 15:38:03 -07002154 if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
David Ahern93531c62018-04-17 17:33:25 -07002155 return false;
2156
2157 if (fib6_check_expired(f6i))
2158 return false;
2159
2160 return true;
2161}
2162
David Aherna68886a2018-04-20 15:38:02 -07002163static struct dst_entry *rt6_check(struct rt6_info *rt,
2164 struct fib6_info *from,
2165 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002166{
Wei Wangc5cff852017-08-21 09:47:10 -07002167 u32 rt_cookie = 0;
2168
David Aherna68886a2018-04-20 15:38:02 -07002169 if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
David Ahern93531c62018-04-17 17:33:25 -07002170 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002171 return NULL;
2172
2173 if (rt6_check_expired(rt))
2174 return NULL;
2175
2176 return &rt->dst;
2177}
2178
David Aherna68886a2018-04-20 15:38:02 -07002179static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2180 struct fib6_info *from,
2181 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002182{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002183 if (!__rt6_check_expired(rt) &&
2184 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Aherna68886a2018-04-20 15:38:02 -07002185 fib6_check(from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002186 return &rt->dst;
2187 else
2188 return NULL;
2189}
2190
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2192{
David Aherna87b7dc2018-04-20 15:38:00 -07002193 struct dst_entry *dst_ret;
David Aherna68886a2018-04-20 15:38:02 -07002194 struct fib6_info *from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 struct rt6_info *rt;
2196
David Aherna87b7dc2018-04-20 15:38:00 -07002197 rt = container_of(dst, struct rt6_info, dst);
2198
2199 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002201 /* All IPV6 dsts are created with ->obsolete set to the value
2202 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2203 * into this function always.
2204 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002205
David Aherna68886a2018-04-20 15:38:02 -07002206 from = rcu_dereference(rt->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002207
David Aherna68886a2018-04-20 15:38:02 -07002208 if (from && (rt->rt6i_flags & RTF_PCPU ||
2209 unlikely(!list_empty(&rt->rt6i_uncached))))
2210 dst_ret = rt6_dst_from_check(rt, from, cookie);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002211 else
David Aherna68886a2018-04-20 15:38:02 -07002212 dst_ret = rt6_check(rt, from, cookie);
David Aherna87b7dc2018-04-20 15:38:00 -07002213
2214 rcu_read_unlock();
2215
2216 return dst_ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217}
2218
2219static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2220{
2221 struct rt6_info *rt = (struct rt6_info *) dst;
2222
2223 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002224 if (rt->rt6i_flags & RTF_CACHE) {
David Ahernc3c14da2018-04-23 11:32:06 -07002225 rcu_read_lock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002226 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002227 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002228 dst = NULL;
2229 }
David Ahernc3c14da2018-04-23 11:32:06 -07002230 rcu_read_unlock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002231 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002233 dst = NULL;
2234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002236 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237}
2238
2239static void ip6_link_failure(struct sk_buff *skb)
2240{
2241 struct rt6_info *rt;
2242
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002243 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
Eric Dumazetadf30902009-06-02 05:19:30 +00002245 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 if (rt) {
David Ahern8a14e462018-04-23 11:32:07 -07002247 rcu_read_lock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002248 if (rt->rt6i_flags & RTF_CACHE) {
Xin Long761f6022018-11-14 00:48:28 +08002249 rt6_remove_exception_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002250 } else {
David Aherna68886a2018-04-20 15:38:02 -07002251 struct fib6_info *from;
Wei Wangc5cff852017-08-21 09:47:10 -07002252 struct fib6_node *fn;
2253
David Aherna68886a2018-04-20 15:38:02 -07002254 from = rcu_dereference(rt->from);
2255 if (from) {
2256 fn = rcu_dereference(from->fib6_node);
2257 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2258 fn->fn_sernum = -1;
2259 }
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002260 }
David Ahern8a14e462018-04-23 11:32:07 -07002261 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 }
2263}
2264
David Ahern6a3e0302018-04-20 15:37:57 -07002265static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2266{
David Aherna68886a2018-04-20 15:38:02 -07002267 if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2268 struct fib6_info *from;
2269
2270 rcu_read_lock();
2271 from = rcu_dereference(rt0->from);
2272 if (from)
2273 rt0->dst.expires = from->expires;
2274 rcu_read_unlock();
2275 }
David Ahern6a3e0302018-04-20 15:37:57 -07002276
2277 dst_set_expires(&rt0->dst, timeout);
2278 rt0->rt6i_flags |= RTF_EXPIRES;
2279}
2280
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002281static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2282{
2283 struct net *net = dev_net(rt->dst.dev);
2284
David Ahernd4ead6b2018-04-17 17:33:16 -07002285 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002286 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002287 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2288}
2289
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002290static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2291{
David Aherna68886a2018-04-20 15:38:02 -07002292 bool from_set;
2293
2294 rcu_read_lock();
2295 from_set = !!rcu_dereference(rt->from);
2296 rcu_read_unlock();
2297
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002298 return !(rt->rt6i_flags & RTF_CACHE) &&
David Aherna68886a2018-04-20 15:38:02 -07002299 (rt->rt6i_flags & RTF_PCPU || from_set);
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002300}
2301
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002302static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2303 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002305 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002306 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Xin Long19bda362016-10-28 18:18:01 +08002308 if (dst_metric_locked(dst, RTAX_MTU))
2309 return;
2310
Julian Anastasov0dec8792017-02-06 23:14:16 +02002311 if (iph) {
2312 daddr = &iph->daddr;
2313 saddr = &iph->saddr;
2314 } else if (sk) {
2315 daddr = &sk->sk_v6_daddr;
2316 saddr = &inet6_sk(sk)->saddr;
2317 } else {
2318 daddr = NULL;
2319 saddr = NULL;
2320 }
2321 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002322 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2323 if (mtu >= dst_mtu(dst))
2324 return;
David S. Miller81aded22012-06-15 14:54:11 -07002325
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002326 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002327 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002328 /* update rt6_ex->stamp for cache */
2329 if (rt6->rt6i_flags & RTF_CACHE)
2330 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002331 } else if (daddr) {
David Aherna68886a2018-04-20 15:38:02 -07002332 struct fib6_info *from;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002333 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002334
David Ahern4d85cd02018-04-20 15:37:59 -07002335 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07002336 from = rcu_dereference(rt6->from);
2337 nrt6 = ip6_rt_cache_alloc(from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002338 if (nrt6) {
2339 rt6_do_update_pmtu(nrt6, mtu);
David Aherna68886a2018-04-20 15:38:02 -07002340 if (rt6_insert_exception(nrt6, from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002341 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002342 }
David Aherna68886a2018-04-20 15:38:02 -07002343 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 }
2345}
2346
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002347static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2348 struct sk_buff *skb, u32 mtu)
2349{
2350 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2351}
2352
David S. Miller42ae66c2012-06-15 20:01:57 -07002353void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002354 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002355{
2356 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2357 struct dst_entry *dst;
Maciej Żenczykowskidc920952018-09-29 23:44:51 -07002358 struct flowi6 fl6 = {
2359 .flowi6_oif = oif,
2360 .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark),
2361 .daddr = iph->daddr,
2362 .saddr = iph->saddr,
2363 .flowlabel = ip6_flowinfo(iph),
2364 .flowi6_uid = uid,
2365 };
David S. Miller81aded22012-06-15 14:54:11 -07002366
2367 dst = ip6_route_output(net, NULL, &fl6);
2368 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002369 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002370 dst_release(dst);
2371}
2372EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2373
2374void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2375{
David Ahern7ddacfa2018-11-18 10:45:30 -08002376 int oif = sk->sk_bound_dev_if;
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002377 struct dst_entry *dst;
2378
David Ahern7ddacfa2018-11-18 10:45:30 -08002379 if (!oif && skb->dev)
2380 oif = l3mdev_master_ifindex(skb->dev);
2381
2382 ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002383
2384 dst = __sk_dst_get(sk);
2385 if (!dst || !dst->obsolete ||
2386 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2387 return;
2388
2389 bh_lock_sock(sk);
2390 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2391 ip6_datagram_dst_update(sk, false);
2392 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002393}
2394EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2395
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002396void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2397 const struct flowi6 *fl6)
2398{
2399#ifdef CONFIG_IPV6_SUBTREES
2400 struct ipv6_pinfo *np = inet6_sk(sk);
2401#endif
2402
2403 ip6_dst_store(sk, dst,
2404 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2405 &sk->sk_v6_daddr : NULL,
2406#ifdef CONFIG_IPV6_SUBTREES
2407 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2408 &np->saddr :
2409#endif
2410 NULL);
2411}
2412
Duan Jiongb55b76b2013-09-04 19:44:21 +08002413/* Handle redirects */
2414struct ip6rd_flowi {
2415 struct flowi6 fl6;
2416 struct in6_addr gateway;
2417};
2418
2419static struct rt6_info *__ip6_route_redirect(struct net *net,
2420 struct fib6_table *table,
2421 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002422 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002423 int flags)
2424{
2425 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern23fb93a2018-04-17 17:33:23 -07002426 struct rt6_info *ret = NULL, *rt_cache;
David Ahern8d1c8022018-04-17 17:33:26 -07002427 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002428 struct fib6_node *fn;
2429
2430 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002431 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002432 *
2433 * RFC 4861 specifies that redirects should only be
2434 * accepted if they come from the nexthop to the target.
2435 * Due to the way the routes are chosen, this notion
2436 * is a bit fuzzy and one might need to check all possible
2437 * routes.
2438 */
2439
Wei Wang66f5d6c2017-10-06 12:06:10 -07002440 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002441 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002442restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002443 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07002444 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +02002445 continue;
David Ahern14895682018-04-17 17:33:17 -07002446 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002447 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002448 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002449 break;
David Ahern93c2fb22018-04-18 15:38:59 -07002450 if (!(rt->fib6_flags & RTF_GATEWAY))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002451 continue;
David Ahern5e670d82018-04-17 17:33:14 -07002452 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002453 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002454 /* rt_cache's gateway might be different from its 'parent'
2455 * in the case of an ip redirect.
2456 * So we keep searching in the exception table if the gateway
2457 * is different.
2458 */
David Ahern5e670d82018-04-17 17:33:14 -07002459 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002460 rt_cache = rt6_find_cached_rt(rt,
2461 &fl6->daddr,
2462 &fl6->saddr);
2463 if (rt_cache &&
2464 ipv6_addr_equal(&rdfl->gateway,
2465 &rt_cache->rt6i_gateway)) {
David Ahern23fb93a2018-04-17 17:33:23 -07002466 ret = rt_cache;
Wei Wang2b760fc2017-10-06 12:06:03 -07002467 break;
2468 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002469 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002470 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002471 break;
2472 }
2473
2474 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002475 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002476 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002477 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002478 goto out;
2479 }
2480
David Ahern421842e2018-04-17 17:33:18 -07002481 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002482 fn = fib6_backtrack(fn, &fl6->saddr);
2483 if (fn)
2484 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002485 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002486
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002487out:
David Ahern23fb93a2018-04-17 17:33:23 -07002488 if (ret)
Wei Wange873e4b2018-07-21 20:56:32 -07002489 ip6_hold_safe(net, &ret, true);
David Ahern23fb93a2018-04-17 17:33:23 -07002490 else
2491 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002492
Wei Wang66f5d6c2017-10-06 12:06:10 -07002493 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002494
Paolo Abenib65f1642017-10-19 09:31:43 +02002495 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002496 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002497};
2498
2499static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002500 const struct flowi6 *fl6,
2501 const struct sk_buff *skb,
2502 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002503{
2504 int flags = RT6_LOOKUP_F_HAS_SADDR;
2505 struct ip6rd_flowi rdfl;
2506
2507 rdfl.fl6 = *fl6;
2508 rdfl.gateway = *gateway;
2509
David Ahernb75cc8f2018-03-02 08:32:17 -08002510 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002511 flags, __ip6_route_redirect);
2512}
2513
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002514void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2515 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002516{
2517 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2518 struct dst_entry *dst;
Maciej Żenczykowski1f7f10a2018-09-29 23:44:48 -07002519 struct flowi6 fl6 = {
2520 .flowi6_iif = LOOPBACK_IFINDEX,
2521 .flowi6_oif = oif,
2522 .flowi6_mark = mark,
2523 .daddr = iph->daddr,
2524 .saddr = iph->saddr,
2525 .flowlabel = ip6_flowinfo(iph),
2526 .flowi6_uid = uid,
2527 };
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002528
David Ahernb75cc8f2018-03-02 08:32:17 -08002529 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002530 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002531 dst_release(dst);
2532}
2533EXPORT_SYMBOL_GPL(ip6_redirect);
2534
Maciej Żenczykowskid4563362018-09-29 23:44:50 -07002535void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
Duan Jiongc92a59e2013-08-22 12:07:35 +08002536{
2537 const struct ipv6hdr *iph = ipv6_hdr(skb);
2538 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2539 struct dst_entry *dst;
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002540 struct flowi6 fl6 = {
2541 .flowi6_iif = LOOPBACK_IFINDEX,
2542 .flowi6_oif = oif,
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002543 .daddr = msg->dest,
2544 .saddr = iph->daddr,
2545 .flowi6_uid = sock_net_uid(net, NULL),
2546 };
Duan Jiongc92a59e2013-08-22 12:07:35 +08002547
David Ahernb75cc8f2018-03-02 08:32:17 -08002548 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002549 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002550 dst_release(dst);
2551}
2552
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002553void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2554{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002555 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2556 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002557}
2558EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2559
David S. Miller0dbaee32010-12-13 12:52:14 -08002560static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561{
David S. Miller0dbaee32010-12-13 12:52:14 -08002562 struct net_device *dev = dst->dev;
2563 unsigned int mtu = dst_mtu(dst);
2564 struct net *net = dev_net(dev);
2565
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2567
Daniel Lezcano55786892008-03-04 13:47:47 -08002568 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2569 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570
2571 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002572 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2573 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2574 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 * rely only on pmtu discovery"
2576 */
2577 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2578 mtu = IPV6_MAXPLEN;
2579 return mtu;
2580}
2581
Steffen Klassertebb762f2011-11-23 02:12:51 +00002582static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002583{
David S. Millerd33e4552010-12-14 13:01:14 -08002584 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002585 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002586
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002587 mtu = dst_metric_raw(dst, RTAX_MTU);
2588 if (mtu)
2589 goto out;
2590
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002591 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002592
2593 rcu_read_lock();
2594 idev = __in6_dev_get(dst->dev);
2595 if (idev)
2596 mtu = idev->cnf.mtu6;
2597 rcu_read_unlock();
2598
Eric Dumazet30f78d82014-04-10 21:23:36 -07002599out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002600 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2601
2602 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002603}
2604
David Ahern901731b2018-05-21 09:08:14 -07002605/* MTU selection:
2606 * 1. mtu on route is locked - use it
2607 * 2. mtu from nexthop exception
2608 * 3. mtu from egress device
2609 *
2610 * based on ip6_dst_mtu_forward and exception logic of
2611 * rt6_find_cached_rt; called with rcu_read_lock
2612 */
2613u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
2614 struct in6_addr *saddr)
2615{
2616 struct rt6_exception_bucket *bucket;
2617 struct rt6_exception *rt6_ex;
2618 struct in6_addr *src_key;
2619 struct inet6_dev *idev;
2620 u32 mtu = 0;
2621
2622 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2623 mtu = f6i->fib6_pmtu;
2624 if (mtu)
2625 goto out;
2626 }
2627
2628 src_key = NULL;
2629#ifdef CONFIG_IPV6_SUBTREES
2630 if (f6i->fib6_src.plen)
2631 src_key = saddr;
2632#endif
2633
2634 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2635 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2636 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2637 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2638
2639 if (likely(!mtu)) {
2640 struct net_device *dev = fib6_info_nh_dev(f6i);
2641
2642 mtu = IPV6_MIN_MTU;
2643 idev = __in6_dev_get(dev);
2644 if (idev && idev->cnf.mtu6 > mtu)
2645 mtu = idev->cnf.mtu6;
2646 }
2647
2648 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2649out:
2650 return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu);
2651}
2652
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002653struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002654 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
David S. Miller87a11572011-12-06 17:04:13 -05002656 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 struct rt6_info *rt;
2658 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002659 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
David S. Miller38308472011-12-03 18:02:47 -05002661 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002662 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Martin KaFai Lauad706862015-08-14 11:05:52 -07002664 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002665 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002667 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 goto out;
2669 }
2670
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002671 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002672 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002673 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002674 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002675 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002676 rt->rt6i_dst.plen = 128;
2677 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002678 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
Ido Schimmel4c981e22018-01-07 12:45:04 +02002680 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002681 * do proper release of the net_device
2682 */
2683 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002684 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
David S. Miller87a11572011-12-06 17:04:13 -05002686 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688out:
David S. Miller87a11572011-12-06 17:04:13 -05002689 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690}
2691
Daniel Lezcano569d3642008-01-18 03:56:57 -08002692static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002694 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002695 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2696 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2697 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2698 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2699 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002700 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Eric Dumazetfc66f952010-10-08 06:37:34 +00002702 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002703 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002704 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 goto out;
2706
Benjamin Thery6891a342008-03-04 13:49:47 -08002707 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002708 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002709 entries = dst_entries_get_slow(ops);
2710 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002711 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002713 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002714 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715}
2716
David Ahern8c145862016-04-24 21:26:04 -07002717static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2718 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002719 const struct in6_addr *gw_addr,
2720 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002721{
2722 struct flowi6 fl6 = {
2723 .flowi6_oif = cfg->fc_ifindex,
2724 .daddr = *gw_addr,
2725 .saddr = cfg->fc_prefsrc,
2726 };
2727 struct fib6_table *table;
2728 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002729
David Ahernf4797b32018-01-25 16:55:08 -08002730 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002731 if (!table)
2732 return NULL;
2733
2734 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2735 flags |= RT6_LOOKUP_F_HAS_SADDR;
2736
David Ahernf4797b32018-01-25 16:55:08 -08002737 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002738 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002739
2740 /* if table lookup failed, fall back to full lookup */
2741 if (rt == net->ipv6.ip6_null_entry) {
2742 ip6_rt_put(rt);
2743 rt = NULL;
2744 }
2745
2746 return rt;
2747}
2748
David Ahernfc1e64e2018-01-25 16:55:09 -08002749static int ip6_route_check_nh_onlink(struct net *net,
2750 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002751 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002752 struct netlink_ext_ack *extack)
2753{
David Ahern44750f82018-02-06 13:17:06 -08002754 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002755 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2756 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002757 struct fib6_info *from;
David Ahernfc1e64e2018-01-25 16:55:09 -08002758 struct rt6_info *grt;
2759 int err;
2760
2761 err = 0;
2762 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2763 if (grt) {
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002764 rcu_read_lock();
2765 from = rcu_dereference(grt->from);
David Ahern58e354c2018-02-06 12:14:12 -08002766 if (!grt->dst.error &&
David Ahern4ed591c2018-10-24 13:58:39 -07002767 /* ignore match if it is the default route */
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002768 from && !ipv6_addr_any(&from->fib6_dst.addr) &&
David Ahern58e354c2018-02-06 12:14:12 -08002769 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002770 NL_SET_ERR_MSG(extack,
2771 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002772 err = -EINVAL;
2773 }
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002774 rcu_read_unlock();
David Ahernfc1e64e2018-01-25 16:55:09 -08002775
2776 ip6_rt_put(grt);
2777 }
2778
2779 return err;
2780}
2781
David Ahern1edce992018-01-25 16:55:07 -08002782static int ip6_route_check_nh(struct net *net,
2783 struct fib6_config *cfg,
2784 struct net_device **_dev,
2785 struct inet6_dev **idev)
2786{
2787 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2788 struct net_device *dev = _dev ? *_dev : NULL;
2789 struct rt6_info *grt = NULL;
2790 int err = -EHOSTUNREACH;
2791
2792 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002793 int flags = RT6_LOOKUP_F_IFACE;
2794
2795 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2796 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002797 if (grt) {
2798 if (grt->rt6i_flags & RTF_GATEWAY ||
2799 (dev && dev != grt->dst.dev)) {
2800 ip6_rt_put(grt);
2801 grt = NULL;
2802 }
2803 }
2804 }
2805
2806 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002807 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002808
2809 if (!grt)
2810 goto out;
2811
2812 if (dev) {
2813 if (dev != grt->dst.dev) {
2814 ip6_rt_put(grt);
2815 goto out;
2816 }
2817 } else {
2818 *_dev = dev = grt->dst.dev;
2819 *idev = grt->rt6i_idev;
2820 dev_hold(dev);
2821 in6_dev_hold(grt->rt6i_idev);
2822 }
2823
2824 if (!(grt->rt6i_flags & RTF_GATEWAY))
2825 err = 0;
2826
2827 ip6_rt_put(grt);
2828
2829out:
2830 return err;
2831}
2832
David Ahern9fbb7042018-03-13 08:29:36 -07002833static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2834 struct net_device **_dev, struct inet6_dev **idev,
2835 struct netlink_ext_ack *extack)
2836{
2837 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2838 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002839 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002840 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002841 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002842 int err = -EINVAL;
2843
2844 /* if gw_addr is local we will fail to detect this in case
2845 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2846 * will return already-added prefix route via interface that
2847 * prefix route was assigned to, which might be non-loopback.
2848 */
David Ahern232378e2018-03-13 08:29:37 -07002849 if (dev &&
2850 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2851 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002852 goto out;
2853 }
2854
2855 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2856 /* IPv6 strictly inhibits using not link-local
2857 * addresses as nexthop address.
2858 * Otherwise, router will not able to send redirects.
2859 * It is very good, but in some (rare!) circumstances
2860 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2861 * some exceptions. --ANK
2862 * We allow IPv4-mapped nexthops to support RFC4798-type
2863 * addressing
2864 */
2865 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2866 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2867 goto out;
2868 }
2869
2870 if (cfg->fc_flags & RTNH_F_ONLINK)
2871 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2872 else
2873 err = ip6_route_check_nh(net, cfg, _dev, idev);
2874
2875 if (err)
2876 goto out;
2877 }
2878
2879 /* reload in case device was changed */
2880 dev = *_dev;
2881
2882 err = -EINVAL;
2883 if (!dev) {
2884 NL_SET_ERR_MSG(extack, "Egress device not specified");
2885 goto out;
2886 } else if (dev->flags & IFF_LOOPBACK) {
2887 NL_SET_ERR_MSG(extack,
2888 "Egress device can not be loopback device for this route");
2889 goto out;
2890 }
David Ahern232378e2018-03-13 08:29:37 -07002891
2892 /* if we did not check gw_addr above, do so now that the
2893 * egress device has been resolved.
2894 */
2895 if (need_addr_check &&
2896 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2897 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2898 goto out;
2899 }
2900
David Ahern9fbb7042018-03-13 08:29:36 -07002901 err = 0;
2902out:
2903 return err;
2904}
2905
David Ahern8d1c8022018-04-17 17:33:26 -07002906static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07002907 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06002908 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909{
Daniel Lezcano55786892008-03-04 13:47:47 -08002910 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07002911 struct fib6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 struct net_device *dev = NULL;
2913 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002914 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002916 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
David Ahern557c44b2017-04-19 14:19:43 -07002918 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002919 if (cfg->fc_flags & RTF_PCPU) {
2920 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002921 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002922 }
David Ahern557c44b2017-04-19 14:19:43 -07002923
Wei Wang2ea23522017-10-27 17:30:12 -07002924 /* RTF_CACHE is an internal flag; can not be set by userspace */
2925 if (cfg->fc_flags & RTF_CACHE) {
2926 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2927 goto out;
2928 }
2929
David Aherne8478e82018-04-17 17:33:13 -07002930 if (cfg->fc_type > RTN_MAX) {
2931 NL_SET_ERR_MSG(extack, "Invalid route type");
2932 goto out;
2933 }
2934
David Ahernd5d531c2017-05-21 10:12:05 -06002935 if (cfg->fc_dst_len > 128) {
2936 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002937 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002938 }
2939 if (cfg->fc_src_len > 128) {
2940 NL_SET_ERR_MSG(extack, "Invalid source address length");
2941 goto out;
2942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002944 if (cfg->fc_src_len) {
2945 NL_SET_ERR_MSG(extack,
2946 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002947 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002950 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002952 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 if (!dev)
2954 goto out;
2955 idev = in6_dev_get(dev);
2956 if (!idev)
2957 goto out;
2958 }
2959
Thomas Graf86872cb2006-08-22 00:01:08 -07002960 if (cfg->fc_metric == 0)
2961 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
David Ahernfc1e64e2018-01-25 16:55:09 -08002963 if (cfg->fc_flags & RTNH_F_ONLINK) {
2964 if (!dev) {
2965 NL_SET_ERR_MSG(extack,
2966 "Nexthop device required for onlink");
2967 err = -ENODEV;
2968 goto out;
2969 }
2970
2971 if (!(dev->flags & IFF_UP)) {
2972 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2973 err = -ENETDOWN;
2974 goto out;
2975 }
2976 }
2977
Matti Vaittinend71314b2011-11-14 00:14:49 +00002978 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002979 if (cfg->fc_nlinfo.nlh &&
2980 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00002981 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002982 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00002983 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00002984 table = fib6_new_table(net, cfg->fc_table);
2985 }
2986 } else {
2987 table = fib6_new_table(net, cfg->fc_table);
2988 }
David S. Miller38308472011-12-03 18:02:47 -05002989
2990 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002991 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07002992
David Ahern93531c62018-04-17 17:33:25 -07002993 err = -ENOMEM;
2994 rt = fib6_info_alloc(gfp_flags);
2995 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 goto out;
David Ahern93531c62018-04-17 17:33:25 -07002997
David Ahernd7e774f2018-11-06 12:51:15 -08002998 rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
2999 extack);
David Ahern767a2212018-10-04 20:07:51 -07003000 if (IS_ERR(rt->fib6_metrics)) {
3001 err = PTR_ERR(rt->fib6_metrics);
Eric Dumazetfda21d42018-10-05 09:17:50 -07003002 /* Do not leave garbage there. */
3003 rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
David Ahern767a2212018-10-04 20:07:51 -07003004 goto out;
3005 }
3006
David Ahern93531c62018-04-17 17:33:25 -07003007 if (cfg->fc_flags & RTF_ADDRCONF)
3008 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
Gao feng1716a962012-04-06 00:13:10 +00003010 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07003011 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00003012 clock_t_to_jiffies(cfg->fc_expires));
3013 else
David Ahern14895682018-04-17 17:33:17 -07003014 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
Thomas Graf86872cb2006-08-22 00:01:08 -07003016 if (cfg->fc_protocol == RTPROT_UNSPEC)
3017 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003018 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003019
3020 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003022 if (cfg->fc_encap) {
3023 struct lwtunnel_state *lwtstate;
3024
David Ahern30357d72017-01-30 12:07:37 -08003025 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07003026 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06003027 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003028 if (err)
3029 goto out;
David Ahern5e670d82018-04-17 17:33:14 -07003030 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003031 }
3032
David Ahern93c2fb22018-04-18 15:38:59 -07003033 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3034 rt->fib6_dst.plen = cfg->fc_dst_len;
3035 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003036 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003037
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003039 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3040 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041#endif
3042
David Ahern93c2fb22018-04-18 15:38:59 -07003043 rt->fib6_metric = cfg->fc_metric;
David Ahern5e670d82018-04-17 17:33:14 -07003044 rt->fib6_nh.nh_weight = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
David Aherne8478e82018-04-17 17:33:13 -07003046 rt->fib6_type = cfg->fc_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047
3048 /* We cannot add true routes via loopback here,
3049 they would result in kernel looping; promote them to reject routes
3050 */
Thomas Graf86872cb2006-08-22 00:01:08 -07003051 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05003052 (dev && (dev->flags & IFF_LOOPBACK) &&
3053 !(addr_type & IPV6_ADDR_LOOPBACK) &&
3054 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08003056 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 if (dev) {
3058 dev_put(dev);
3059 in6_dev_put(idev);
3060 }
Daniel Lezcano55786892008-03-04 13:47:47 -08003061 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 dev_hold(dev);
3063 idev = in6_dev_get(dev);
3064 if (!idev) {
3065 err = -ENODEV;
3066 goto out;
3067 }
3068 }
David Ahern93c2fb22018-04-18 15:38:59 -07003069 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 goto install_route;
3071 }
3072
Thomas Graf86872cb2006-08-22 00:01:08 -07003073 if (cfg->fc_flags & RTF_GATEWAY) {
David Ahern9fbb7042018-03-13 08:29:36 -07003074 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3075 if (err)
Florian Westphal48ed7b22015-05-21 00:25:41 +02003076 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
David Ahern93531c62018-04-17 17:33:25 -07003078 rt->fib6_nh.nh_gw = cfg->fc_gateway;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 }
3080
3081 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05003082 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 goto out;
3084
Lorenzo Bianconi428604f2018-03-29 11:02:24 +02003085 if (idev->cnf.disable_ipv6) {
3086 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3087 err = -EACCES;
3088 goto out;
3089 }
3090
David Ahern955ec4c2018-01-24 19:45:29 -08003091 if (!(dev->flags & IFF_UP)) {
3092 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3093 err = -ENETDOWN;
3094 goto out;
3095 }
3096
Daniel Walterc3968a82011-04-13 21:10:57 +00003097 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
3098 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003099 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003100 err = -EINVAL;
3101 goto out;
3102 }
David Ahern93c2fb22018-04-18 15:38:59 -07003103 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3104 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003105 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003106 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003107
David Ahern93c2fb22018-04-18 15:38:59 -07003108 rt->fib6_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110install_route:
David Ahern93c2fb22018-04-18 15:38:59 -07003111 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
Ido Schimmel5609b802018-01-07 12:45:06 +02003112 !netif_carrier_ok(dev))
David Ahern5e670d82018-04-17 17:33:14 -07003113 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
3114 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
David Ahern93531c62018-04-17 17:33:25 -07003115 rt->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07003116 rt->fib6_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003117
David Aherndcd1f572018-04-18 15:39:05 -07003118 if (idev)
3119 in6_dev_put(idev);
3120
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003121 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122out:
3123 if (dev)
3124 dev_put(dev);
3125 if (idev)
3126 in6_dev_put(idev);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003127
David Ahern93531c62018-04-17 17:33:25 -07003128 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003129 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003130}
3131
David Ahernacb54e32018-04-17 17:33:22 -07003132int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003133 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003134{
David Ahern8d1c8022018-04-17 17:33:26 -07003135 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003136 int err;
3137
David Ahernacb54e32018-04-17 17:33:22 -07003138 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003139 if (IS_ERR(rt))
3140 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003141
David Ahernd4ead6b2018-04-17 17:33:16 -07003142 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003143 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003144
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 return err;
3146}
3147
David Ahern8d1c8022018-04-17 17:33:26 -07003148static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149{
David Ahernafb1d4b52018-04-17 17:33:11 -07003150 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003151 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003152 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
David Ahern421842e2018-04-17 17:33:18 -07003154 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003155 err = -ENOENT;
3156 goto out;
3157 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003158
David Ahern93c2fb22018-04-18 15:38:59 -07003159 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003160 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003161 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003162 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
Gao feng6825a262012-09-19 19:25:34 +00003164out:
David Ahern93531c62018-04-17 17:33:25 -07003165 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 return err;
3167}
3168
David Ahern8d1c8022018-04-17 17:33:26 -07003169int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003170{
David Ahernafb1d4b52018-04-17 17:33:11 -07003171 struct nl_info info = { .nl_net = net };
3172
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003173 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003174}
3175
David Ahern8d1c8022018-04-17 17:33:26 -07003176static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003177{
3178 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003179 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003180 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003181 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003182 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003183
David Ahern421842e2018-04-17 17:33:18 -07003184 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003185 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003186 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003187 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003188
David Ahern93c2fb22018-04-18 15:38:59 -07003189 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003190 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003191
David Ahern16a16cd2017-02-02 12:37:11 -08003192 /* prefer to send a single notification with all hops */
3193 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3194 if (skb) {
3195 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3196
David Ahernd4ead6b2018-04-17 17:33:16 -07003197 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003198 NULL, NULL, 0, RTM_DELROUTE,
3199 info->portid, seq, 0) < 0) {
3200 kfree_skb(skb);
3201 skb = NULL;
3202 } else
3203 info->skip_notify = 1;
3204 }
3205
David Ahern0ae81332017-02-02 12:37:08 -08003206 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003207 &rt->fib6_siblings,
3208 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003209 err = fib6_del(sibling, info);
3210 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003211 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003212 }
3213 }
3214
3215 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003216out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003217 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003218out_put:
David Ahern93531c62018-04-17 17:33:25 -07003219 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003220
3221 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003222 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003223 info->nlh, gfp_any());
3224 }
David Ahern0ae81332017-02-02 12:37:08 -08003225 return err;
3226}
3227
David Ahern23fb93a2018-04-17 17:33:23 -07003228static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3229{
3230 int rc = -ESRCH;
3231
3232 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3233 goto out;
3234
3235 if (cfg->fc_flags & RTF_GATEWAY &&
3236 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3237 goto out;
Xin Long761f6022018-11-14 00:48:28 +08003238
3239 rc = rt6_remove_exception_rt(rt);
David Ahern23fb93a2018-04-17 17:33:23 -07003240out:
3241 return rc;
3242}
3243
David Ahern333c4302017-05-21 10:12:04 -06003244static int ip6_route_del(struct fib6_config *cfg,
3245 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246{
David Ahern8d1c8022018-04-17 17:33:26 -07003247 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003248 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003249 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 int err = -ESRCH;
3252
Daniel Lezcano55786892008-03-04 13:47:47 -08003253 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003254 if (!table) {
3255 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003256 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
Wei Wang66f5d6c2017-10-06 12:06:10 -07003259 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003260
3261 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003262 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003263 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003264 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003265
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003267 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003268 if (cfg->fc_flags & RTF_CACHE) {
David Ahern23fb93a2018-04-17 17:33:23 -07003269 int rc;
3270
Wei Wang2b760fc2017-10-06 12:06:03 -07003271 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
3272 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003273 if (rt_cache) {
3274 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003275 if (rc != -ESRCH) {
3276 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003277 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003278 }
David Ahern23fb93a2018-04-17 17:33:23 -07003279 }
3280 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003281 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003282 if (cfg->fc_ifindex &&
David Ahern5e670d82018-04-17 17:33:14 -07003283 (!rt->fib6_nh.nh_dev ||
3284 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003286 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahern5e670d82018-04-17 17:33:14 -07003287 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003289 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003291 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003292 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003293 if (!fib6_info_hold_safe(rt))
3294 continue;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003295 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
David Ahern0ae81332017-02-02 12:37:08 -08003297 /* if gateway was specified only delete the one hop */
3298 if (cfg->fc_flags & RTF_GATEWAY)
3299 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3300
3301 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 }
3303 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003304 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305
3306 return err;
3307}
3308
David S. Miller6700c272012-07-17 03:29:28 -07003309static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003310{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003311 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003312 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003313 struct ndisc_options ndopts;
3314 struct inet6_dev *in6_dev;
3315 struct neighbour *neigh;
David Aherna68886a2018-04-20 15:38:02 -07003316 struct fib6_info *from;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003317 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003318 int optlen, on_link;
3319 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003320
Simon Horman29a3cad2013-05-28 20:34:26 +00003321 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003322 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003323
3324 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003325 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003326 return;
3327 }
3328
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003329 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003330
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003331 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003332 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003333 return;
3334 }
3335
David S. Miller6e157b62012-07-12 00:05:02 -07003336 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003337 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003338 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003339 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003340 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003341 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003342 return;
3343 }
3344
3345 in6_dev = __in6_dev_get(skb->dev);
3346 if (!in6_dev)
3347 return;
3348 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3349 return;
3350
3351 /* RFC2461 8.1:
3352 * The IP source address of the Redirect MUST be the same as the current
3353 * first-hop router for the specified ICMP Destination Address.
3354 */
3355
Alexander Aringf997c552016-06-15 21:20:23 +02003356 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003357 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3358 return;
3359 }
David S. Miller6e157b62012-07-12 00:05:02 -07003360
3361 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003362 if (ndopts.nd_opts_tgt_lladdr) {
3363 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3364 skb->dev);
3365 if (!lladdr) {
3366 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3367 return;
3368 }
3369 }
3370
David S. Miller6e157b62012-07-12 00:05:02 -07003371 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003372 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003373 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3374 return;
3375 }
3376
3377 /* Redirect received -> path was valid.
3378 * Look, redirects are sent only in response to data packets,
3379 * so that this nexthop apparently is reachable. --ANK
3380 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003381 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003382
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003383 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003384 if (!neigh)
3385 return;
3386
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 /*
3388 * We have finally decided to accept it.
3389 */
3390
Alexander Aringf997c552016-06-15 21:20:23 +02003391 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3393 NEIGH_UPDATE_F_OVERRIDE|
3394 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003395 NEIGH_UPDATE_F_ISROUTER)),
3396 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
David Ahern4d85cd02018-04-20 15:37:59 -07003398 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07003399 from = rcu_dereference(rt->from);
Wei Wange873e4b2018-07-21 20:56:32 -07003400 /* This fib6_info_hold() is safe here because we hold reference to rt
3401 * and rt already holds reference to fib6_info.
3402 */
David Ahern8a14e462018-04-23 11:32:07 -07003403 fib6_info_hold(from);
David Ahern4d85cd02018-04-20 15:37:59 -07003404 rcu_read_unlock();
David Ahern8a14e462018-04-23 11:32:07 -07003405
3406 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003407 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 goto out;
3409
3410 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3411 if (on_link)
3412 nrt->rt6i_flags &= ~RTF_GATEWAY;
3413
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003414 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
Wei Wang2b760fc2017-10-06 12:06:03 -07003416 /* No need to remove rt from the exception table if rt is
3417 * a cached route because rt6_insert_exception() will
3418 * takes care of it
3419 */
David Ahern8a14e462018-04-23 11:32:07 -07003420 if (rt6_insert_exception(nrt, from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003421 dst_release_immediate(&nrt->dst);
3422 goto out;
3423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
Changli Gaod8d1f302010-06-10 23:31:35 -07003425 netevent.old = &rt->dst;
3426 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003427 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003428 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003429 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3430
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431out:
David Ahern8a14e462018-04-23 11:32:07 -07003432 fib6_info_release(from);
David S. Millere8599ff2012-07-11 23:43:53 -07003433 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003434}
3435
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003436#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003437static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003438 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003439 const struct in6_addr *gwaddr,
3440 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003441{
David Ahern830218c2016-10-24 10:52:35 -07003442 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3443 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003444 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003445 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003446 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003447
David Ahern830218c2016-10-24 10:52:35 -07003448 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003449 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003450 return NULL;
3451
Wei Wang66f5d6c2017-10-06 12:06:10 -07003452 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003453 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003454 if (!fn)
3455 goto out;
3456
Wei Wang66f5d6c2017-10-06 12:06:10 -07003457 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07003458 if (rt->fib6_nh.nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003459 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003460 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003461 continue;
David Ahern5e670d82018-04-17 17:33:14 -07003462 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003463 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003464 if (!fib6_info_hold_safe(rt))
3465 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003466 break;
3467 }
3468out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003469 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003470 return rt;
3471}
3472
David Ahern8d1c8022018-04-17 17:33:26 -07003473static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003474 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003475 const struct in6_addr *gwaddr,
3476 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003477 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003478{
Thomas Graf86872cb2006-08-22 00:01:08 -07003479 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003480 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003481 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003482 .fc_dst_len = prefixlen,
3483 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3484 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003485 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003486 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003487 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003488 .fc_nlinfo.nlh = NULL,
3489 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003490 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003491
David Ahern830218c2016-10-24 10:52:35 -07003492 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003493 cfg.fc_dst = *prefix;
3494 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003495
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003496 /* We should treat it as a default route if prefix length is 0. */
3497 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003498 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003499
David Ahernacb54e32018-04-17 17:33:22 -07003500 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003501
David Ahern830218c2016-10-24 10:52:35 -07003502 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003503}
3504#endif
3505
David Ahern8d1c8022018-04-17 17:33:26 -07003506struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003507 const struct in6_addr *addr,
3508 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003509{
David Ahern830218c2016-10-24 10:52:35 -07003510 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003511 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003512 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513
David Ahernafb1d4b52018-04-17 17:33:11 -07003514 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003515 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003516 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
Wei Wang66f5d6c2017-10-06 12:06:10 -07003518 rcu_read_lock();
3519 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern5e670d82018-04-17 17:33:14 -07003520 if (dev == rt->fib6_nh.nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003521 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahern5e670d82018-04-17 17:33:14 -07003522 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 break;
3524 }
Wei Wange873e4b2018-07-21 20:56:32 -07003525 if (rt && !fib6_info_hold_safe(rt))
3526 rt = NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003527 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 return rt;
3529}
3530
David Ahern8d1c8022018-04-17 17:33:26 -07003531struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003532 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003533 struct net_device *dev,
3534 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535{
Thomas Graf86872cb2006-08-22 00:01:08 -07003536 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003537 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003538 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003539 .fc_ifindex = dev->ifindex,
3540 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3541 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003542 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003543 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003544 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003545 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003546 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003547 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003549 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
David Ahernacb54e32018-04-17 17:33:22 -07003551 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003552 struct fib6_table *table;
3553
3554 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3555 if (table)
3556 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
David Ahernafb1d4b52018-04-17 17:33:11 -07003559 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560}
3561
David Ahernafb1d4b52018-04-17 17:33:11 -07003562static void __rt6_purge_dflt_routers(struct net *net,
3563 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564{
David Ahern8d1c8022018-04-17 17:33:26 -07003565 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003568 rcu_read_lock();
3569 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003570 struct net_device *dev = fib6_info_nh_dev(rt);
3571 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3572
David Ahern93c2fb22018-04-18 15:38:59 -07003573 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
Wei Wange873e4b2018-07-21 20:56:32 -07003574 (!idev || idev->cnf.accept_ra != 2) &&
3575 fib6_info_hold_safe(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07003576 rcu_read_unlock();
3577 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 goto restart;
3579 }
3580 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003581 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003582
3583 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3584}
3585
3586void rt6_purge_dflt_routers(struct net *net)
3587{
3588 struct fib6_table *table;
3589 struct hlist_head *head;
3590 unsigned int h;
3591
3592 rcu_read_lock();
3593
3594 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3595 head = &net->ipv6.fib_table_hash[h];
3596 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3597 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003598 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003599 }
3600 }
3601
3602 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603}
3604
Daniel Lezcano55786892008-03-04 13:47:47 -08003605static void rtmsg_to_fib6_config(struct net *net,
3606 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003607 struct fib6_config *cfg)
3608{
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003609 *cfg = (struct fib6_config){
3610 .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3611 : RT6_TABLE_MAIN,
3612 .fc_ifindex = rtmsg->rtmsg_ifindex,
3613 .fc_metric = rtmsg->rtmsg_metric,
3614 .fc_expires = rtmsg->rtmsg_info,
3615 .fc_dst_len = rtmsg->rtmsg_dst_len,
3616 .fc_src_len = rtmsg->rtmsg_src_len,
3617 .fc_flags = rtmsg->rtmsg_flags,
3618 .fc_type = rtmsg->rtmsg_type,
Thomas Graf86872cb2006-08-22 00:01:08 -07003619
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003620 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003621
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003622 .fc_dst = rtmsg->rtmsg_dst,
3623 .fc_src = rtmsg->rtmsg_src,
3624 .fc_gateway = rtmsg->rtmsg_gateway,
3625 };
Thomas Graf86872cb2006-08-22 00:01:08 -07003626}
3627
Daniel Lezcano55786892008-03-04 13:47:47 -08003628int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629{
Thomas Graf86872cb2006-08-22 00:01:08 -07003630 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 struct in6_rtmsg rtmsg;
3632 int err;
3633
Ian Morris67ba4152014-08-24 21:53:10 +01003634 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 case SIOCADDRT: /* Add a route */
3636 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003637 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 return -EPERM;
3639 err = copy_from_user(&rtmsg, arg,
3640 sizeof(struct in6_rtmsg));
3641 if (err)
3642 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003643
Daniel Lezcano55786892008-03-04 13:47:47 -08003644 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003645
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 rtnl_lock();
3647 switch (cmd) {
3648 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003649 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 break;
3651 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003652 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 break;
3654 default:
3655 err = -EINVAL;
3656 }
3657 rtnl_unlock();
3658
3659 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661
3662 return -EINVAL;
3663}
3664
3665/*
3666 * Drop the packet on the floor
3667 */
3668
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003669static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003671 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003672 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003673 switch (ipstats_mib_noroutes) {
3674 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003675 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003676 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003677 IP6_INC_STATS(dev_net(dst->dev),
3678 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003679 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003680 break;
3681 }
3682 /* FALLTHROUGH */
3683 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003684 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3685 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003686 break;
3687 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003688 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 kfree_skb(skb);
3690 return 0;
3691}
3692
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003693static int ip6_pkt_discard(struct sk_buff *skb)
3694{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003695 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003696}
3697
Eric W. Biedermanede20592015-10-07 16:48:47 -05003698static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699{
Eric Dumazetadf30902009-06-02 05:19:30 +00003700 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003701 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702}
3703
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003704static int ip6_pkt_prohibit(struct sk_buff *skb)
3705{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003706 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003707}
3708
Eric W. Biedermanede20592015-10-07 16:48:47 -05003709static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003710{
Eric Dumazetadf30902009-06-02 05:19:30 +00003711 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003712 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003713}
3714
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715/*
3716 * Allocate a dst for local (unicast / anycast) address.
3717 */
3718
David Ahern360a9882018-04-18 15:39:00 -07003719struct fib6_info *addrconf_f6i_alloc(struct net *net,
3720 struct inet6_dev *idev,
3721 const struct in6_addr *addr,
3722 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723{
David Ahernca254492015-10-12 11:47:10 -07003724 u32 tb_id;
David Ahern4832c302017-08-17 12:17:20 -07003725 struct net_device *dev = idev->dev;
David Ahern360a9882018-04-18 15:39:00 -07003726 struct fib6_info *f6i;
David Ahern5f02ce242016-09-10 12:09:54 -07003727
David Ahern360a9882018-04-18 15:39:00 -07003728 f6i = fib6_info_alloc(gfp_flags);
3729 if (!f6i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 return ERR_PTR(-ENOMEM);
3731
David Ahernd7e774f2018-11-06 12:51:15 -08003732 f6i->fib6_metrics = ip_fib_metrics_init(net, NULL, 0, NULL);
David Ahern360a9882018-04-18 15:39:00 -07003733 f6i->dst_nocount = true;
David Ahern360a9882018-04-18 15:39:00 -07003734 f6i->dst_host = true;
3735 f6i->fib6_protocol = RTPROT_KERNEL;
3736 f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
David Aherne8478e82018-04-17 17:33:13 -07003737 if (anycast) {
David Ahern360a9882018-04-18 15:39:00 -07003738 f6i->fib6_type = RTN_ANYCAST;
3739 f6i->fib6_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003740 } else {
David Ahern360a9882018-04-18 15:39:00 -07003741 f6i->fib6_type = RTN_LOCAL;
3742 f6i->fib6_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
David Ahern360a9882018-04-18 15:39:00 -07003745 f6i->fib6_nh.nh_gw = *addr;
David Ahern93531c62018-04-17 17:33:25 -07003746 dev_hold(dev);
David Ahern360a9882018-04-18 15:39:00 -07003747 f6i->fib6_nh.nh_dev = dev;
3748 f6i->fib6_dst.addr = *addr;
3749 f6i->fib6_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003750 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
David Ahern360a9882018-04-18 15:39:00 -07003751 f6i->fib6_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752
David Ahern360a9882018-04-18 15:39:00 -07003753 return f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754}
3755
Daniel Walterc3968a82011-04-13 21:10:57 +00003756/* remove deleted ip from prefsrc entries */
3757struct arg_dev_net_ip {
3758 struct net_device *dev;
3759 struct net *net;
3760 struct in6_addr *addr;
3761};
3762
David Ahern8d1c8022018-04-17 17:33:26 -07003763static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003764{
3765 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3766 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3767 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3768
David Ahern5e670d82018-04-17 17:33:14 -07003769 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003770 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003771 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003772 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003773 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003774 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003775 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003776 }
3777 return 0;
3778}
3779
3780void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3781{
3782 struct net *net = dev_net(ifp->idev->dev);
3783 struct arg_dev_net_ip adni = {
3784 .dev = ifp->idev->dev,
3785 .net = net,
3786 .addr = &ifp->addr,
3787 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003788 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003789}
3790
Duan Jiongbe7a0102014-05-15 15:56:14 +08003791#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003792
3793/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003794static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003795{
3796 struct in6_addr *gateway = (struct in6_addr *)arg;
3797
David Ahern93c2fb22018-04-18 15:38:59 -07003798 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahern5e670d82018-04-17 17:33:14 -07003799 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003800 return -1;
3801 }
Wei Wangb16cb452017-10-06 12:06:00 -07003802
3803 /* Further clean up cached routes in exception table.
3804 * This is needed because cached route may have a different
3805 * gateway than its 'parent' in the case of an ip redirect.
3806 */
3807 rt6_exceptions_clean_tohost(rt, gateway);
3808
Duan Jiongbe7a0102014-05-15 15:56:14 +08003809 return 0;
3810}
3811
3812void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3813{
3814 fib6_clean_all(net, fib6_clean_tohost, gateway);
3815}
3816
Ido Schimmel2127d952018-01-07 12:45:03 +02003817struct arg_netdev_event {
3818 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003819 union {
3820 unsigned int nh_flags;
3821 unsigned long event;
3822 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003823};
3824
David Ahern8d1c8022018-04-17 17:33:26 -07003825static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003826{
David Ahern8d1c8022018-04-17 17:33:26 -07003827 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003828 struct fib6_node *fn;
3829
David Ahern93c2fb22018-04-18 15:38:59 -07003830 fn = rcu_dereference_protected(rt->fib6_node,
3831 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003832 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003833 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003834 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003835 if (iter->fib6_metric == rt->fib6_metric &&
David Ahern33bd5ac2018-07-03 14:36:21 -07003836 rt6_qualify_for_ecmp(iter))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003837 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003838 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003839 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003840 }
3841
3842 return NULL;
3843}
3844
David Ahern8d1c8022018-04-17 17:33:26 -07003845static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003846{
David Ahern5e670d82018-04-17 17:33:14 -07003847 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
3848 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Aherndcd1f572018-04-18 15:39:05 -07003849 fib6_ignore_linkdown(rt)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003850 return true;
3851
3852 return false;
3853}
3854
David Ahern8d1c8022018-04-17 17:33:26 -07003855static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003856{
David Ahern8d1c8022018-04-17 17:33:26 -07003857 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003858 int total = 0;
3859
3860 if (!rt6_is_dead(rt))
David Ahern5e670d82018-04-17 17:33:14 -07003861 total += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003862
David Ahern93c2fb22018-04-18 15:38:59 -07003863 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003864 if (!rt6_is_dead(iter))
David Ahern5e670d82018-04-17 17:33:14 -07003865 total += iter->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003866 }
3867
3868 return total;
3869}
3870
David Ahern8d1c8022018-04-17 17:33:26 -07003871static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003872{
3873 int upper_bound = -1;
3874
3875 if (!rt6_is_dead(rt)) {
David Ahern5e670d82018-04-17 17:33:14 -07003876 *weight += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003877 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3878 total) - 1;
3879 }
David Ahern5e670d82018-04-17 17:33:14 -07003880 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003881}
3882
David Ahern8d1c8022018-04-17 17:33:26 -07003883static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003884{
David Ahern8d1c8022018-04-17 17:33:26 -07003885 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003886 int weight = 0;
3887
3888 rt6_upper_bound_set(rt, &weight, total);
3889
David Ahern93c2fb22018-04-18 15:38:59 -07003890 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003891 rt6_upper_bound_set(iter, &weight, total);
3892}
3893
David Ahern8d1c8022018-04-17 17:33:26 -07003894void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003895{
David Ahern8d1c8022018-04-17 17:33:26 -07003896 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003897 int total;
3898
3899 /* In case the entire multipath route was marked for flushing,
3900 * then there is no need to rebalance upon the removal of every
3901 * sibling route.
3902 */
David Ahern93c2fb22018-04-18 15:38:59 -07003903 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003904 return;
3905
3906 /* During lookup routes are evaluated in order, so we need to
3907 * make sure upper bounds are assigned from the first sibling
3908 * onwards.
3909 */
3910 first = rt6_multipath_first_sibling(rt);
3911 if (WARN_ON_ONCE(!first))
3912 return;
3913
3914 total = rt6_multipath_total_weight(first);
3915 rt6_multipath_upper_bound_set(first, total);
3916}
3917
David Ahern8d1c8022018-04-17 17:33:26 -07003918static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003919{
3920 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003921 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003922
David Ahern421842e2018-04-17 17:33:18 -07003923 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
David Ahern5e670d82018-04-17 17:33:14 -07003924 rt->fib6_nh.nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003925 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003926 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003927 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003928
3929 return 0;
3930}
3931
3932void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3933{
3934 struct arg_netdev_event arg = {
3935 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003936 {
3937 .nh_flags = nh_flags,
3938 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003939 };
3940
3941 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3942 arg.nh_flags |= RTNH_F_LINKDOWN;
3943
3944 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3945}
3946
David Ahern8d1c8022018-04-17 17:33:26 -07003947static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003948 const struct net_device *dev)
3949{
David Ahern8d1c8022018-04-17 17:33:26 -07003950 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003951
David Ahern5e670d82018-04-17 17:33:14 -07003952 if (rt->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003953 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07003954 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003955 if (iter->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003956 return true;
3957
3958 return false;
3959}
3960
David Ahern8d1c8022018-04-17 17:33:26 -07003961static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003962{
David Ahern8d1c8022018-04-17 17:33:26 -07003963 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003964
3965 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07003966 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003967 iter->should_flush = 1;
3968}
3969
David Ahern8d1c8022018-04-17 17:33:26 -07003970static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003971 const struct net_device *down_dev)
3972{
David Ahern8d1c8022018-04-17 17:33:26 -07003973 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003974 unsigned int dead = 0;
3975
David Ahern5e670d82018-04-17 17:33:14 -07003976 if (rt->fib6_nh.nh_dev == down_dev ||
3977 rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003978 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07003979 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003980 if (iter->fib6_nh.nh_dev == down_dev ||
3981 iter->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003982 dead++;
3983
3984 return dead;
3985}
3986
David Ahern8d1c8022018-04-17 17:33:26 -07003987static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003988 const struct net_device *dev,
3989 unsigned int nh_flags)
3990{
David Ahern8d1c8022018-04-17 17:33:26 -07003991 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003992
David Ahern5e670d82018-04-17 17:33:14 -07003993 if (rt->fib6_nh.nh_dev == dev)
3994 rt->fib6_nh.nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07003995 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003996 if (iter->fib6_nh.nh_dev == dev)
3997 iter->fib6_nh.nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003998}
3999
David Aherna1a22c12017-01-18 07:40:36 -08004000/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07004001static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004003 const struct arg_netdev_event *arg = p_arg;
4004 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07004005 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004006
David Ahern421842e2018-04-17 17:33:18 -07004007 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004008 return 0;
4009
4010 switch (arg->event) {
4011 case NETDEV_UNREGISTER:
David Ahern5e670d82018-04-17 17:33:14 -07004012 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004013 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02004014 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004015 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004016 if (!rt->fib6_nsiblings)
David Ahern5e670d82018-04-17 17:33:14 -07004017 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004018 if (rt6_multipath_uses_dev(rt, dev)) {
4019 unsigned int count;
4020
4021 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004022 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004023 rt6_multipath_flush(rt);
4024 return -1;
4025 }
4026 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4027 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004028 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004029 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004030 }
4031 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004032 case NETDEV_CHANGE:
David Ahern5e670d82018-04-17 17:33:14 -07004033 if (rt->fib6_nh.nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004034 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004035 break;
David Ahern5e670d82018-04-17 17:33:14 -07004036 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004037 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004038 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004039 }
David S. Millerc159d302011-12-26 15:24:36 -05004040
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 return 0;
4042}
4043
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004044void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004046 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004047 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004048 {
4049 .event = event,
4050 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004051 };
David Ahern7c6bb7d2018-10-11 20:17:21 -07004052 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004053
David Ahern7c6bb7d2018-10-11 20:17:21 -07004054 if (net->ipv6.sysctl.skip_notify_on_dev_down)
4055 fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
4056 else
4057 fib6_clean_all(net, fib6_ifdown, &arg);
Ido Schimmel4c981e22018-01-07 12:45:04 +02004058}
4059
4060void rt6_disable_ip(struct net_device *dev, unsigned long event)
4061{
4062 rt6_sync_down_dev(dev, event);
4063 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4064 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065}
4066
Eric Dumazet95c96172012-04-15 05:58:06 +00004067struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004069 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070};
4071
David Ahern8d1c8022018-04-17 17:33:26 -07004072static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073{
4074 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4075 struct inet6_dev *idev;
4076
4077 /* In IPv6 pmtu discovery is not optional,
4078 so that RTAX_MTU lock cannot disable it.
4079 We still use this lock to block changes
4080 caused by addrconf/ndisc.
4081 */
4082
4083 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004084 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 return 0;
4086
4087 /* For administrative MTU increase, there is no way to discover
4088 IPv6 PMTU increase, so PMTU increase should be updated here.
4089 Since RFC 1981 doesn't include administrative MTU increase
4090 update PMTU increase is a MUST. (i.e. jumbo frame)
4091 */
David Ahern5e670d82018-04-17 17:33:14 -07004092 if (rt->fib6_nh.nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004093 !fib6_metric_locked(rt, RTAX_MTU)) {
4094 u32 mtu = rt->fib6_pmtu;
4095
4096 if (mtu >= arg->mtu ||
4097 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4098 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4099
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004100 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004101 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004102 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 return 0;
4105}
4106
Eric Dumazet95c96172012-04-15 05:58:06 +00004107void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108{
Thomas Grafc71099a2006-08-04 23:20:06 -07004109 struct rt6_mtu_change_arg arg = {
4110 .dev = dev,
4111 .mtu = mtu,
4112 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
Li RongQing0c3584d2013-12-27 16:32:38 +08004114 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115}
4116
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004117static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004118 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004119 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004120 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004121 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004122 [RTA_PRIORITY] = { .type = NLA_U32 },
4123 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004124 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004125 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004126 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4127 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004128 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004129 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004130 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004131 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004132 [RTA_IP_PROTO] = { .type = NLA_U8 },
4133 [RTA_SPORT] = { .type = NLA_U16 },
4134 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004135};
4136
4137static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004138 struct fib6_config *cfg,
4139 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140{
Thomas Graf86872cb2006-08-22 00:01:08 -07004141 struct rtmsg *rtm;
4142 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004143 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004144 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145
Johannes Bergfceb6432017-04-12 14:34:07 +02004146 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Aherndac9c972018-10-07 20:16:24 -07004147 extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004148 if (err < 0)
4149 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Thomas Graf86872cb2006-08-22 00:01:08 -07004151 err = -EINVAL;
4152 rtm = nlmsg_data(nlh);
Thomas Graf86872cb2006-08-22 00:01:08 -07004153
Maciej Żenczykowski84db8402018-09-29 23:44:53 -07004154 *cfg = (struct fib6_config){
4155 .fc_table = rtm->rtm_table,
4156 .fc_dst_len = rtm->rtm_dst_len,
4157 .fc_src_len = rtm->rtm_src_len,
4158 .fc_flags = RTF_UP,
4159 .fc_protocol = rtm->rtm_protocol,
4160 .fc_type = rtm->rtm_type,
4161
4162 .fc_nlinfo.portid = NETLINK_CB(skb).portid,
4163 .fc_nlinfo.nlh = nlh,
4164 .fc_nlinfo.nl_net = sock_net(skb->sk),
4165 };
Thomas Graf86872cb2006-08-22 00:01:08 -07004166
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004167 if (rtm->rtm_type == RTN_UNREACHABLE ||
4168 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004169 rtm->rtm_type == RTN_PROHIBIT ||
4170 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004171 cfg->fc_flags |= RTF_REJECT;
4172
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004173 if (rtm->rtm_type == RTN_LOCAL)
4174 cfg->fc_flags |= RTF_LOCAL;
4175
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004176 if (rtm->rtm_flags & RTM_F_CLONED)
4177 cfg->fc_flags |= RTF_CACHE;
4178
David Ahernfc1e64e2018-01-25 16:55:09 -08004179 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4180
Thomas Graf86872cb2006-08-22 00:01:08 -07004181 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004182 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004183 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004185
4186 if (tb[RTA_DST]) {
4187 int plen = (rtm->rtm_dst_len + 7) >> 3;
4188
4189 if (nla_len(tb[RTA_DST]) < plen)
4190 goto errout;
4191
4192 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004194
4195 if (tb[RTA_SRC]) {
4196 int plen = (rtm->rtm_src_len + 7) >> 3;
4197
4198 if (nla_len(tb[RTA_SRC]) < plen)
4199 goto errout;
4200
4201 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004203
Daniel Walterc3968a82011-04-13 21:10:57 +00004204 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004205 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004206
Thomas Graf86872cb2006-08-22 00:01:08 -07004207 if (tb[RTA_OIF])
4208 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4209
4210 if (tb[RTA_PRIORITY])
4211 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4212
4213 if (tb[RTA_METRICS]) {
4214 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4215 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004217
4218 if (tb[RTA_TABLE])
4219 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4220
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004221 if (tb[RTA_MULTIPATH]) {
4222 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4223 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004224
4225 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004226 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004227 if (err < 0)
4228 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004229 }
4230
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004231 if (tb[RTA_PREF]) {
4232 pref = nla_get_u8(tb[RTA_PREF]);
4233 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4234 pref != ICMPV6_ROUTER_PREF_HIGH)
4235 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4236 cfg->fc_flags |= RTF_PREF(pref);
4237 }
4238
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004239 if (tb[RTA_ENCAP])
4240 cfg->fc_encap = tb[RTA_ENCAP];
4241
David Ahern9ed59592017-01-17 14:57:36 -08004242 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004243 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4244
David Ahernc255bd62017-05-27 16:19:27 -06004245 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004246 if (err < 0)
4247 goto errout;
4248 }
4249
Xin Long32bc2012015-12-16 17:50:11 +08004250 if (tb[RTA_EXPIRES]) {
4251 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4252
4253 if (addrconf_finite_timeout(timeout)) {
4254 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4255 cfg->fc_flags |= RTF_EXPIRES;
4256 }
4257 }
4258
Thomas Graf86872cb2006-08-22 00:01:08 -07004259 err = 0;
4260errout:
4261 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262}
4263
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004264struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004265 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004266 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004267 struct list_head next;
4268};
4269
David Ahernd4ead6b2018-04-17 17:33:16 -07004270static int ip6_route_info_append(struct net *net,
4271 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004272 struct fib6_info *rt,
4273 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004274{
4275 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004276 int err = -EEXIST;
4277
4278 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004279 /* check if fib6_info already exists */
4280 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004281 return err;
4282 }
4283
4284 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4285 if (!nh)
4286 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004287 nh->fib6_info = rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004288 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4289 list_add_tail(&nh->next, rt6_nh_list);
4290
4291 return 0;
4292}
4293
David Ahern8d1c8022018-04-17 17:33:26 -07004294static void ip6_route_mpath_notify(struct fib6_info *rt,
4295 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004296 struct nl_info *info,
4297 __u16 nlflags)
4298{
4299 /* if this is an APPEND route, then rt points to the first route
4300 * inserted and rt_last points to last route inserted. Userspace
4301 * wants a consistent dump of the route which starts at the first
4302 * nexthop. Since sibling routes are always added at the end of
4303 * the list, find the first sibling of the last route appended
4304 */
David Ahern93c2fb22018-04-18 15:38:59 -07004305 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4306 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004307 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004308 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004309 }
4310
4311 if (rt)
4312 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4313}
4314
David Ahern333c4302017-05-21 10:12:04 -06004315static int ip6_route_multipath_add(struct fib6_config *cfg,
4316 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004317{
David Ahern8d1c8022018-04-17 17:33:26 -07004318 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004319 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004320 struct fib6_config r_cfg;
4321 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004322 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004323 struct rt6_nh *err_nh;
4324 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004325 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004326 int remaining;
4327 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004328 int err = 1;
4329 int nhn = 0;
4330 int replace = (cfg->fc_nlinfo.nlh &&
4331 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4332 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004333
David Ahern3b1137f2017-02-02 12:37:10 -08004334 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4335 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4336 nlflags |= NLM_F_APPEND;
4337
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004338 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004339 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004340
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004341 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004342 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004343 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004344 while (rtnh_ok(rtnh, remaining)) {
4345 memcpy(&r_cfg, cfg, sizeof(*cfg));
4346 if (rtnh->rtnh_ifindex)
4347 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4348
4349 attrlen = rtnh_attrlen(rtnh);
4350 if (attrlen > 0) {
4351 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4352
4353 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4354 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004355 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004356 r_cfg.fc_flags |= RTF_GATEWAY;
4357 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004358 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4359 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4360 if (nla)
4361 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004362 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004363
David Ahern68e2ffd2018-03-20 10:06:59 -07004364 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004365 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004366 if (IS_ERR(rt)) {
4367 err = PTR_ERR(rt);
4368 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004369 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004370 }
David Ahernb5d2d752018-07-15 09:35:19 -07004371 if (!rt6_qualify_for_ecmp(rt)) {
4372 err = -EINVAL;
4373 NL_SET_ERR_MSG(extack,
4374 "Device only routes can not be added for IPv6 using the multipath API.");
4375 fib6_info_release(rt);
4376 goto cleanup;
4377 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004378
David Ahern5e670d82018-04-17 17:33:14 -07004379 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004380
David Ahernd4ead6b2018-04-17 17:33:16 -07004381 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4382 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004383 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004384 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004385 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004386 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004387
4388 rtnh = rtnh_next(rtnh, &remaining);
4389 }
4390
David Ahern3b1137f2017-02-02 12:37:10 -08004391 /* for add and replace send one notification with all nexthops.
4392 * Skip the notification in fib6_add_rt2node and send one with
4393 * the full route when done
4394 */
4395 info->skip_notify = 1;
4396
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004397 err_nh = NULL;
4398 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004399 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4400 fib6_info_release(nh->fib6_info);
David Ahern3b1137f2017-02-02 12:37:10 -08004401
David Ahernf7225172018-06-04 13:41:42 -07004402 if (!err) {
4403 /* save reference to last route successfully inserted */
4404 rt_last = nh->fib6_info;
4405
4406 /* save reference to first route for notification */
4407 if (!rt_notif)
4408 rt_notif = nh->fib6_info;
4409 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004410
David Ahern8d1c8022018-04-17 17:33:26 -07004411 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4412 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004413 if (err) {
4414 if (replace && nhn)
Jakub Kicinskia5a82d82019-01-14 10:52:45 -08004415 NL_SET_ERR_MSG_MOD(extack,
4416 "multipath route replace failed (check consistency of installed routes)");
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004417 err_nh = nh;
4418 goto add_errout;
4419 }
4420
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004421 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004422 * these flags after the first nexthop: if there is a collision,
4423 * we have already failed to add the first nexthop:
4424 * fib6_add_rt2node() has rejected it; when replacing, old
4425 * nexthops have been replaced by first new, the rest should
4426 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004427 */
Michal Kubeček27596472015-05-18 20:54:00 +02004428 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4429 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004430 nhn++;
4431 }
4432
David Ahern3b1137f2017-02-02 12:37:10 -08004433 /* success ... tell user about new route */
4434 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004435 goto cleanup;
4436
4437add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004438 /* send notification for routes that were added so that
4439 * the delete notifications sent by ip6_route_del are
4440 * coherent
4441 */
4442 if (rt_notif)
4443 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4444
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004445 /* Delete routes that were already added */
4446 list_for_each_entry(nh, &rt6_nh_list, next) {
4447 if (err_nh == nh)
4448 break;
David Ahern333c4302017-05-21 10:12:04 -06004449 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004450 }
4451
4452cleanup:
4453 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004454 if (nh->fib6_info)
4455 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004456 list_del(&nh->next);
4457 kfree(nh);
4458 }
4459
4460 return err;
4461}
4462
David Ahern333c4302017-05-21 10:12:04 -06004463static int ip6_route_multipath_del(struct fib6_config *cfg,
4464 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004465{
4466 struct fib6_config r_cfg;
4467 struct rtnexthop *rtnh;
4468 int remaining;
4469 int attrlen;
4470 int err = 1, last_err = 0;
4471
4472 remaining = cfg->fc_mp_len;
4473 rtnh = (struct rtnexthop *)cfg->fc_mp;
4474
4475 /* Parse a Multipath Entry */
4476 while (rtnh_ok(rtnh, remaining)) {
4477 memcpy(&r_cfg, cfg, sizeof(*cfg));
4478 if (rtnh->rtnh_ifindex)
4479 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4480
4481 attrlen = rtnh_attrlen(rtnh);
4482 if (attrlen > 0) {
4483 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4484
4485 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4486 if (nla) {
4487 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4488 r_cfg.fc_flags |= RTF_GATEWAY;
4489 }
4490 }
David Ahern333c4302017-05-21 10:12:04 -06004491 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004492 if (err)
4493 last_err = err;
4494
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004495 rtnh = rtnh_next(rtnh, &remaining);
4496 }
4497
4498 return last_err;
4499}
4500
David Ahernc21ef3e2017-04-16 09:48:24 -07004501static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4502 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503{
Thomas Graf86872cb2006-08-22 00:01:08 -07004504 struct fib6_config cfg;
4505 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506
David Ahern333c4302017-05-21 10:12:04 -06004507 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004508 if (err < 0)
4509 return err;
4510
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004511 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004512 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004513 else {
4514 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004515 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517}
4518
David Ahernc21ef3e2017-04-16 09:48:24 -07004519static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4520 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521{
Thomas Graf86872cb2006-08-22 00:01:08 -07004522 struct fib6_config cfg;
4523 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
David Ahern333c4302017-05-21 10:12:04 -06004525 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004526 if (err < 0)
4527 return err;
4528
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004529 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004530 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004531 else
David Ahernacb54e32018-04-17 17:33:22 -07004532 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533}
4534
David Ahern8d1c8022018-04-17 17:33:26 -07004535static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004536{
David Ahernbeb1afac52017-02-02 12:37:09 -08004537 int nexthop_len = 0;
4538
David Ahern93c2fb22018-04-18 15:38:59 -07004539 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004540 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4541 + NLA_ALIGN(sizeof(struct rtnexthop))
4542 + nla_total_size(16) /* RTA_GATEWAY */
David Ahern5e670d82018-04-17 17:33:14 -07004543 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
David Ahernbeb1afac52017-02-02 12:37:09 -08004544
David Ahern93c2fb22018-04-18 15:38:59 -07004545 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004546 }
4547
Thomas Graf339bf982006-11-10 14:10:15 -08004548 return NLMSG_ALIGN(sizeof(struct rtmsg))
4549 + nla_total_size(16) /* RTA_SRC */
4550 + nla_total_size(16) /* RTA_DST */
4551 + nla_total_size(16) /* RTA_GATEWAY */
4552 + nla_total_size(16) /* RTA_PREFSRC */
4553 + nla_total_size(4) /* RTA_TABLE */
4554 + nla_total_size(4) /* RTA_IIF */
4555 + nla_total_size(4) /* RTA_OIF */
4556 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004557 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004558 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004559 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004560 + nla_total_size(1) /* RTA_PREF */
David Ahern5e670d82018-04-17 17:33:14 -07004561 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate)
David Ahernbeb1afac52017-02-02 12:37:09 -08004562 + nexthop_len;
4563}
4564
David Ahern8d1c8022018-04-17 17:33:26 -07004565static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004566 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004567{
David Ahern5e670d82018-04-17 17:33:14 -07004568 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004569 *flags |= RTNH_F_DEAD;
4570
David Ahern5e670d82018-04-17 17:33:14 -07004571 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004572 *flags |= RTNH_F_LINKDOWN;
David Aherndcd1f572018-04-18 15:39:05 -07004573
4574 rcu_read_lock();
4575 if (fib6_ignore_linkdown(rt))
David Ahernbeb1afac52017-02-02 12:37:09 -08004576 *flags |= RTNH_F_DEAD;
David Aherndcd1f572018-04-18 15:39:05 -07004577 rcu_read_unlock();
David Ahernbeb1afac52017-02-02 12:37:09 -08004578 }
4579
David Ahern93c2fb22018-04-18 15:38:59 -07004580 if (rt->fib6_flags & RTF_GATEWAY) {
David Ahern5e670d82018-04-17 17:33:14 -07004581 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004582 goto nla_put_failure;
4583 }
4584
David Ahern5e670d82018-04-17 17:33:14 -07004585 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK);
4586 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004587 *flags |= RTNH_F_OFFLOAD;
4588
David Ahern5be083c2017-03-06 15:57:31 -08004589 /* not needed for multipath encoding b/c it has a rtnexthop struct */
David Ahern5e670d82018-04-17 17:33:14 -07004590 if (!skip_oif && rt->fib6_nh.nh_dev &&
4591 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex))
David Ahernbeb1afac52017-02-02 12:37:09 -08004592 goto nla_put_failure;
4593
David Ahern5e670d82018-04-17 17:33:14 -07004594 if (rt->fib6_nh.nh_lwtstate &&
4595 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004596 goto nla_put_failure;
4597
4598 return 0;
4599
4600nla_put_failure:
4601 return -EMSGSIZE;
4602}
4603
David Ahern5be083c2017-03-06 15:57:31 -08004604/* add multipath next hop */
David Ahern8d1c8022018-04-17 17:33:26 -07004605static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt)
David Ahernbeb1afac52017-02-02 12:37:09 -08004606{
David Ahern5e670d82018-04-17 17:33:14 -07004607 const struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernbeb1afac52017-02-02 12:37:09 -08004608 struct rtnexthop *rtnh;
4609 unsigned int flags = 0;
4610
4611 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4612 if (!rtnh)
4613 goto nla_put_failure;
4614
David Ahern5e670d82018-04-17 17:33:14 -07004615 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1;
4616 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
David Ahernbeb1afac52017-02-02 12:37:09 -08004617
David Ahern5be083c2017-03-06 15:57:31 -08004618 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004619 goto nla_put_failure;
4620
4621 rtnh->rtnh_flags = flags;
4622
4623 /* length of rtnetlink header + attributes */
4624 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4625
4626 return 0;
4627
4628nla_put_failure:
4629 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004630}
4631
David Ahernd4ead6b2018-04-17 17:33:16 -07004632static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004633 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004634 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004635 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004636 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637{
Xin Long22d0bd82018-09-11 14:33:58 +08004638 struct rt6_info *rt6 = (struct rt6_info *)dst;
4639 struct rt6key *rt6_dst, *rt6_src;
4640 u32 *pmetrics, table, rt6_flags;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004641 struct nlmsghdr *nlh;
Xin Long22d0bd82018-09-11 14:33:58 +08004642 struct rtmsg *rtm;
David Ahernd4ead6b2018-04-17 17:33:16 -07004643 long expires = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644
Eric W. Biederman15e47302012-09-07 20:12:54 +00004645 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004646 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004647 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004648
Xin Long22d0bd82018-09-11 14:33:58 +08004649 if (rt6) {
4650 rt6_dst = &rt6->rt6i_dst;
4651 rt6_src = &rt6->rt6i_src;
4652 rt6_flags = rt6->rt6i_flags;
4653 } else {
4654 rt6_dst = &rt->fib6_dst;
4655 rt6_src = &rt->fib6_src;
4656 rt6_flags = rt->fib6_flags;
4657 }
4658
Thomas Graf2d7202b2006-08-22 00:01:27 -07004659 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 rtm->rtm_family = AF_INET6;
Xin Long22d0bd82018-09-11 14:33:58 +08004661 rtm->rtm_dst_len = rt6_dst->plen;
4662 rtm->rtm_src_len = rt6_src->plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004664 if (rt->fib6_table)
4665 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004666 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004667 table = RT6_TABLE_UNSPEC;
4668 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04004669 if (nla_put_u32(skb, RTA_TABLE, table))
4670 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004671
4672 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 rtm->rtm_flags = 0;
4674 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004675 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
Xin Long22d0bd82018-09-11 14:33:58 +08004677 if (rt6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 rtm->rtm_flags |= RTM_F_CLONED;
4679
David Ahernd4ead6b2018-04-17 17:33:16 -07004680 if (dest) {
4681 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004682 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004683 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 } else if (rtm->rtm_dst_len)
Xin Long22d0bd82018-09-11 14:33:58 +08004685 if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004686 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687#ifdef CONFIG_IPV6_SUBTREES
4688 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004689 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004690 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004691 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004692 } else if (rtm->rtm_src_len &&
Xin Long22d0bd82018-09-11 14:33:58 +08004693 nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004694 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004696 if (iif) {
4697#ifdef CONFIG_IPV6_MROUTE
Xin Long22d0bd82018-09-11 14:33:58 +08004698 if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004699 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004700
David Ahernfd61c6b2017-01-17 15:51:07 -08004701 if (err == 0)
4702 return 0;
4703 if (err < 0)
4704 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004705 } else
4706#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004707 if (nla_put_u32(skb, RTA_IIF, iif))
4708 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004709 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004711 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004712 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004713 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004715
David Ahern93c2fb22018-04-18 15:38:59 -07004716 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004717 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004718 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004719 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004720 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004721 }
4722
David Ahernd4ead6b2018-04-17 17:33:16 -07004723 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4724 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004725 goto nla_put_failure;
4726
David Ahern93c2fb22018-04-18 15:38:59 -07004727 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004728 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004729
David Ahernbeb1afac52017-02-02 12:37:09 -08004730 /* For multipath routes, walk the siblings list and add
4731 * each as a nexthop within RTA_MULTIPATH.
4732 */
Xin Long22d0bd82018-09-11 14:33:58 +08004733 if (rt6) {
4734 if (rt6_flags & RTF_GATEWAY &&
4735 nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
4736 goto nla_put_failure;
4737
4738 if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
4739 goto nla_put_failure;
4740 } else if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004741 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004742 struct nlattr *mp;
4743
4744 mp = nla_nest_start(skb, RTA_MULTIPATH);
4745 if (!mp)
4746 goto nla_put_failure;
4747
4748 if (rt6_add_nexthop(skb, rt) < 0)
4749 goto nla_put_failure;
4750
4751 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004752 &rt->fib6_siblings, fib6_siblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004753 if (rt6_add_nexthop(skb, sibling) < 0)
4754 goto nla_put_failure;
4755 }
4756
4757 nla_nest_end(skb, mp);
4758 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004759 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004760 goto nla_put_failure;
4761 }
4762
Xin Long22d0bd82018-09-11 14:33:58 +08004763 if (rt6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004764 expires = dst ? dst->expires : rt->expires;
4765 expires -= jiffies;
4766 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004767
David Ahernd4ead6b2018-04-17 17:33:16 -07004768 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004769 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Xin Long22d0bd82018-09-11 14:33:58 +08004771 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004772 goto nla_put_failure;
4773
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004774
Johannes Berg053c0952015-01-16 22:09:00 +01004775 nlmsg_end(skb, nlh);
4776 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004777
4778nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004779 nlmsg_cancel(skb, nlh);
4780 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781}
4782
David Ahern13e38902018-10-15 18:56:44 -07004783static bool fib6_info_uses_dev(const struct fib6_info *f6i,
4784 const struct net_device *dev)
4785{
4786 if (f6i->fib6_nh.nh_dev == dev)
4787 return true;
4788
4789 if (f6i->fib6_nsiblings) {
4790 struct fib6_info *sibling, *next_sibling;
4791
4792 list_for_each_entry_safe(sibling, next_sibling,
4793 &f6i->fib6_siblings, fib6_siblings) {
4794 if (sibling->fib6_nh.nh_dev == dev)
4795 return true;
4796 }
4797 }
4798
4799 return false;
4800}
4801
David Ahern8d1c8022018-04-17 17:33:26 -07004802int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803{
4804 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern13e38902018-10-15 18:56:44 -07004805 struct fib_dump_filter *filter = &arg->filter;
4806 unsigned int flags = NLM_F_MULTI;
David Ahern1f17e2f2017-01-26 13:54:08 -08004807 struct net *net = arg->net;
4808
David Ahern421842e2018-04-17 17:33:18 -07004809 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004810 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811
David Ahern13e38902018-10-15 18:56:44 -07004812 if ((filter->flags & RTM_F_PREFIX) &&
4813 !(rt->fib6_flags & RTF_PREFIX_RT)) {
4814 /* success since this is not a prefix route */
4815 return 1;
4816 }
4817 if (filter->filter_set) {
4818 if ((filter->rt_type && rt->fib6_type != filter->rt_type) ||
4819 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) ||
4820 (filter->protocol && rt->fib6_protocol != filter->protocol)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004821 return 1;
4822 }
David Ahern13e38902018-10-15 18:56:44 -07004823 flags |= NLM_F_DUMP_FILTERED;
David Ahernf8cfe2c2017-01-17 15:51:08 -08004824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825
David Ahernd4ead6b2018-04-17 17:33:16 -07004826 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4827 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
David Ahern13e38902018-10-15 18:56:44 -07004828 arg->cb->nlh->nlmsg_seq, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829}
4830
David Ahernc21ef3e2017-04-16 09:48:24 -07004831static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4832 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004834 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004835 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004836 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004837 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004838 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004840 struct sk_buff *skb;
4841 struct rtmsg *rtm;
Maciej Żenczykowski744486d2018-09-29 23:44:54 -07004842 struct flowi6 fl6 = {};
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004843 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004844
Johannes Bergfceb6432017-04-12 14:34:07 +02004845 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07004846 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004847 if (err < 0)
4848 goto errout;
4849
4850 err = -EINVAL;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004851 rtm = nlmsg_data(nlh);
4852 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004853 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004854
4855 if (tb[RTA_SRC]) {
4856 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4857 goto errout;
4858
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004859 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004860 }
4861
4862 if (tb[RTA_DST]) {
4863 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4864 goto errout;
4865
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004866 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004867 }
4868
4869 if (tb[RTA_IIF])
4870 iif = nla_get_u32(tb[RTA_IIF]);
4871
4872 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004873 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004874
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004875 if (tb[RTA_MARK])
4876 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4877
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004878 if (tb[RTA_UID])
4879 fl6.flowi6_uid = make_kuid(current_user_ns(),
4880 nla_get_u32(tb[RTA_UID]));
4881 else
4882 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4883
Roopa Prabhueacb9382018-05-22 14:03:28 -07004884 if (tb[RTA_SPORT])
4885 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
4886
4887 if (tb[RTA_DPORT])
4888 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
4889
4890 if (tb[RTA_IP_PROTO]) {
4891 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
4892 &fl6.flowi6_proto, extack);
4893 if (err)
4894 goto errout;
4895 }
4896
Thomas Grafab364a62006-08-22 00:01:47 -07004897 if (iif) {
4898 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004899 int flags = 0;
4900
Florian Westphal121622d2017-08-15 16:34:42 +02004901 rcu_read_lock();
4902
4903 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004904 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004905 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004906 err = -ENODEV;
4907 goto errout;
4908 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004909
4910 fl6.flowi6_iif = iif;
4911
4912 if (!ipv6_addr_any(&fl6.saddr))
4913 flags |= RT6_LOOKUP_F_HAS_SADDR;
4914
David Ahernb75cc8f2018-03-02 08:32:17 -08004915 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004916
4917 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004918 } else {
4919 fl6.flowi6_oif = oif;
4920
Ido Schimmel58acfd72017-12-20 12:28:25 +02004921 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004922 }
4923
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004924
4925 rt = container_of(dst, struct rt6_info, dst);
4926 if (rt->dst.error) {
4927 err = rt->dst.error;
4928 ip6_rt_put(rt);
4929 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931
WANG Cong9d6acb32017-03-01 20:48:39 -08004932 if (rt == net->ipv6.ip6_null_entry) {
4933 err = rt->dst.error;
4934 ip6_rt_put(rt);
4935 goto errout;
4936 }
4937
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004939 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004940 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07004941 err = -ENOBUFS;
4942 goto errout;
4943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944
Changli Gaod8d1f302010-06-10 23:31:35 -07004945 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07004946
4947 rcu_read_lock();
4948 from = rcu_dereference(rt->from);
4949
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004950 if (fibmatch)
David Aherna68886a2018-04-20 15:38:02 -07004951 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004952 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
4953 nlh->nlmsg_seq, 0);
4954 else
David Aherna68886a2018-04-20 15:38:02 -07004955 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
4956 &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07004957 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
4958 0);
David Aherna68886a2018-04-20 15:38:02 -07004959 rcu_read_unlock();
4960
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07004962 kfree_skb(skb);
4963 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 }
4965
Eric W. Biederman15e47302012-09-07 20:12:54 +00004966 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07004967errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969}
4970
David Ahern8d1c8022018-04-17 17:33:26 -07004971void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07004972 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973{
4974 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08004975 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004976 u32 seq;
4977 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004979 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05004980 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07004981
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004982 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05004983 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07004984 goto errout;
4985
David Ahernd4ead6b2018-04-17 17:33:16 -07004986 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
4987 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08004988 if (err < 0) {
4989 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
4990 WARN_ON(err == -EMSGSIZE);
4991 kfree_skb(skb);
4992 goto errout;
4993 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00004994 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08004995 info->nlh, gfp_any());
4996 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07004997errout:
4998 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08004999 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000}
5001
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005002static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00005003 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005004{
Jiri Pirko351638e2013-05-28 01:30:21 +00005005 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09005006 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005007
WANG Cong242d3a42017-05-08 10:12:13 -07005008 if (!(dev->flags & IFF_LOOPBACK))
5009 return NOTIFY_OK;
5010
5011 if (event == NETDEV_REGISTER) {
David Ahern421842e2018-04-17 17:33:18 -07005012 net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07005013 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005014 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
5015#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07005016 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005017 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07005018 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005019 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
5020#endif
WANG Cong76da0702017-06-20 11:42:27 -07005021 } else if (event == NETDEV_UNREGISTER &&
5022 dev->reg_state != NETREG_UNREGISTERED) {
5023 /* NETDEV_UNREGISTER could be fired for multiple times by
5024 * netdev_wait_allrefs(). Make sure we only call this once.
5025 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07005026 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005027#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005028 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5029 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005030#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005031 }
5032
5033 return NOTIFY_OK;
5034}
5035
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036/*
5037 * /proc
5038 */
5039
5040#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5042{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005043 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005045 net->ipv6.rt6_stats->fib_nodes,
5046 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005047 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005048 net->ipv6.rt6_stats->fib_rt_entries,
5049 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005050 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005051 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052
5053 return 0;
5054}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055#endif /* CONFIG_PROC_FS */
5056
5057#ifdef CONFIG_SYSCTL
5058
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005060int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 void __user *buffer, size_t *lenp, loff_t *ppos)
5062{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005063 struct net *net;
5064 int delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005065 int ret;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005066 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005068
5069 net = (struct net *)ctl->extra1;
5070 delay = net->ipv6.sysctl.flush_delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005071 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
5072 if (ret)
5073 return ret;
5074
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005075 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005076 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077}
5078
David Ahern7c6bb7d2018-10-11 20:17:21 -07005079static int zero;
5080static int one = 1;
5081
David Aherned792e22018-10-08 14:06:34 -07005082static struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005083 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005085 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005087 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005088 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 },
5090 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005092 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 .maxlen = sizeof(int),
5094 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005095 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 },
5097 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005099 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 .maxlen = sizeof(int),
5101 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005102 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 },
5104 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005106 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 .maxlen = sizeof(int),
5108 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005109 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 },
5111 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005113 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 .maxlen = sizeof(int),
5115 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005116 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 },
5118 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005120 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 .maxlen = sizeof(int),
5122 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005123 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 },
5125 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005127 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 .maxlen = sizeof(int),
5129 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005130 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 },
5132 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005134 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 .maxlen = sizeof(int),
5136 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005137 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 },
5139 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005141 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 .maxlen = sizeof(int),
5143 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005144 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 },
5146 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005148 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 .maxlen = sizeof(int),
5150 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005151 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 },
David Ahern7c6bb7d2018-10-11 20:17:21 -07005153 {
5154 .procname = "skip_notify_on_dev_down",
5155 .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
5156 .maxlen = sizeof(int),
5157 .mode = 0644,
5158 .proc_handler = proc_dointvec,
5159 .extra1 = &zero,
5160 .extra2 = &one,
5161 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005162 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163};
5164
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005165struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005166{
5167 struct ctl_table *table;
5168
5169 table = kmemdup(ipv6_route_table_template,
5170 sizeof(ipv6_route_table_template),
5171 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005172
5173 if (table) {
5174 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005175 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005176 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005177 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5178 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5179 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5180 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5181 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5182 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5183 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005184 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005185 table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005186
5187 /* Don't export sysctls to unprivileged users */
5188 if (net->user_ns != &init_user_ns)
5189 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005190 }
5191
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005192 return table;
5193}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194#endif
5195
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005196static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005197{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005198 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005199
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005200 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5201 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005202
Eric Dumazetfc66f952010-10-08 06:37:34 +00005203 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5204 goto out_ip6_dst_ops;
5205
David Ahern421842e2018-04-17 17:33:18 -07005206 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5207 sizeof(*net->ipv6.fib6_null_entry),
5208 GFP_KERNEL);
5209 if (!net->ipv6.fib6_null_entry)
5210 goto out_ip6_dst_entries;
5211
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005212 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5213 sizeof(*net->ipv6.ip6_null_entry),
5214 GFP_KERNEL);
5215 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005216 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005217 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005218 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5219 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005220
5221#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005222 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005223 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5224 sizeof(*net->ipv6.ip6_prohibit_entry),
5225 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005226 if (!net->ipv6.ip6_prohibit_entry)
5227 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005228 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005229 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5230 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005231
5232 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5233 sizeof(*net->ipv6.ip6_blk_hole_entry),
5234 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005235 if (!net->ipv6.ip6_blk_hole_entry)
5236 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005237 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005238 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5239 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005240#endif
5241
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005242 net->ipv6.sysctl.flush_delay = 0;
5243 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5244 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5245 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5246 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5247 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5248 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5249 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005250 net->ipv6.sysctl.skip_notify_on_dev_down = 0;
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005251
Benjamin Thery6891a342008-03-04 13:49:47 -08005252 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5253
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005254 ret = 0;
5255out:
5256 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005257
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005258#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5259out_ip6_prohibit_entry:
5260 kfree(net->ipv6.ip6_prohibit_entry);
5261out_ip6_null_entry:
5262 kfree(net->ipv6.ip6_null_entry);
5263#endif
David Ahern421842e2018-04-17 17:33:18 -07005264out_fib6_null_entry:
5265 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005266out_ip6_dst_entries:
5267 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005268out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005269 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005270}
5271
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005272static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005273{
David Ahern421842e2018-04-17 17:33:18 -07005274 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005275 kfree(net->ipv6.ip6_null_entry);
5276#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5277 kfree(net->ipv6.ip6_prohibit_entry);
5278 kfree(net->ipv6.ip6_blk_hole_entry);
5279#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005280 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005281}
5282
Thomas Grafd1896342012-06-18 12:08:33 +00005283static int __net_init ip6_route_net_init_late(struct net *net)
5284{
5285#ifdef CONFIG_PROC_FS
Christoph Hellwigc3506372018-04-10 19:42:55 +02005286 proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
5287 sizeof(struct ipv6_route_iter));
Christoph Hellwig3617d942018-04-13 20:38:35 +02005288 proc_create_net_single("rt6_stats", 0444, net->proc_net,
5289 rt6_stats_seq_show, NULL);
Thomas Grafd1896342012-06-18 12:08:33 +00005290#endif
5291 return 0;
5292}
5293
5294static void __net_exit ip6_route_net_exit_late(struct net *net)
5295{
5296#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005297 remove_proc_entry("ipv6_route", net->proc_net);
5298 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005299#endif
5300}
5301
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005302static struct pernet_operations ip6_route_net_ops = {
5303 .init = ip6_route_net_init,
5304 .exit = ip6_route_net_exit,
5305};
5306
David S. Millerc3426b42012-06-09 16:27:05 -07005307static int __net_init ipv6_inetpeer_init(struct net *net)
5308{
5309 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5310
5311 if (!bp)
5312 return -ENOMEM;
5313 inet_peer_base_init(bp);
5314 net->ipv6.peers = bp;
5315 return 0;
5316}
5317
5318static void __net_exit ipv6_inetpeer_exit(struct net *net)
5319{
5320 struct inet_peer_base *bp = net->ipv6.peers;
5321
5322 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005323 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005324 kfree(bp);
5325}
5326
David S. Miller2b823f72012-06-09 19:00:16 -07005327static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005328 .init = ipv6_inetpeer_init,
5329 .exit = ipv6_inetpeer_exit,
5330};
5331
Thomas Grafd1896342012-06-18 12:08:33 +00005332static struct pernet_operations ip6_route_net_late_ops = {
5333 .init = ip6_route_net_init_late,
5334 .exit = ip6_route_net_exit_late,
5335};
5336
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005337static struct notifier_block ip6_route_dev_notifier = {
5338 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005339 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005340};
5341
WANG Cong2f460932017-05-03 22:07:31 -07005342void __init ip6_route_init_special_entries(void)
5343{
5344 /* Registering of the loopback is done before this portion of code,
5345 * the loopback reference in rt6_info will not be taken, do it
5346 * manually for init_net */
David Ahern421842e2018-04-17 17:33:18 -07005347 init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005348 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5349 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5350 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5351 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5352 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5353 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5354 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5355 #endif
5356}
5357
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005358int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005360 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005361 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005362
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005363 ret = -ENOMEM;
5364 ip6_dst_ops_template.kmem_cachep =
5365 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5366 SLAB_HWCACHE_ALIGN, NULL);
5367 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005368 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005369
Eric Dumazetfc66f952010-10-08 06:37:34 +00005370 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005371 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005372 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005373
David S. Millerc3426b42012-06-09 16:27:05 -07005374 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5375 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005376 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005377
David S. Miller7e52b332012-06-15 15:51:55 -07005378 ret = register_pernet_subsys(&ip6_route_net_ops);
5379 if (ret)
5380 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005381
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005382 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5383
David S. Millere8803b62012-06-16 01:12:19 -07005384 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005385 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005386 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005387
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005388 ret = xfrm6_init();
5389 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005390 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005391
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005392 ret = fib6_rules_init();
5393 if (ret)
5394 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005395
Thomas Grafd1896342012-06-18 12:08:33 +00005396 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5397 if (ret)
5398 goto fib6_rules_init;
5399
Florian Westphal16feebc2017-12-02 21:44:08 +01005400 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5401 inet6_rtm_newroute, NULL, 0);
5402 if (ret < 0)
5403 goto out_register_late_subsys;
5404
5405 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5406 inet6_rtm_delroute, NULL, 0);
5407 if (ret < 0)
5408 goto out_register_late_subsys;
5409
5410 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5411 inet6_rtm_getroute, NULL,
5412 RTNL_FLAG_DOIT_UNLOCKED);
5413 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005414 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005415
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005416 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005417 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005418 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005419
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005420 for_each_possible_cpu(cpu) {
5421 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5422
5423 INIT_LIST_HEAD(&ul->head);
5424 spin_lock_init(&ul->lock);
5425 }
5426
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005427out:
5428 return ret;
5429
Thomas Grafd1896342012-06-18 12:08:33 +00005430out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005431 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005432 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005433fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005434 fib6_rules_cleanup();
5435xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005436 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005437out_fib6_init:
5438 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005439out_register_subsys:
5440 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005441out_register_inetpeer:
5442 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005443out_dst_entries:
5444 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005445out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005446 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005447 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448}
5449
5450void ip6_route_cleanup(void)
5451{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005452 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005453 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005454 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005457 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005458 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005459 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005460 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461}