blob: dc066fdf7e4617239980532844ae56ad1e523c54 [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{
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001277 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001278
Wei Wang35732d02017-10-06 12:05:57 -07001279 if (!bucket || !rt6_ex)
1280 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001281
1282 net = dev_net(rt6_ex->rt6i->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001283 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001284 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001285 kfree_rcu(rt6_ex, rcu);
1286 WARN_ON_ONCE(!bucket->depth);
1287 bucket->depth--;
Wei Wang81eb8442017-10-06 12:06:11 -07001288 net->ipv6.rt6_stats->fib_rt_cache--;
Wei Wang35732d02017-10-06 12:05:57 -07001289}
1290
1291/* Remove oldest rt6_ex in bucket and free the memory
1292 * Caller must hold rt6_exception_lock
1293 */
1294static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1295{
1296 struct rt6_exception *rt6_ex, *oldest = NULL;
1297
1298 if (!bucket)
1299 return;
1300
1301 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1302 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1303 oldest = rt6_ex;
1304 }
1305 rt6_remove_exception(bucket, oldest);
1306}
1307
1308static u32 rt6_exception_hash(const struct in6_addr *dst,
1309 const struct in6_addr *src)
1310{
1311 static u32 seed __read_mostly;
1312 u32 val;
1313
1314 net_get_random_once(&seed, sizeof(seed));
1315 val = jhash(dst, sizeof(*dst), seed);
1316
1317#ifdef CONFIG_IPV6_SUBTREES
1318 if (src)
1319 val = jhash(src, sizeof(*src), val);
1320#endif
1321 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1322}
1323
1324/* Helper function to find the cached rt in the hash table
1325 * and update bucket pointer to point to the bucket for this
1326 * (daddr, saddr) pair
1327 * Caller must hold rt6_exception_lock
1328 */
1329static struct rt6_exception *
1330__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1331 const struct in6_addr *daddr,
1332 const struct in6_addr *saddr)
1333{
1334 struct rt6_exception *rt6_ex;
1335 u32 hval;
1336
1337 if (!(*bucket) || !daddr)
1338 return NULL;
1339
1340 hval = rt6_exception_hash(daddr, saddr);
1341 *bucket += hval;
1342
1343 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1344 struct rt6_info *rt6 = rt6_ex->rt6i;
1345 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1346
1347#ifdef CONFIG_IPV6_SUBTREES
1348 if (matched && saddr)
1349 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1350#endif
1351 if (matched)
1352 return rt6_ex;
1353 }
1354 return NULL;
1355}
1356
1357/* Helper function to find the cached rt in the hash table
1358 * and update bucket pointer to point to the bucket for this
1359 * (daddr, saddr) pair
1360 * Caller must hold rcu_read_lock()
1361 */
1362static struct rt6_exception *
1363__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1364 const struct in6_addr *daddr,
1365 const struct in6_addr *saddr)
1366{
1367 struct rt6_exception *rt6_ex;
1368 u32 hval;
1369
1370 WARN_ON_ONCE(!rcu_read_lock_held());
1371
1372 if (!(*bucket) || !daddr)
1373 return NULL;
1374
1375 hval = rt6_exception_hash(daddr, saddr);
1376 *bucket += hval;
1377
1378 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1379 struct rt6_info *rt6 = rt6_ex->rt6i;
1380 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1381
1382#ifdef CONFIG_IPV6_SUBTREES
1383 if (matched && saddr)
1384 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1385#endif
1386 if (matched)
1387 return rt6_ex;
1388 }
1389 return NULL;
1390}
1391
David Ahern8d1c8022018-04-17 17:33:26 -07001392static unsigned int fib6_mtu(const struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001393{
David Ahernd4ead6b2018-04-17 17:33:16 -07001394 unsigned int mtu;
1395
David Aherndcd1f572018-04-18 15:39:05 -07001396 if (rt->fib6_pmtu) {
1397 mtu = rt->fib6_pmtu;
1398 } else {
1399 struct net_device *dev = fib6_info_nh_dev(rt);
1400 struct inet6_dev *idev;
1401
1402 rcu_read_lock();
1403 idev = __in6_dev_get(dev);
1404 mtu = idev->cnf.mtu6;
1405 rcu_read_unlock();
1406 }
1407
David Ahernd4ead6b2018-04-17 17:33:16 -07001408 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1409
1410 return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu);
1411}
1412
Wei Wang35732d02017-10-06 12:05:57 -07001413static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern8d1c8022018-04-17 17:33:26 -07001414 struct fib6_info *ort)
Wei Wang35732d02017-10-06 12:05:57 -07001415{
David Ahern5e670d82018-04-17 17:33:14 -07001416 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001417 struct rt6_exception_bucket *bucket;
1418 struct in6_addr *src_key = NULL;
1419 struct rt6_exception *rt6_ex;
1420 int err = 0;
1421
Wei Wang35732d02017-10-06 12:05:57 -07001422 spin_lock_bh(&rt6_exception_lock);
1423
1424 if (ort->exception_bucket_flushed) {
1425 err = -EINVAL;
1426 goto out;
1427 }
1428
1429 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1430 lockdep_is_held(&rt6_exception_lock));
1431 if (!bucket) {
1432 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1433 GFP_ATOMIC);
1434 if (!bucket) {
1435 err = -ENOMEM;
1436 goto out;
1437 }
1438 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1439 }
1440
1441#ifdef CONFIG_IPV6_SUBTREES
1442 /* rt6i_src.plen != 0 indicates ort is in subtree
1443 * and exception table is indexed by a hash of
1444 * both rt6i_dst and rt6i_src.
1445 * Otherwise, the exception table is indexed by
1446 * a hash of only rt6i_dst.
1447 */
David Ahern93c2fb22018-04-18 15:38:59 -07001448 if (ort->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001449 src_key = &nrt->rt6i_src.addr;
1450#endif
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001451 /* rt6_mtu_change() might lower mtu on ort.
1452 * Only insert this exception route if its mtu
1453 * is less than ort's mtu value.
1454 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001455 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(ort)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001456 err = -EINVAL;
1457 goto out;
1458 }
Wei Wang60006a42017-10-06 12:05:58 -07001459
Wei Wang35732d02017-10-06 12:05:57 -07001460 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1461 src_key);
1462 if (rt6_ex)
1463 rt6_remove_exception(bucket, rt6_ex);
1464
1465 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1466 if (!rt6_ex) {
1467 err = -ENOMEM;
1468 goto out;
1469 }
1470 rt6_ex->rt6i = nrt;
1471 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001472 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1473 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001474 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001475
1476 if (bucket->depth > FIB6_MAX_DEPTH)
1477 rt6_exception_remove_oldest(bucket);
1478
1479out:
1480 spin_unlock_bh(&rt6_exception_lock);
1481
1482 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001483 if (!err) {
David Ahern93c2fb22018-04-18 15:38:59 -07001484 spin_lock_bh(&ort->fib6_table->tb6_lock);
David Ahern7aef6852018-04-17 17:33:10 -07001485 fib6_update_sernum(net, ort);
David Ahern93c2fb22018-04-18 15:38:59 -07001486 spin_unlock_bh(&ort->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001487 fib6_force_start_gc(net);
1488 }
Wei Wang35732d02017-10-06 12:05:57 -07001489
1490 return err;
1491}
1492
David Ahern8d1c8022018-04-17 17:33:26 -07001493void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001494{
1495 struct rt6_exception_bucket *bucket;
1496 struct rt6_exception *rt6_ex;
1497 struct hlist_node *tmp;
1498 int i;
1499
1500 spin_lock_bh(&rt6_exception_lock);
1501 /* Prevent rt6_insert_exception() to recreate the bucket list */
1502 rt->exception_bucket_flushed = 1;
1503
1504 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1505 lockdep_is_held(&rt6_exception_lock));
1506 if (!bucket)
1507 goto out;
1508
1509 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1510 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1511 rt6_remove_exception(bucket, rt6_ex);
1512 WARN_ON_ONCE(bucket->depth);
1513 bucket++;
1514 }
1515
1516out:
1517 spin_unlock_bh(&rt6_exception_lock);
1518}
1519
1520/* Find cached rt in the hash table inside passed in rt
1521 * Caller has to hold rcu_read_lock()
1522 */
David Ahern8d1c8022018-04-17 17:33:26 -07001523static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -07001524 struct in6_addr *daddr,
1525 struct in6_addr *saddr)
1526{
1527 struct rt6_exception_bucket *bucket;
1528 struct in6_addr *src_key = NULL;
1529 struct rt6_exception *rt6_ex;
1530 struct rt6_info *res = NULL;
1531
1532 bucket = rcu_dereference(rt->rt6i_exception_bucket);
1533
1534#ifdef CONFIG_IPV6_SUBTREES
1535 /* rt6i_src.plen != 0 indicates rt is in subtree
1536 * and exception table is indexed by a hash of
1537 * both rt6i_dst and rt6i_src.
1538 * Otherwise, the exception table is indexed by
1539 * a hash of only rt6i_dst.
1540 */
David Ahern93c2fb22018-04-18 15:38:59 -07001541 if (rt->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001542 src_key = saddr;
1543#endif
1544 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1545
1546 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1547 res = rt6_ex->rt6i;
1548
1549 return res;
1550}
1551
1552/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001553static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001554{
Wei Wang35732d02017-10-06 12:05:57 -07001555 struct rt6_exception_bucket *bucket;
1556 struct in6_addr *src_key = NULL;
1557 struct rt6_exception *rt6_ex;
David Ahern8a14e462018-04-23 11:32:07 -07001558 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001559 int err;
1560
Eric Dumazet091311d2018-04-24 09:22:49 -07001561 from = rcu_dereference(rt->from);
Wei Wang35732d02017-10-06 12:05:57 -07001562 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001563 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001564 return -EINVAL;
1565
1566 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1567 return -ENOENT;
1568
1569 spin_lock_bh(&rt6_exception_lock);
1570 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1571 lockdep_is_held(&rt6_exception_lock));
1572#ifdef CONFIG_IPV6_SUBTREES
1573 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1574 * and exception table is indexed by a hash of
1575 * both rt6i_dst and rt6i_src.
1576 * Otherwise, the exception table is indexed by
1577 * a hash of only rt6i_dst.
1578 */
David Ahern93c2fb22018-04-18 15:38:59 -07001579 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001580 src_key = &rt->rt6i_src.addr;
1581#endif
1582 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1583 &rt->rt6i_dst.addr,
1584 src_key);
1585 if (rt6_ex) {
1586 rt6_remove_exception(bucket, rt6_ex);
1587 err = 0;
1588 } else {
1589 err = -ENOENT;
1590 }
1591
1592 spin_unlock_bh(&rt6_exception_lock);
1593 return err;
1594}
1595
1596/* Find rt6_ex which contains the passed in rt cache and
1597 * refresh its stamp
1598 */
1599static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1600{
Wei Wang35732d02017-10-06 12:05:57 -07001601 struct rt6_exception_bucket *bucket;
David Ahern8d1c8022018-04-17 17:33:26 -07001602 struct fib6_info *from = rt->from;
Wei Wang35732d02017-10-06 12:05:57 -07001603 struct in6_addr *src_key = NULL;
1604 struct rt6_exception *rt6_ex;
1605
1606 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001607 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001608 return;
1609
1610 rcu_read_lock();
1611 bucket = rcu_dereference(from->rt6i_exception_bucket);
1612
1613#ifdef CONFIG_IPV6_SUBTREES
1614 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1615 * and exception table is indexed by a hash of
1616 * both rt6i_dst and rt6i_src.
1617 * Otherwise, the exception table is indexed by
1618 * a hash of only rt6i_dst.
1619 */
David Ahern93c2fb22018-04-18 15:38:59 -07001620 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001621 src_key = &rt->rt6i_src.addr;
1622#endif
1623 rt6_ex = __rt6_find_exception_rcu(&bucket,
1624 &rt->rt6i_dst.addr,
1625 src_key);
1626 if (rt6_ex)
1627 rt6_ex->stamp = jiffies;
1628
1629 rcu_read_unlock();
1630}
1631
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001632static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1633 struct rt6_info *rt, int mtu)
1634{
1635 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1636 * lowest MTU in the path: always allow updating the route PMTU to
1637 * reflect PMTU decreases.
1638 *
1639 * If the new MTU is higher, and the route PMTU is equal to the local
1640 * MTU, this means the old MTU is the lowest in the path, so allow
1641 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1642 * handle this.
1643 */
1644
1645 if (dst_mtu(&rt->dst) >= mtu)
1646 return true;
1647
1648 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1649 return true;
1650
1651 return false;
1652}
1653
1654static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001655 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001656{
1657 struct rt6_exception_bucket *bucket;
1658 struct rt6_exception *rt6_ex;
1659 int i;
1660
1661 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1662 lockdep_is_held(&rt6_exception_lock));
1663
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001664 if (!bucket)
1665 return;
1666
1667 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1668 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1669 struct rt6_info *entry = rt6_ex->rt6i;
1670
1671 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001672 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001673 * been updated.
1674 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001675 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001676 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001677 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001678 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001679 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001680 }
1681}
1682
Wei Wangb16cb452017-10-06 12:06:00 -07001683#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1684
David Ahern8d1c8022018-04-17 17:33:26 -07001685static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001686 struct in6_addr *gateway)
1687{
1688 struct rt6_exception_bucket *bucket;
1689 struct rt6_exception *rt6_ex;
1690 struct hlist_node *tmp;
1691 int i;
1692
1693 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1694 return;
1695
1696 spin_lock_bh(&rt6_exception_lock);
1697 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1698 lockdep_is_held(&rt6_exception_lock));
1699
1700 if (bucket) {
1701 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1702 hlist_for_each_entry_safe(rt6_ex, tmp,
1703 &bucket->chain, hlist) {
1704 struct rt6_info *entry = rt6_ex->rt6i;
1705
1706 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1707 RTF_CACHE_GATEWAY &&
1708 ipv6_addr_equal(gateway,
1709 &entry->rt6i_gateway)) {
1710 rt6_remove_exception(bucket, rt6_ex);
1711 }
1712 }
1713 bucket++;
1714 }
1715 }
1716
1717 spin_unlock_bh(&rt6_exception_lock);
1718}
1719
Wei Wangc757faa2017-10-06 12:06:01 -07001720static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1721 struct rt6_exception *rt6_ex,
1722 struct fib6_gc_args *gc_args,
1723 unsigned long now)
1724{
1725 struct rt6_info *rt = rt6_ex->rt6i;
1726
Paolo Abeni1859bac2017-10-19 16:07:11 +02001727 /* we are pruning and obsoleting aged-out and non gateway exceptions
1728 * even if others have still references to them, so that on next
1729 * dst_check() such references can be dropped.
1730 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1731 * expired, independently from their aging, as per RFC 8201 section 4
1732 */
Wei Wang31afeb42018-01-26 11:40:17 -08001733 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1734 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1735 RT6_TRACE("aging clone %p\n", rt);
1736 rt6_remove_exception(bucket, rt6_ex);
1737 return;
1738 }
1739 } else if (time_after(jiffies, rt->dst.expires)) {
1740 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001741 rt6_remove_exception(bucket, rt6_ex);
1742 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001743 }
1744
1745 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001746 struct neighbour *neigh;
1747 __u8 neigh_flags = 0;
1748
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001749 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1750 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001751 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001752
Wei Wangc757faa2017-10-06 12:06:01 -07001753 if (!(neigh_flags & NTF_ROUTER)) {
1754 RT6_TRACE("purging route %p via non-router but gateway\n",
1755 rt);
1756 rt6_remove_exception(bucket, rt6_ex);
1757 return;
1758 }
1759 }
Wei Wang31afeb42018-01-26 11:40:17 -08001760
Wei Wangc757faa2017-10-06 12:06:01 -07001761 gc_args->more++;
1762}
1763
David Ahern8d1c8022018-04-17 17:33:26 -07001764void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001765 struct fib6_gc_args *gc_args,
1766 unsigned long now)
1767{
1768 struct rt6_exception_bucket *bucket;
1769 struct rt6_exception *rt6_ex;
1770 struct hlist_node *tmp;
1771 int i;
1772
1773 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1774 return;
1775
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001776 rcu_read_lock_bh();
1777 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001778 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1779 lockdep_is_held(&rt6_exception_lock));
1780
1781 if (bucket) {
1782 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1783 hlist_for_each_entry_safe(rt6_ex, tmp,
1784 &bucket->chain, hlist) {
1785 rt6_age_examine_exception(bucket, rt6_ex,
1786 gc_args, now);
1787 }
1788 bucket++;
1789 }
1790 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001791 spin_unlock(&rt6_exception_lock);
1792 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001793}
1794
David Ahern1d053da2018-05-09 20:34:21 -07001795/* must be called with rcu lock held */
1796struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
1797 int oif, struct flowi6 *fl6, int strict)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001799 struct fib6_node *fn, *saved_fn;
David Ahern8d1c8022018-04-17 17:33:26 -07001800 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
David Ahern64547432018-05-09 20:34:19 -07001802 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001803 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
David Ahernca254492015-10-12 11:47:10 -07001805 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1806 oif = 0;
1807
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001808redo_rt6_select:
David Ahern23fb93a2018-04-17 17:33:23 -07001809 f6i = rt6_select(net, fn, oif, strict);
David Ahern23fb93a2018-04-17 17:33:23 -07001810 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001811 fn = fib6_backtrack(fn, &fl6->saddr);
1812 if (fn)
1813 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001814 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1815 /* also consider unreachable route */
1816 strict &= ~RT6_LOOKUP_F_REACHABLE;
1817 fn = saved_fn;
1818 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001819 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001820 }
1821
David Ahernd4bea422018-05-09 20:34:24 -07001822 trace_fib6_table_lookup(net, f6i, table, fl6);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001823
David Ahern1d053da2018-05-09 20:34:21 -07001824 return f6i;
1825}
1826
1827struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1828 int oif, struct flowi6 *fl6,
1829 const struct sk_buff *skb, int flags)
1830{
1831 struct fib6_info *f6i;
1832 struct rt6_info *rt;
1833 int strict = 0;
1834
1835 strict |= flags & RT6_LOOKUP_F_IFACE;
1836 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1837 if (net->ipv6.devconf_all->forwarding == 0)
1838 strict |= RT6_LOOKUP_F_REACHABLE;
1839
1840 rcu_read_lock();
1841
1842 f6i = fib6_table_lookup(net, table, oif, fl6, strict);
1843 if (f6i->fib6_nsiblings)
1844 f6i = fib6_multipath_select(net, f6i, fl6, oif, skb, strict);
1845
David Ahern23fb93a2018-04-17 17:33:23 -07001846 if (f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001847 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001848 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001849 dst_hold(&rt->dst);
Wei Wangd3843fe2017-10-06 12:06:06 -07001850 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001851 }
1852
1853 /*Search through exception table */
1854 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1855 if (rt) {
David Ahernd4ead6b2018-04-17 17:33:16 -07001856 if (ip6_hold_safe(net, &rt, true))
Wei Wangd3843fe2017-10-06 12:06:06 -07001857 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001858
Wei Wang66f5d6c2017-10-06 12:06:10 -07001859 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001860 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001861 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahern93c2fb22018-04-18 15:38:59 -07001862 !(f6i->fib6_flags & RTF_GATEWAY))) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001863 /* Create a RTF_CACHE clone which will not be
1864 * owned by the fib6 tree. It is for the special case where
1865 * the daddr in the skb during the neighbor look-up is different
1866 * from the fl6->daddr used to look-up route here.
1867 */
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001868 struct rt6_info *uncached_rt;
1869
David Ahern23fb93a2018-04-17 17:33:23 -07001870 uncached_rt = ip6_rt_cache_alloc(f6i, &fl6->daddr, NULL);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001871
David Ahern4d85cd02018-04-20 15:37:59 -07001872 rcu_read_unlock();
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001873
Wei Wang1cfb71e2017-06-17 10:42:33 -07001874 if (uncached_rt) {
1875 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1876 * No need for another dst_hold()
1877 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001878 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001879 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001880 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001881 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001882 dst_hold(&uncached_rt->dst);
1883 }
David Ahernb8115802015-11-19 12:24:22 -08001884
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001885 return uncached_rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001886 } else {
1887 /* Get a percpu copy */
1888
1889 struct rt6_info *pcpu_rt;
1890
Eric Dumazet951f7882017-10-08 21:07:18 -07001891 local_bh_disable();
David Ahern23fb93a2018-04-17 17:33:23 -07001892 pcpu_rt = rt6_get_pcpu_route(f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001893
David Ahern93531c62018-04-17 17:33:25 -07001894 if (!pcpu_rt)
1895 pcpu_rt = rt6_make_pcpu_route(net, f6i);
1896
Eric Dumazet951f7882017-10-08 21:07:18 -07001897 local_bh_enable();
1898 rcu_read_unlock();
David Ahernd4bea422018-05-09 20:34:24 -07001899
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001900 return pcpu_rt;
1901 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001902}
David Ahern9ff74382016-06-13 13:44:19 -07001903EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001904
David Ahernb75cc8f2018-03-02 08:32:17 -08001905static struct rt6_info *ip6_pol_route_input(struct net *net,
1906 struct fib6_table *table,
1907 struct flowi6 *fl6,
1908 const struct sk_buff *skb,
1909 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001910{
David Ahernb75cc8f2018-03-02 08:32:17 -08001911 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001912}
1913
Mahesh Bandeward409b842016-09-16 12:59:08 -07001914struct dst_entry *ip6_route_input_lookup(struct net *net,
1915 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001916 struct flowi6 *fl6,
1917 const struct sk_buff *skb,
1918 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001919{
1920 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1921 flags |= RT6_LOOKUP_F_IFACE;
1922
David Ahernb75cc8f2018-03-02 08:32:17 -08001923 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001924}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001925EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001926
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001927static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001928 struct flow_keys *keys,
1929 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001930{
1931 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1932 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001933 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001934 const struct ipv6hdr *inner_iph;
1935 const struct icmp6hdr *icmph;
1936 struct ipv6hdr _inner_iph;
Eric Dumazetcea67a22018-04-29 09:54:59 -07001937 struct icmp6hdr _icmph;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001938
1939 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1940 goto out;
1941
Eric Dumazetcea67a22018-04-29 09:54:59 -07001942 icmph = skb_header_pointer(skb, skb_transport_offset(skb),
1943 sizeof(_icmph), &_icmph);
1944 if (!icmph)
1945 goto out;
1946
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001947 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1948 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1949 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1950 icmph->icmp6_type != ICMPV6_PARAMPROB)
1951 goto out;
1952
1953 inner_iph = skb_header_pointer(skb,
1954 skb_transport_offset(skb) + sizeof(*icmph),
1955 sizeof(_inner_iph), &_inner_iph);
1956 if (!inner_iph)
1957 goto out;
1958
1959 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001960 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001961out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001962 if (_flkeys) {
1963 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1964 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1965 keys->tags.flow_label = _flkeys->tags.flow_label;
1966 keys->basic.ip_proto = _flkeys->basic.ip_proto;
1967 } else {
1968 keys->addrs.v6addrs.src = key_iph->saddr;
1969 keys->addrs.v6addrs.dst = key_iph->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02001970 keys->tags.flow_label = ip6_flowlabel(key_iph);
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001971 keys->basic.ip_proto = key_iph->nexthdr;
1972 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001973}
1974
1975/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08001976u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
1977 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001978{
1979 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08001980 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001981
David S. Millerbbfa0472018-03-12 11:09:33 -04001982 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08001983 case 0:
1984 memset(&hash_keys, 0, sizeof(hash_keys));
1985 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1986 if (skb) {
1987 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
1988 } else {
1989 hash_keys.addrs.v6addrs.src = fl6->saddr;
1990 hash_keys.addrs.v6addrs.dst = fl6->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02001991 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
David Ahernb4bac172018-03-02 08:32:18 -08001992 hash_keys.basic.ip_proto = fl6->flowi6_proto;
1993 }
1994 break;
1995 case 1:
1996 if (skb) {
1997 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
1998 struct flow_keys keys;
1999
2000 /* short-circuit if we already have L4 hash present */
2001 if (skb->l4_hash)
2002 return skb_get_hash_raw(skb) >> 1;
2003
2004 memset(&hash_keys, 0, sizeof(hash_keys));
2005
2006 if (!flkeys) {
2007 skb_flow_dissect_flow_keys(skb, &keys, flag);
2008 flkeys = &keys;
2009 }
2010 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2011 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2012 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2013 hash_keys.ports.src = flkeys->ports.src;
2014 hash_keys.ports.dst = flkeys->ports.dst;
2015 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2016 } else {
2017 memset(&hash_keys, 0, sizeof(hash_keys));
2018 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2019 hash_keys.addrs.v6addrs.src = fl6->saddr;
2020 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2021 hash_keys.ports.src = fl6->fl6_sport;
2022 hash_keys.ports.dst = fl6->fl6_dport;
2023 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2024 }
2025 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002026 }
David Ahern9a2a5372018-03-02 08:32:15 -08002027 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002028
David Ahern9a2a5372018-03-02 08:32:15 -08002029 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002030}
2031
Thomas Grafc71099a2006-08-04 23:20:06 -07002032void ip6_route_input(struct sk_buff *skb)
2033{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002034 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002035 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002036 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002037 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002038 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002039 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002040 .daddr = iph->daddr,
2041 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002042 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002043 .flowi6_mark = skb->mark,
2044 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002045 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002046 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002047
Jiri Benc904af042015-08-20 13:56:31 +02002048 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002049 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002050 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002051
2052 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2053 flkeys = &_flkeys;
2054
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002055 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002056 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002057 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002058 skb_dst_set(skb,
2059 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002060}
2061
David Ahernb75cc8f2018-03-02 08:32:17 -08002062static struct rt6_info *ip6_pol_route_output(struct net *net,
2063 struct fib6_table *table,
2064 struct flowi6 *fl6,
2065 const struct sk_buff *skb,
2066 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002067{
David Ahernb75cc8f2018-03-02 08:32:17 -08002068 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002069}
2070
Paolo Abeni6f21c962016-01-29 12:30:19 +01002071struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2072 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002073{
David Ahernd46a9d62015-10-21 08:42:22 -07002074 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002075
Robert Shearman3ede0bb2018-09-19 13:56:53 +01002076 if (ipv6_addr_type(&fl6->daddr) &
2077 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
David Ahern4c1feac2016-09-10 12:09:56 -07002078 struct dst_entry *dst;
2079
2080 dst = l3mdev_link_scope_lookup(net, fl6);
2081 if (dst)
2082 return dst;
2083 }
David Ahernca254492015-10-12 11:47:10 -07002084
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002085 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002086
David Ahernd46a9d62015-10-21 08:42:22 -07002087 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002088 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002089 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002090 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002091
David Ahernd46a9d62015-10-21 08:42:22 -07002092 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002093 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002094 else if (sk)
2095 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002096
David Ahernb75cc8f2018-03-02 08:32:17 -08002097 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002099EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
David S. Miller2774c132011-03-01 14:59:04 -08002101struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002102{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002103 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002104 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002105 struct dst_entry *new = NULL;
2106
Wei Wang1dbe32522017-06-17 10:42:26 -07002107 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002108 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002109 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002110 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002111 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002112
Changli Gaod8d1f302010-06-10 23:31:35 -07002113 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002114 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002115 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002116 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002117
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002118 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002119
Wei Wang1dbe32522017-06-17 10:42:26 -07002120 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002121 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002122 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002123
2124 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2125#ifdef CONFIG_IPV6_SUBTREES
2126 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2127#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002128 }
2129
David S. Miller69ead7a2011-03-01 14:45:33 -08002130 dst_release(dst_orig);
2131 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002132}
David S. Miller14e50e52007-05-24 18:17:54 -07002133
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134/*
2135 * Destination cache support functions
2136 */
2137
David Ahern8d1c8022018-04-17 17:33:26 -07002138static bool fib6_check(struct fib6_info *f6i, u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002139{
Steffen Klassert36143642017-08-25 09:05:42 +02002140 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002141
David Ahern8ae86972018-04-20 15:38:03 -07002142 if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
David Ahern93531c62018-04-17 17:33:25 -07002143 return false;
2144
2145 if (fib6_check_expired(f6i))
2146 return false;
2147
2148 return true;
2149}
2150
David Aherna68886a2018-04-20 15:38:02 -07002151static struct dst_entry *rt6_check(struct rt6_info *rt,
2152 struct fib6_info *from,
2153 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002154{
Wei Wangc5cff852017-08-21 09:47:10 -07002155 u32 rt_cookie = 0;
2156
David Aherna68886a2018-04-20 15:38:02 -07002157 if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
David Ahern93531c62018-04-17 17:33:25 -07002158 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002159 return NULL;
2160
2161 if (rt6_check_expired(rt))
2162 return NULL;
2163
2164 return &rt->dst;
2165}
2166
David Aherna68886a2018-04-20 15:38:02 -07002167static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2168 struct fib6_info *from,
2169 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002170{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002171 if (!__rt6_check_expired(rt) &&
2172 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Aherna68886a2018-04-20 15:38:02 -07002173 fib6_check(from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002174 return &rt->dst;
2175 else
2176 return NULL;
2177}
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2180{
David Aherna87b7dc2018-04-20 15:38:00 -07002181 struct dst_entry *dst_ret;
David Aherna68886a2018-04-20 15:38:02 -07002182 struct fib6_info *from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 struct rt6_info *rt;
2184
David Aherna87b7dc2018-04-20 15:38:00 -07002185 rt = container_of(dst, struct rt6_info, dst);
2186
2187 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002189 /* All IPV6 dsts are created with ->obsolete set to the value
2190 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2191 * into this function always.
2192 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002193
David Aherna68886a2018-04-20 15:38:02 -07002194 from = rcu_dereference(rt->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002195
David Aherna68886a2018-04-20 15:38:02 -07002196 if (from && (rt->rt6i_flags & RTF_PCPU ||
2197 unlikely(!list_empty(&rt->rt6i_uncached))))
2198 dst_ret = rt6_dst_from_check(rt, from, cookie);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002199 else
David Aherna68886a2018-04-20 15:38:02 -07002200 dst_ret = rt6_check(rt, from, cookie);
David Aherna87b7dc2018-04-20 15:38:00 -07002201
2202 rcu_read_unlock();
2203
2204 return dst_ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205}
2206
2207static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2208{
2209 struct rt6_info *rt = (struct rt6_info *) dst;
2210
2211 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002212 if (rt->rt6i_flags & RTF_CACHE) {
David Ahernc3c14da2018-04-23 11:32:06 -07002213 rcu_read_lock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002214 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002215 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002216 dst = NULL;
2217 }
David Ahernc3c14da2018-04-23 11:32:06 -07002218 rcu_read_unlock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002219 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002221 dst = NULL;
2222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002224 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225}
2226
2227static void ip6_link_failure(struct sk_buff *skb)
2228{
2229 struct rt6_info *rt;
2230
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002231 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Eric Dumazetadf30902009-06-02 05:19:30 +00002233 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 if (rt) {
David Ahern8a14e462018-04-23 11:32:07 -07002235 rcu_read_lock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002236 if (rt->rt6i_flags & RTF_CACHE) {
Xin Long761f6022018-11-14 00:48:28 +08002237 rt6_remove_exception_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002238 } else {
David Aherna68886a2018-04-20 15:38:02 -07002239 struct fib6_info *from;
Wei Wangc5cff852017-08-21 09:47:10 -07002240 struct fib6_node *fn;
2241
David Aherna68886a2018-04-20 15:38:02 -07002242 from = rcu_dereference(rt->from);
2243 if (from) {
2244 fn = rcu_dereference(from->fib6_node);
2245 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2246 fn->fn_sernum = -1;
2247 }
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002248 }
David Ahern8a14e462018-04-23 11:32:07 -07002249 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 }
2251}
2252
David Ahern6a3e0302018-04-20 15:37:57 -07002253static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2254{
David Aherna68886a2018-04-20 15:38:02 -07002255 if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2256 struct fib6_info *from;
2257
2258 rcu_read_lock();
2259 from = rcu_dereference(rt0->from);
2260 if (from)
2261 rt0->dst.expires = from->expires;
2262 rcu_read_unlock();
2263 }
David Ahern6a3e0302018-04-20 15:37:57 -07002264
2265 dst_set_expires(&rt0->dst, timeout);
2266 rt0->rt6i_flags |= RTF_EXPIRES;
2267}
2268
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002269static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2270{
2271 struct net *net = dev_net(rt->dst.dev);
2272
David Ahernd4ead6b2018-04-17 17:33:16 -07002273 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002274 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002275 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2276}
2277
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002278static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2279{
David Aherna68886a2018-04-20 15:38:02 -07002280 bool from_set;
2281
2282 rcu_read_lock();
2283 from_set = !!rcu_dereference(rt->from);
2284 rcu_read_unlock();
2285
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002286 return !(rt->rt6i_flags & RTF_CACHE) &&
David Aherna68886a2018-04-20 15:38:02 -07002287 (rt->rt6i_flags & RTF_PCPU || from_set);
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002288}
2289
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002290static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2291 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002293 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002294 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
Xin Long19bda362016-10-28 18:18:01 +08002296 if (dst_metric_locked(dst, RTAX_MTU))
2297 return;
2298
Julian Anastasov0dec8792017-02-06 23:14:16 +02002299 if (iph) {
2300 daddr = &iph->daddr;
2301 saddr = &iph->saddr;
2302 } else if (sk) {
2303 daddr = &sk->sk_v6_daddr;
2304 saddr = &inet6_sk(sk)->saddr;
2305 } else {
2306 daddr = NULL;
2307 saddr = NULL;
2308 }
2309 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002310 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2311 if (mtu >= dst_mtu(dst))
2312 return;
David S. Miller81aded22012-06-15 14:54:11 -07002313
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002314 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002315 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002316 /* update rt6_ex->stamp for cache */
2317 if (rt6->rt6i_flags & RTF_CACHE)
2318 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002319 } else if (daddr) {
David Aherna68886a2018-04-20 15:38:02 -07002320 struct fib6_info *from;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002321 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002322
David Ahern4d85cd02018-04-20 15:37:59 -07002323 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07002324 from = rcu_dereference(rt6->from);
2325 nrt6 = ip6_rt_cache_alloc(from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002326 if (nrt6) {
2327 rt6_do_update_pmtu(nrt6, mtu);
David Aherna68886a2018-04-20 15:38:02 -07002328 if (rt6_insert_exception(nrt6, from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002329 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002330 }
David Aherna68886a2018-04-20 15:38:02 -07002331 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 }
2333}
2334
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002335static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2336 struct sk_buff *skb, u32 mtu)
2337{
2338 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2339}
2340
David S. Miller42ae66c2012-06-15 20:01:57 -07002341void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002342 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002343{
2344 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2345 struct dst_entry *dst;
Maciej Żenczykowskidc920952018-09-29 23:44:51 -07002346 struct flowi6 fl6 = {
2347 .flowi6_oif = oif,
2348 .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark),
2349 .daddr = iph->daddr,
2350 .saddr = iph->saddr,
2351 .flowlabel = ip6_flowinfo(iph),
2352 .flowi6_uid = uid,
2353 };
David S. Miller81aded22012-06-15 14:54:11 -07002354
2355 dst = ip6_route_output(net, NULL, &fl6);
2356 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002357 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002358 dst_release(dst);
2359}
2360EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2361
2362void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2363{
David Ahern7ddacfa2018-11-18 10:45:30 -08002364 int oif = sk->sk_bound_dev_if;
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002365 struct dst_entry *dst;
2366
David Ahern7ddacfa2018-11-18 10:45:30 -08002367 if (!oif && skb->dev)
2368 oif = l3mdev_master_ifindex(skb->dev);
2369
2370 ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002371
2372 dst = __sk_dst_get(sk);
2373 if (!dst || !dst->obsolete ||
2374 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2375 return;
2376
2377 bh_lock_sock(sk);
2378 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2379 ip6_datagram_dst_update(sk, false);
2380 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002381}
2382EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2383
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002384void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2385 const struct flowi6 *fl6)
2386{
2387#ifdef CONFIG_IPV6_SUBTREES
2388 struct ipv6_pinfo *np = inet6_sk(sk);
2389#endif
2390
2391 ip6_dst_store(sk, dst,
2392 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2393 &sk->sk_v6_daddr : NULL,
2394#ifdef CONFIG_IPV6_SUBTREES
2395 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2396 &np->saddr :
2397#endif
2398 NULL);
2399}
2400
Duan Jiongb55b76b2013-09-04 19:44:21 +08002401/* Handle redirects */
2402struct ip6rd_flowi {
2403 struct flowi6 fl6;
2404 struct in6_addr gateway;
2405};
2406
2407static struct rt6_info *__ip6_route_redirect(struct net *net,
2408 struct fib6_table *table,
2409 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002410 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002411 int flags)
2412{
2413 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern23fb93a2018-04-17 17:33:23 -07002414 struct rt6_info *ret = NULL, *rt_cache;
David Ahern8d1c8022018-04-17 17:33:26 -07002415 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002416 struct fib6_node *fn;
2417
2418 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002419 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002420 *
2421 * RFC 4861 specifies that redirects should only be
2422 * accepted if they come from the nexthop to the target.
2423 * Due to the way the routes are chosen, this notion
2424 * is a bit fuzzy and one might need to check all possible
2425 * routes.
2426 */
2427
Wei Wang66f5d6c2017-10-06 12:06:10 -07002428 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002429 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002430restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002431 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07002432 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +02002433 continue;
David Ahern14895682018-04-17 17:33:17 -07002434 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002435 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002436 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002437 break;
David Ahern93c2fb22018-04-18 15:38:59 -07002438 if (!(rt->fib6_flags & RTF_GATEWAY))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002439 continue;
David Ahern5e670d82018-04-17 17:33:14 -07002440 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002441 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002442 /* rt_cache's gateway might be different from its 'parent'
2443 * in the case of an ip redirect.
2444 * So we keep searching in the exception table if the gateway
2445 * is different.
2446 */
David Ahern5e670d82018-04-17 17:33:14 -07002447 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002448 rt_cache = rt6_find_cached_rt(rt,
2449 &fl6->daddr,
2450 &fl6->saddr);
2451 if (rt_cache &&
2452 ipv6_addr_equal(&rdfl->gateway,
2453 &rt_cache->rt6i_gateway)) {
David Ahern23fb93a2018-04-17 17:33:23 -07002454 ret = rt_cache;
Wei Wang2b760fc2017-10-06 12:06:03 -07002455 break;
2456 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002457 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002458 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002459 break;
2460 }
2461
2462 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002463 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002464 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002465 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002466 goto out;
2467 }
2468
David Ahern421842e2018-04-17 17:33:18 -07002469 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002470 fn = fib6_backtrack(fn, &fl6->saddr);
2471 if (fn)
2472 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002473 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002474
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002475out:
David Ahern23fb93a2018-04-17 17:33:23 -07002476 if (ret)
Wei Wange873e4b2018-07-21 20:56:32 -07002477 ip6_hold_safe(net, &ret, true);
David Ahern23fb93a2018-04-17 17:33:23 -07002478 else
2479 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002480
Wei Wang66f5d6c2017-10-06 12:06:10 -07002481 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002482
Paolo Abenib65f1642017-10-19 09:31:43 +02002483 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002484 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002485};
2486
2487static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002488 const struct flowi6 *fl6,
2489 const struct sk_buff *skb,
2490 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002491{
2492 int flags = RT6_LOOKUP_F_HAS_SADDR;
2493 struct ip6rd_flowi rdfl;
2494
2495 rdfl.fl6 = *fl6;
2496 rdfl.gateway = *gateway;
2497
David Ahernb75cc8f2018-03-02 08:32:17 -08002498 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002499 flags, __ip6_route_redirect);
2500}
2501
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002502void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2503 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002504{
2505 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2506 struct dst_entry *dst;
Maciej Żenczykowski1f7f10a2018-09-29 23:44:48 -07002507 struct flowi6 fl6 = {
2508 .flowi6_iif = LOOPBACK_IFINDEX,
2509 .flowi6_oif = oif,
2510 .flowi6_mark = mark,
2511 .daddr = iph->daddr,
2512 .saddr = iph->saddr,
2513 .flowlabel = ip6_flowinfo(iph),
2514 .flowi6_uid = uid,
2515 };
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002516
David Ahernb75cc8f2018-03-02 08:32:17 -08002517 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002518 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002519 dst_release(dst);
2520}
2521EXPORT_SYMBOL_GPL(ip6_redirect);
2522
Maciej Żenczykowskid4563362018-09-29 23:44:50 -07002523void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
Duan Jiongc92a59e2013-08-22 12:07:35 +08002524{
2525 const struct ipv6hdr *iph = ipv6_hdr(skb);
2526 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2527 struct dst_entry *dst;
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002528 struct flowi6 fl6 = {
2529 .flowi6_iif = LOOPBACK_IFINDEX,
2530 .flowi6_oif = oif,
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002531 .daddr = msg->dest,
2532 .saddr = iph->daddr,
2533 .flowi6_uid = sock_net_uid(net, NULL),
2534 };
Duan Jiongc92a59e2013-08-22 12:07:35 +08002535
David Ahernb75cc8f2018-03-02 08:32:17 -08002536 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002537 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002538 dst_release(dst);
2539}
2540
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002541void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2542{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002543 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2544 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002545}
2546EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2547
David S. Miller0dbaee32010-12-13 12:52:14 -08002548static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549{
David S. Miller0dbaee32010-12-13 12:52:14 -08002550 struct net_device *dev = dst->dev;
2551 unsigned int mtu = dst_mtu(dst);
2552 struct net *net = dev_net(dev);
2553
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2555
Daniel Lezcano55786892008-03-04 13:47:47 -08002556 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2557 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
2559 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002560 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2561 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2562 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 * rely only on pmtu discovery"
2564 */
2565 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2566 mtu = IPV6_MAXPLEN;
2567 return mtu;
2568}
2569
Steffen Klassertebb762f2011-11-23 02:12:51 +00002570static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002571{
David S. Millerd33e4552010-12-14 13:01:14 -08002572 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002573 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002574
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002575 mtu = dst_metric_raw(dst, RTAX_MTU);
2576 if (mtu)
2577 goto out;
2578
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002579 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002580
2581 rcu_read_lock();
2582 idev = __in6_dev_get(dst->dev);
2583 if (idev)
2584 mtu = idev->cnf.mtu6;
2585 rcu_read_unlock();
2586
Eric Dumazet30f78d82014-04-10 21:23:36 -07002587out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002588 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2589
2590 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002591}
2592
David Ahern901731b2018-05-21 09:08:14 -07002593/* MTU selection:
2594 * 1. mtu on route is locked - use it
2595 * 2. mtu from nexthop exception
2596 * 3. mtu from egress device
2597 *
2598 * based on ip6_dst_mtu_forward and exception logic of
2599 * rt6_find_cached_rt; called with rcu_read_lock
2600 */
2601u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
2602 struct in6_addr *saddr)
2603{
2604 struct rt6_exception_bucket *bucket;
2605 struct rt6_exception *rt6_ex;
2606 struct in6_addr *src_key;
2607 struct inet6_dev *idev;
2608 u32 mtu = 0;
2609
2610 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2611 mtu = f6i->fib6_pmtu;
2612 if (mtu)
2613 goto out;
2614 }
2615
2616 src_key = NULL;
2617#ifdef CONFIG_IPV6_SUBTREES
2618 if (f6i->fib6_src.plen)
2619 src_key = saddr;
2620#endif
2621
2622 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2623 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2624 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2625 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2626
2627 if (likely(!mtu)) {
2628 struct net_device *dev = fib6_info_nh_dev(f6i);
2629
2630 mtu = IPV6_MIN_MTU;
2631 idev = __in6_dev_get(dev);
2632 if (idev && idev->cnf.mtu6 > mtu)
2633 mtu = idev->cnf.mtu6;
2634 }
2635
2636 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2637out:
2638 return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu);
2639}
2640
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002641struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002642 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
David S. Miller87a11572011-12-06 17:04:13 -05002644 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 struct rt6_info *rt;
2646 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002647 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
David S. Miller38308472011-12-03 18:02:47 -05002649 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002650 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Martin KaFai Lauad706862015-08-14 11:05:52 -07002652 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002653 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002655 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 goto out;
2657 }
2658
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002659 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002660 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002661 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002662 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002663 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002664 rt->rt6i_dst.plen = 128;
2665 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002666 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
Ido Schimmel4c981e22018-01-07 12:45:04 +02002668 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002669 * do proper release of the net_device
2670 */
2671 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002672 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
David S. Miller87a11572011-12-06 17:04:13 -05002674 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676out:
David S. Miller87a11572011-12-06 17:04:13 -05002677 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678}
2679
Daniel Lezcano569d3642008-01-18 03:56:57 -08002680static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002682 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002683 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2684 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2685 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2686 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2687 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002688 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Eric Dumazetfc66f952010-10-08 06:37:34 +00002690 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002691 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002692 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 goto out;
2694
Benjamin Thery6891a342008-03-04 13:49:47 -08002695 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002696 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002697 entries = dst_entries_get_slow(ops);
2698 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002699 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002701 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002702 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703}
2704
David Ahern8c145862016-04-24 21:26:04 -07002705static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2706 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002707 const struct in6_addr *gw_addr,
2708 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002709{
2710 struct flowi6 fl6 = {
2711 .flowi6_oif = cfg->fc_ifindex,
2712 .daddr = *gw_addr,
2713 .saddr = cfg->fc_prefsrc,
2714 };
2715 struct fib6_table *table;
2716 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002717
David Ahernf4797b32018-01-25 16:55:08 -08002718 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002719 if (!table)
2720 return NULL;
2721
2722 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2723 flags |= RT6_LOOKUP_F_HAS_SADDR;
2724
David Ahernf4797b32018-01-25 16:55:08 -08002725 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002726 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002727
2728 /* if table lookup failed, fall back to full lookup */
2729 if (rt == net->ipv6.ip6_null_entry) {
2730 ip6_rt_put(rt);
2731 rt = NULL;
2732 }
2733
2734 return rt;
2735}
2736
David Ahernfc1e64e2018-01-25 16:55:09 -08002737static int ip6_route_check_nh_onlink(struct net *net,
2738 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002739 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002740 struct netlink_ext_ack *extack)
2741{
David Ahern44750f82018-02-06 13:17:06 -08002742 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002743 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2744 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
2745 struct rt6_info *grt;
2746 int err;
2747
2748 err = 0;
2749 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2750 if (grt) {
David Ahern58e354c2018-02-06 12:14:12 -08002751 if (!grt->dst.error &&
David Ahern4ed591c2018-10-24 13:58:39 -07002752 /* ignore match if it is the default route */
2753 grt->from && !ipv6_addr_any(&grt->from->fib6_dst.addr) &&
David Ahern58e354c2018-02-06 12:14:12 -08002754 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002755 NL_SET_ERR_MSG(extack,
2756 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002757 err = -EINVAL;
2758 }
2759
2760 ip6_rt_put(grt);
2761 }
2762
2763 return err;
2764}
2765
David Ahern1edce992018-01-25 16:55:07 -08002766static int ip6_route_check_nh(struct net *net,
2767 struct fib6_config *cfg,
2768 struct net_device **_dev,
2769 struct inet6_dev **idev)
2770{
2771 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2772 struct net_device *dev = _dev ? *_dev : NULL;
2773 struct rt6_info *grt = NULL;
2774 int err = -EHOSTUNREACH;
2775
2776 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002777 int flags = RT6_LOOKUP_F_IFACE;
2778
2779 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2780 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002781 if (grt) {
2782 if (grt->rt6i_flags & RTF_GATEWAY ||
2783 (dev && dev != grt->dst.dev)) {
2784 ip6_rt_put(grt);
2785 grt = NULL;
2786 }
2787 }
2788 }
2789
2790 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002791 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002792
2793 if (!grt)
2794 goto out;
2795
2796 if (dev) {
2797 if (dev != grt->dst.dev) {
2798 ip6_rt_put(grt);
2799 goto out;
2800 }
2801 } else {
2802 *_dev = dev = grt->dst.dev;
2803 *idev = grt->rt6i_idev;
2804 dev_hold(dev);
2805 in6_dev_hold(grt->rt6i_idev);
2806 }
2807
2808 if (!(grt->rt6i_flags & RTF_GATEWAY))
2809 err = 0;
2810
2811 ip6_rt_put(grt);
2812
2813out:
2814 return err;
2815}
2816
David Ahern9fbb7042018-03-13 08:29:36 -07002817static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2818 struct net_device **_dev, struct inet6_dev **idev,
2819 struct netlink_ext_ack *extack)
2820{
2821 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2822 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002823 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002824 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002825 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002826 int err = -EINVAL;
2827
2828 /* if gw_addr is local we will fail to detect this in case
2829 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2830 * will return already-added prefix route via interface that
2831 * prefix route was assigned to, which might be non-loopback.
2832 */
David Ahern232378e2018-03-13 08:29:37 -07002833 if (dev &&
2834 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2835 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002836 goto out;
2837 }
2838
2839 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2840 /* IPv6 strictly inhibits using not link-local
2841 * addresses as nexthop address.
2842 * Otherwise, router will not able to send redirects.
2843 * It is very good, but in some (rare!) circumstances
2844 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2845 * some exceptions. --ANK
2846 * We allow IPv4-mapped nexthops to support RFC4798-type
2847 * addressing
2848 */
2849 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2850 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2851 goto out;
2852 }
2853
2854 if (cfg->fc_flags & RTNH_F_ONLINK)
2855 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2856 else
2857 err = ip6_route_check_nh(net, cfg, _dev, idev);
2858
2859 if (err)
2860 goto out;
2861 }
2862
2863 /* reload in case device was changed */
2864 dev = *_dev;
2865
2866 err = -EINVAL;
2867 if (!dev) {
2868 NL_SET_ERR_MSG(extack, "Egress device not specified");
2869 goto out;
2870 } else if (dev->flags & IFF_LOOPBACK) {
2871 NL_SET_ERR_MSG(extack,
2872 "Egress device can not be loopback device for this route");
2873 goto out;
2874 }
David Ahern232378e2018-03-13 08:29:37 -07002875
2876 /* if we did not check gw_addr above, do so now that the
2877 * egress device has been resolved.
2878 */
2879 if (need_addr_check &&
2880 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2881 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2882 goto out;
2883 }
2884
David Ahern9fbb7042018-03-13 08:29:36 -07002885 err = 0;
2886out:
2887 return err;
2888}
2889
David Ahern8d1c8022018-04-17 17:33:26 -07002890static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07002891 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06002892 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893{
Daniel Lezcano55786892008-03-04 13:47:47 -08002894 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07002895 struct fib6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 struct net_device *dev = NULL;
2897 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002898 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002900 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
David Ahern557c44b2017-04-19 14:19:43 -07002902 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002903 if (cfg->fc_flags & RTF_PCPU) {
2904 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002905 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002906 }
David Ahern557c44b2017-04-19 14:19:43 -07002907
Wei Wang2ea23522017-10-27 17:30:12 -07002908 /* RTF_CACHE is an internal flag; can not be set by userspace */
2909 if (cfg->fc_flags & RTF_CACHE) {
2910 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2911 goto out;
2912 }
2913
David Aherne8478e82018-04-17 17:33:13 -07002914 if (cfg->fc_type > RTN_MAX) {
2915 NL_SET_ERR_MSG(extack, "Invalid route type");
2916 goto out;
2917 }
2918
David Ahernd5d531c2017-05-21 10:12:05 -06002919 if (cfg->fc_dst_len > 128) {
2920 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002921 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002922 }
2923 if (cfg->fc_src_len > 128) {
2924 NL_SET_ERR_MSG(extack, "Invalid source address length");
2925 goto out;
2926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002928 if (cfg->fc_src_len) {
2929 NL_SET_ERR_MSG(extack,
2930 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002931 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002934 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002936 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 if (!dev)
2938 goto out;
2939 idev = in6_dev_get(dev);
2940 if (!idev)
2941 goto out;
2942 }
2943
Thomas Graf86872cb2006-08-22 00:01:08 -07002944 if (cfg->fc_metric == 0)
2945 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
David Ahernfc1e64e2018-01-25 16:55:09 -08002947 if (cfg->fc_flags & RTNH_F_ONLINK) {
2948 if (!dev) {
2949 NL_SET_ERR_MSG(extack,
2950 "Nexthop device required for onlink");
2951 err = -ENODEV;
2952 goto out;
2953 }
2954
2955 if (!(dev->flags & IFF_UP)) {
2956 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2957 err = -ENETDOWN;
2958 goto out;
2959 }
2960 }
2961
Matti Vaittinend71314b2011-11-14 00:14:49 +00002962 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002963 if (cfg->fc_nlinfo.nlh &&
2964 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00002965 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002966 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00002967 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00002968 table = fib6_new_table(net, cfg->fc_table);
2969 }
2970 } else {
2971 table = fib6_new_table(net, cfg->fc_table);
2972 }
David S. Miller38308472011-12-03 18:02:47 -05002973
2974 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002975 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07002976
David Ahern93531c62018-04-17 17:33:25 -07002977 err = -ENOMEM;
2978 rt = fib6_info_alloc(gfp_flags);
2979 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 goto out;
David Ahern93531c62018-04-17 17:33:25 -07002981
David Ahernd7e774f2018-11-06 12:51:15 -08002982 rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
2983 extack);
David Ahern767a2212018-10-04 20:07:51 -07002984 if (IS_ERR(rt->fib6_metrics)) {
2985 err = PTR_ERR(rt->fib6_metrics);
Eric Dumazetfda21d42018-10-05 09:17:50 -07002986 /* Do not leave garbage there. */
2987 rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
David Ahern767a2212018-10-04 20:07:51 -07002988 goto out;
2989 }
2990
David Ahern93531c62018-04-17 17:33:25 -07002991 if (cfg->fc_flags & RTF_ADDRCONF)
2992 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
Gao feng1716a962012-04-06 00:13:10 +00002994 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07002995 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00002996 clock_t_to_jiffies(cfg->fc_expires));
2997 else
David Ahern14895682018-04-17 17:33:17 -07002998 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999
Thomas Graf86872cb2006-08-22 00:01:08 -07003000 if (cfg->fc_protocol == RTPROT_UNSPEC)
3001 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003002 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003003
3004 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003006 if (cfg->fc_encap) {
3007 struct lwtunnel_state *lwtstate;
3008
David Ahern30357d72017-01-30 12:07:37 -08003009 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07003010 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06003011 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003012 if (err)
3013 goto out;
David Ahern5e670d82018-04-17 17:33:14 -07003014 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003015 }
3016
David Ahern93c2fb22018-04-18 15:38:59 -07003017 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3018 rt->fib6_dst.plen = cfg->fc_dst_len;
3019 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003020 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003021
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003023 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3024 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025#endif
3026
David Ahern93c2fb22018-04-18 15:38:59 -07003027 rt->fib6_metric = cfg->fc_metric;
David Ahern5e670d82018-04-17 17:33:14 -07003028 rt->fib6_nh.nh_weight = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
David Aherne8478e82018-04-17 17:33:13 -07003030 rt->fib6_type = cfg->fc_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031
3032 /* We cannot add true routes via loopback here,
3033 they would result in kernel looping; promote them to reject routes
3034 */
Thomas Graf86872cb2006-08-22 00:01:08 -07003035 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05003036 (dev && (dev->flags & IFF_LOOPBACK) &&
3037 !(addr_type & IPV6_ADDR_LOOPBACK) &&
3038 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08003040 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 if (dev) {
3042 dev_put(dev);
3043 in6_dev_put(idev);
3044 }
Daniel Lezcano55786892008-03-04 13:47:47 -08003045 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 dev_hold(dev);
3047 idev = in6_dev_get(dev);
3048 if (!idev) {
3049 err = -ENODEV;
3050 goto out;
3051 }
3052 }
David Ahern93c2fb22018-04-18 15:38:59 -07003053 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 goto install_route;
3055 }
3056
Thomas Graf86872cb2006-08-22 00:01:08 -07003057 if (cfg->fc_flags & RTF_GATEWAY) {
David Ahern9fbb7042018-03-13 08:29:36 -07003058 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3059 if (err)
Florian Westphal48ed7b22015-05-21 00:25:41 +02003060 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
David Ahern93531c62018-04-17 17:33:25 -07003062 rt->fib6_nh.nh_gw = cfg->fc_gateway;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 }
3064
3065 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05003066 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 goto out;
3068
Lorenzo Bianconi428604f2018-03-29 11:02:24 +02003069 if (idev->cnf.disable_ipv6) {
3070 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3071 err = -EACCES;
3072 goto out;
3073 }
3074
David Ahern955ec4c2018-01-24 19:45:29 -08003075 if (!(dev->flags & IFF_UP)) {
3076 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3077 err = -ENETDOWN;
3078 goto out;
3079 }
3080
Daniel Walterc3968a82011-04-13 21:10:57 +00003081 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
3082 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003083 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003084 err = -EINVAL;
3085 goto out;
3086 }
David Ahern93c2fb22018-04-18 15:38:59 -07003087 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3088 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003089 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003090 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003091
David Ahern93c2fb22018-04-18 15:38:59 -07003092 rt->fib6_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
3094install_route:
David Ahern93c2fb22018-04-18 15:38:59 -07003095 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
Ido Schimmel5609b802018-01-07 12:45:06 +02003096 !netif_carrier_ok(dev))
David Ahern5e670d82018-04-17 17:33:14 -07003097 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
3098 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
David Ahern93531c62018-04-17 17:33:25 -07003099 rt->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07003100 rt->fib6_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003101
David Aherndcd1f572018-04-18 15:39:05 -07003102 if (idev)
3103 in6_dev_put(idev);
3104
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003105 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106out:
3107 if (dev)
3108 dev_put(dev);
3109 if (idev)
3110 in6_dev_put(idev);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003111
David Ahern93531c62018-04-17 17:33:25 -07003112 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003113 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003114}
3115
David Ahernacb54e32018-04-17 17:33:22 -07003116int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003117 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003118{
David Ahern8d1c8022018-04-17 17:33:26 -07003119 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003120 int err;
3121
David Ahernacb54e32018-04-17 17:33:22 -07003122 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003123 if (IS_ERR(rt))
3124 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003125
David Ahernd4ead6b2018-04-17 17:33:16 -07003126 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003127 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003128
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 return err;
3130}
3131
David Ahern8d1c8022018-04-17 17:33:26 -07003132static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133{
David Ahernafb1d4b52018-04-17 17:33:11 -07003134 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003135 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003136 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
David Ahern421842e2018-04-17 17:33:18 -07003138 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003139 err = -ENOENT;
3140 goto out;
3141 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003142
David Ahern93c2fb22018-04-18 15:38:59 -07003143 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003144 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003145 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003146 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147
Gao feng6825a262012-09-19 19:25:34 +00003148out:
David Ahern93531c62018-04-17 17:33:25 -07003149 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 return err;
3151}
3152
David Ahern8d1c8022018-04-17 17:33:26 -07003153int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003154{
David Ahernafb1d4b52018-04-17 17:33:11 -07003155 struct nl_info info = { .nl_net = net };
3156
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003157 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003158}
3159
David Ahern8d1c8022018-04-17 17:33:26 -07003160static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003161{
3162 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003163 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003164 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003165 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003166 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003167
David Ahern421842e2018-04-17 17:33:18 -07003168 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003169 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003170 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003171 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003172
David Ahern93c2fb22018-04-18 15:38:59 -07003173 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003174 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003175
David Ahern16a16cd2017-02-02 12:37:11 -08003176 /* prefer to send a single notification with all hops */
3177 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3178 if (skb) {
3179 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3180
David Ahernd4ead6b2018-04-17 17:33:16 -07003181 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003182 NULL, NULL, 0, RTM_DELROUTE,
3183 info->portid, seq, 0) < 0) {
3184 kfree_skb(skb);
3185 skb = NULL;
3186 } else
3187 info->skip_notify = 1;
3188 }
3189
David Ahern0ae81332017-02-02 12:37:08 -08003190 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003191 &rt->fib6_siblings,
3192 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003193 err = fib6_del(sibling, info);
3194 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003195 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003196 }
3197 }
3198
3199 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003200out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003201 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003202out_put:
David Ahern93531c62018-04-17 17:33:25 -07003203 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003204
3205 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003206 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003207 info->nlh, gfp_any());
3208 }
David Ahern0ae81332017-02-02 12:37:08 -08003209 return err;
3210}
3211
David Ahern23fb93a2018-04-17 17:33:23 -07003212static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3213{
3214 int rc = -ESRCH;
3215
3216 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3217 goto out;
3218
3219 if (cfg->fc_flags & RTF_GATEWAY &&
3220 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3221 goto out;
Xin Long761f6022018-11-14 00:48:28 +08003222
3223 rc = rt6_remove_exception_rt(rt);
David Ahern23fb93a2018-04-17 17:33:23 -07003224out:
3225 return rc;
3226}
3227
David Ahern333c4302017-05-21 10:12:04 -06003228static int ip6_route_del(struct fib6_config *cfg,
3229 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230{
David Ahern8d1c8022018-04-17 17:33:26 -07003231 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003232 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003233 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 int err = -ESRCH;
3236
Daniel Lezcano55786892008-03-04 13:47:47 -08003237 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003238 if (!table) {
3239 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003240 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
Wei Wang66f5d6c2017-10-06 12:06:10 -07003243 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003244
3245 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003246 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003247 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003248 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003249
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003251 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003252 if (cfg->fc_flags & RTF_CACHE) {
David Ahern23fb93a2018-04-17 17:33:23 -07003253 int rc;
3254
Wei Wang2b760fc2017-10-06 12:06:03 -07003255 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
3256 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003257 if (rt_cache) {
3258 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003259 if (rc != -ESRCH) {
3260 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003261 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003262 }
David Ahern23fb93a2018-04-17 17:33:23 -07003263 }
3264 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003265 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003266 if (cfg->fc_ifindex &&
David Ahern5e670d82018-04-17 17:33:14 -07003267 (!rt->fib6_nh.nh_dev ||
3268 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003270 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahern5e670d82018-04-17 17:33:14 -07003271 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003273 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003275 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003276 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003277 if (!fib6_info_hold_safe(rt))
3278 continue;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003279 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
David Ahern0ae81332017-02-02 12:37:08 -08003281 /* if gateway was specified only delete the one hop */
3282 if (cfg->fc_flags & RTF_GATEWAY)
3283 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3284
3285 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 }
3287 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003288 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
3290 return err;
3291}
3292
David S. Miller6700c272012-07-17 03:29:28 -07003293static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003294{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003295 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003296 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003297 struct ndisc_options ndopts;
3298 struct inet6_dev *in6_dev;
3299 struct neighbour *neigh;
David Aherna68886a2018-04-20 15:38:02 -07003300 struct fib6_info *from;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003301 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003302 int optlen, on_link;
3303 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003304
Simon Horman29a3cad2013-05-28 20:34:26 +00003305 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003306 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003307
3308 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003309 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003310 return;
3311 }
3312
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003313 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003314
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003315 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003316 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003317 return;
3318 }
3319
David S. Miller6e157b62012-07-12 00:05:02 -07003320 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003321 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003322 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003323 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003324 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003325 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003326 return;
3327 }
3328
3329 in6_dev = __in6_dev_get(skb->dev);
3330 if (!in6_dev)
3331 return;
3332 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3333 return;
3334
3335 /* RFC2461 8.1:
3336 * The IP source address of the Redirect MUST be the same as the current
3337 * first-hop router for the specified ICMP Destination Address.
3338 */
3339
Alexander Aringf997c552016-06-15 21:20:23 +02003340 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003341 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3342 return;
3343 }
David S. Miller6e157b62012-07-12 00:05:02 -07003344
3345 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003346 if (ndopts.nd_opts_tgt_lladdr) {
3347 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3348 skb->dev);
3349 if (!lladdr) {
3350 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3351 return;
3352 }
3353 }
3354
David S. Miller6e157b62012-07-12 00:05:02 -07003355 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003356 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003357 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3358 return;
3359 }
3360
3361 /* Redirect received -> path was valid.
3362 * Look, redirects are sent only in response to data packets,
3363 * so that this nexthop apparently is reachable. --ANK
3364 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003365 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003366
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003367 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003368 if (!neigh)
3369 return;
3370
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 /*
3372 * We have finally decided to accept it.
3373 */
3374
Alexander Aringf997c552016-06-15 21:20:23 +02003375 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3377 NEIGH_UPDATE_F_OVERRIDE|
3378 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003379 NEIGH_UPDATE_F_ISROUTER)),
3380 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381
David Ahern4d85cd02018-04-20 15:37:59 -07003382 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07003383 from = rcu_dereference(rt->from);
Wei Wange873e4b2018-07-21 20:56:32 -07003384 /* This fib6_info_hold() is safe here because we hold reference to rt
3385 * and rt already holds reference to fib6_info.
3386 */
David Ahern8a14e462018-04-23 11:32:07 -07003387 fib6_info_hold(from);
David Ahern4d85cd02018-04-20 15:37:59 -07003388 rcu_read_unlock();
David Ahern8a14e462018-04-23 11:32:07 -07003389
3390 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003391 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 goto out;
3393
3394 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3395 if (on_link)
3396 nrt->rt6i_flags &= ~RTF_GATEWAY;
3397
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003398 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399
Wei Wang2b760fc2017-10-06 12:06:03 -07003400 /* No need to remove rt from the exception table if rt is
3401 * a cached route because rt6_insert_exception() will
3402 * takes care of it
3403 */
David Ahern8a14e462018-04-23 11:32:07 -07003404 if (rt6_insert_exception(nrt, from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003405 dst_release_immediate(&nrt->dst);
3406 goto out;
3407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
Changli Gaod8d1f302010-06-10 23:31:35 -07003409 netevent.old = &rt->dst;
3410 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003411 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003412 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003413 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3414
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415out:
David Ahern8a14e462018-04-23 11:32:07 -07003416 fib6_info_release(from);
David S. Millere8599ff2012-07-11 23:43:53 -07003417 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003418}
3419
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003420#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003421static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003422 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003423 const struct in6_addr *gwaddr,
3424 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003425{
David Ahern830218c2016-10-24 10:52:35 -07003426 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3427 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003428 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003429 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003430 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003431
David Ahern830218c2016-10-24 10:52:35 -07003432 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003433 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003434 return NULL;
3435
Wei Wang66f5d6c2017-10-06 12:06:10 -07003436 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003437 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003438 if (!fn)
3439 goto out;
3440
Wei Wang66f5d6c2017-10-06 12:06:10 -07003441 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07003442 if (rt->fib6_nh.nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003443 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003444 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003445 continue;
David Ahern5e670d82018-04-17 17:33:14 -07003446 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003447 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003448 if (!fib6_info_hold_safe(rt))
3449 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003450 break;
3451 }
3452out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003453 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003454 return rt;
3455}
3456
David Ahern8d1c8022018-04-17 17:33:26 -07003457static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003458 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003459 const struct in6_addr *gwaddr,
3460 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003461 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003462{
Thomas Graf86872cb2006-08-22 00:01:08 -07003463 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003464 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003465 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003466 .fc_dst_len = prefixlen,
3467 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3468 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003469 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003470 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003471 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003472 .fc_nlinfo.nlh = NULL,
3473 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003474 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003475
David Ahern830218c2016-10-24 10:52:35 -07003476 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003477 cfg.fc_dst = *prefix;
3478 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003479
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003480 /* We should treat it as a default route if prefix length is 0. */
3481 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003482 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003483
David Ahernacb54e32018-04-17 17:33:22 -07003484 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003485
David Ahern830218c2016-10-24 10:52:35 -07003486 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003487}
3488#endif
3489
David Ahern8d1c8022018-04-17 17:33:26 -07003490struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003491 const struct in6_addr *addr,
3492 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003493{
David Ahern830218c2016-10-24 10:52:35 -07003494 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003495 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003496 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
David Ahernafb1d4b52018-04-17 17:33:11 -07003498 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003499 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003500 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
Wei Wang66f5d6c2017-10-06 12:06:10 -07003502 rcu_read_lock();
3503 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern5e670d82018-04-17 17:33:14 -07003504 if (dev == rt->fib6_nh.nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003505 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahern5e670d82018-04-17 17:33:14 -07003506 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 break;
3508 }
Wei Wange873e4b2018-07-21 20:56:32 -07003509 if (rt && !fib6_info_hold_safe(rt))
3510 rt = NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003511 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 return rt;
3513}
3514
David Ahern8d1c8022018-04-17 17:33:26 -07003515struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003516 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003517 struct net_device *dev,
3518 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519{
Thomas Graf86872cb2006-08-22 00:01:08 -07003520 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003521 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003522 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003523 .fc_ifindex = dev->ifindex,
3524 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3525 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003526 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003527 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003528 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003529 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003530 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003531 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003533 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
David Ahernacb54e32018-04-17 17:33:22 -07003535 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003536 struct fib6_table *table;
3537
3538 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3539 if (table)
3540 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
David Ahernafb1d4b52018-04-17 17:33:11 -07003543 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544}
3545
David Ahernafb1d4b52018-04-17 17:33:11 -07003546static void __rt6_purge_dflt_routers(struct net *net,
3547 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548{
David Ahern8d1c8022018-04-17 17:33:26 -07003549 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
3551restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003552 rcu_read_lock();
3553 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003554 struct net_device *dev = fib6_info_nh_dev(rt);
3555 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3556
David Ahern93c2fb22018-04-18 15:38:59 -07003557 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
Wei Wange873e4b2018-07-21 20:56:32 -07003558 (!idev || idev->cnf.accept_ra != 2) &&
3559 fib6_info_hold_safe(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07003560 rcu_read_unlock();
3561 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 goto restart;
3563 }
3564 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003565 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003566
3567 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3568}
3569
3570void rt6_purge_dflt_routers(struct net *net)
3571{
3572 struct fib6_table *table;
3573 struct hlist_head *head;
3574 unsigned int h;
3575
3576 rcu_read_lock();
3577
3578 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3579 head = &net->ipv6.fib_table_hash[h];
3580 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3581 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003582 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003583 }
3584 }
3585
3586 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587}
3588
Daniel Lezcano55786892008-03-04 13:47:47 -08003589static void rtmsg_to_fib6_config(struct net *net,
3590 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003591 struct fib6_config *cfg)
3592{
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003593 *cfg = (struct fib6_config){
3594 .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3595 : RT6_TABLE_MAIN,
3596 .fc_ifindex = rtmsg->rtmsg_ifindex,
3597 .fc_metric = rtmsg->rtmsg_metric,
3598 .fc_expires = rtmsg->rtmsg_info,
3599 .fc_dst_len = rtmsg->rtmsg_dst_len,
3600 .fc_src_len = rtmsg->rtmsg_src_len,
3601 .fc_flags = rtmsg->rtmsg_flags,
3602 .fc_type = rtmsg->rtmsg_type,
Thomas Graf86872cb2006-08-22 00:01:08 -07003603
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003604 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003605
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003606 .fc_dst = rtmsg->rtmsg_dst,
3607 .fc_src = rtmsg->rtmsg_src,
3608 .fc_gateway = rtmsg->rtmsg_gateway,
3609 };
Thomas Graf86872cb2006-08-22 00:01:08 -07003610}
3611
Daniel Lezcano55786892008-03-04 13:47:47 -08003612int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613{
Thomas Graf86872cb2006-08-22 00:01:08 -07003614 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 struct in6_rtmsg rtmsg;
3616 int err;
3617
Ian Morris67ba4152014-08-24 21:53:10 +01003618 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 case SIOCADDRT: /* Add a route */
3620 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003621 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 return -EPERM;
3623 err = copy_from_user(&rtmsg, arg,
3624 sizeof(struct in6_rtmsg));
3625 if (err)
3626 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003627
Daniel Lezcano55786892008-03-04 13:47:47 -08003628 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003629
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 rtnl_lock();
3631 switch (cmd) {
3632 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003633 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 break;
3635 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003636 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 break;
3638 default:
3639 err = -EINVAL;
3640 }
3641 rtnl_unlock();
3642
3643 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645
3646 return -EINVAL;
3647}
3648
3649/*
3650 * Drop the packet on the floor
3651 */
3652
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003653static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003655 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003656 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003657 switch (ipstats_mib_noroutes) {
3658 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003659 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003660 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003661 IP6_INC_STATS(dev_net(dst->dev),
3662 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003663 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003664 break;
3665 }
3666 /* FALLTHROUGH */
3667 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003668 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3669 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003670 break;
3671 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003672 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 kfree_skb(skb);
3674 return 0;
3675}
3676
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003677static int ip6_pkt_discard(struct sk_buff *skb)
3678{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003679 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003680}
3681
Eric W. Biedermanede20592015-10-07 16:48:47 -05003682static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683{
Eric Dumazetadf30902009-06-02 05:19:30 +00003684 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003685 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686}
3687
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003688static int ip6_pkt_prohibit(struct sk_buff *skb)
3689{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003690 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003691}
3692
Eric W. Biedermanede20592015-10-07 16:48:47 -05003693static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003694{
Eric Dumazetadf30902009-06-02 05:19:30 +00003695 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003696 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003697}
3698
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699/*
3700 * Allocate a dst for local (unicast / anycast) address.
3701 */
3702
David Ahern360a9882018-04-18 15:39:00 -07003703struct fib6_info *addrconf_f6i_alloc(struct net *net,
3704 struct inet6_dev *idev,
3705 const struct in6_addr *addr,
3706 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707{
David Ahernca254492015-10-12 11:47:10 -07003708 u32 tb_id;
David Ahern4832c302017-08-17 12:17:20 -07003709 struct net_device *dev = idev->dev;
David Ahern360a9882018-04-18 15:39:00 -07003710 struct fib6_info *f6i;
David Ahern5f02ce242016-09-10 12:09:54 -07003711
David Ahern360a9882018-04-18 15:39:00 -07003712 f6i = fib6_info_alloc(gfp_flags);
3713 if (!f6i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 return ERR_PTR(-ENOMEM);
3715
David Ahernd7e774f2018-11-06 12:51:15 -08003716 f6i->fib6_metrics = ip_fib_metrics_init(net, NULL, 0, NULL);
David Ahern360a9882018-04-18 15:39:00 -07003717 f6i->dst_nocount = true;
David Ahern360a9882018-04-18 15:39:00 -07003718 f6i->dst_host = true;
3719 f6i->fib6_protocol = RTPROT_KERNEL;
3720 f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
David Aherne8478e82018-04-17 17:33:13 -07003721 if (anycast) {
David Ahern360a9882018-04-18 15:39:00 -07003722 f6i->fib6_type = RTN_ANYCAST;
3723 f6i->fib6_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003724 } else {
David Ahern360a9882018-04-18 15:39:00 -07003725 f6i->fib6_type = RTN_LOCAL;
3726 f6i->fib6_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
David Ahern360a9882018-04-18 15:39:00 -07003729 f6i->fib6_nh.nh_gw = *addr;
David Ahern93531c62018-04-17 17:33:25 -07003730 dev_hold(dev);
David Ahern360a9882018-04-18 15:39:00 -07003731 f6i->fib6_nh.nh_dev = dev;
3732 f6i->fib6_dst.addr = *addr;
3733 f6i->fib6_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003734 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
David Ahern360a9882018-04-18 15:39:00 -07003735 f6i->fib6_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736
David Ahern360a9882018-04-18 15:39:00 -07003737 return f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738}
3739
Daniel Walterc3968a82011-04-13 21:10:57 +00003740/* remove deleted ip from prefsrc entries */
3741struct arg_dev_net_ip {
3742 struct net_device *dev;
3743 struct net *net;
3744 struct in6_addr *addr;
3745};
3746
David Ahern8d1c8022018-04-17 17:33:26 -07003747static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003748{
3749 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3750 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3751 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3752
David Ahern5e670d82018-04-17 17:33:14 -07003753 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003754 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003755 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003756 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003757 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003758 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003759 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003760 }
3761 return 0;
3762}
3763
3764void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3765{
3766 struct net *net = dev_net(ifp->idev->dev);
3767 struct arg_dev_net_ip adni = {
3768 .dev = ifp->idev->dev,
3769 .net = net,
3770 .addr = &ifp->addr,
3771 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003772 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003773}
3774
Duan Jiongbe7a0102014-05-15 15:56:14 +08003775#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003776
3777/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003778static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003779{
3780 struct in6_addr *gateway = (struct in6_addr *)arg;
3781
David Ahern93c2fb22018-04-18 15:38:59 -07003782 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahern5e670d82018-04-17 17:33:14 -07003783 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003784 return -1;
3785 }
Wei Wangb16cb452017-10-06 12:06:00 -07003786
3787 /* Further clean up cached routes in exception table.
3788 * This is needed because cached route may have a different
3789 * gateway than its 'parent' in the case of an ip redirect.
3790 */
3791 rt6_exceptions_clean_tohost(rt, gateway);
3792
Duan Jiongbe7a0102014-05-15 15:56:14 +08003793 return 0;
3794}
3795
3796void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3797{
3798 fib6_clean_all(net, fib6_clean_tohost, gateway);
3799}
3800
Ido Schimmel2127d952018-01-07 12:45:03 +02003801struct arg_netdev_event {
3802 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003803 union {
3804 unsigned int nh_flags;
3805 unsigned long event;
3806 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003807};
3808
David Ahern8d1c8022018-04-17 17:33:26 -07003809static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003810{
David Ahern8d1c8022018-04-17 17:33:26 -07003811 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003812 struct fib6_node *fn;
3813
David Ahern93c2fb22018-04-18 15:38:59 -07003814 fn = rcu_dereference_protected(rt->fib6_node,
3815 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003816 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003817 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003818 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003819 if (iter->fib6_metric == rt->fib6_metric &&
David Ahern33bd5ac2018-07-03 14:36:21 -07003820 rt6_qualify_for_ecmp(iter))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003821 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003822 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003823 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003824 }
3825
3826 return NULL;
3827}
3828
David Ahern8d1c8022018-04-17 17:33:26 -07003829static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003830{
David Ahern5e670d82018-04-17 17:33:14 -07003831 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
3832 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Aherndcd1f572018-04-18 15:39:05 -07003833 fib6_ignore_linkdown(rt)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003834 return true;
3835
3836 return false;
3837}
3838
David Ahern8d1c8022018-04-17 17:33:26 -07003839static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003840{
David Ahern8d1c8022018-04-17 17:33:26 -07003841 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003842 int total = 0;
3843
3844 if (!rt6_is_dead(rt))
David Ahern5e670d82018-04-17 17:33:14 -07003845 total += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003846
David Ahern93c2fb22018-04-18 15:38:59 -07003847 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003848 if (!rt6_is_dead(iter))
David Ahern5e670d82018-04-17 17:33:14 -07003849 total += iter->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003850 }
3851
3852 return total;
3853}
3854
David Ahern8d1c8022018-04-17 17:33:26 -07003855static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003856{
3857 int upper_bound = -1;
3858
3859 if (!rt6_is_dead(rt)) {
David Ahern5e670d82018-04-17 17:33:14 -07003860 *weight += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003861 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3862 total) - 1;
3863 }
David Ahern5e670d82018-04-17 17:33:14 -07003864 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003865}
3866
David Ahern8d1c8022018-04-17 17:33:26 -07003867static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003868{
David Ahern8d1c8022018-04-17 17:33:26 -07003869 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003870 int weight = 0;
3871
3872 rt6_upper_bound_set(rt, &weight, total);
3873
David Ahern93c2fb22018-04-18 15:38:59 -07003874 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003875 rt6_upper_bound_set(iter, &weight, total);
3876}
3877
David Ahern8d1c8022018-04-17 17:33:26 -07003878void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003879{
David Ahern8d1c8022018-04-17 17:33:26 -07003880 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003881 int total;
3882
3883 /* In case the entire multipath route was marked for flushing,
3884 * then there is no need to rebalance upon the removal of every
3885 * sibling route.
3886 */
David Ahern93c2fb22018-04-18 15:38:59 -07003887 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003888 return;
3889
3890 /* During lookup routes are evaluated in order, so we need to
3891 * make sure upper bounds are assigned from the first sibling
3892 * onwards.
3893 */
3894 first = rt6_multipath_first_sibling(rt);
3895 if (WARN_ON_ONCE(!first))
3896 return;
3897
3898 total = rt6_multipath_total_weight(first);
3899 rt6_multipath_upper_bound_set(first, total);
3900}
3901
David Ahern8d1c8022018-04-17 17:33:26 -07003902static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003903{
3904 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003905 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003906
David Ahern421842e2018-04-17 17:33:18 -07003907 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
David Ahern5e670d82018-04-17 17:33:14 -07003908 rt->fib6_nh.nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003909 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003910 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003911 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003912
3913 return 0;
3914}
3915
3916void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3917{
3918 struct arg_netdev_event arg = {
3919 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003920 {
3921 .nh_flags = nh_flags,
3922 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003923 };
3924
3925 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3926 arg.nh_flags |= RTNH_F_LINKDOWN;
3927
3928 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3929}
3930
David Ahern8d1c8022018-04-17 17:33:26 -07003931static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003932 const struct net_device *dev)
3933{
David Ahern8d1c8022018-04-17 17:33:26 -07003934 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003935
David Ahern5e670d82018-04-17 17:33:14 -07003936 if (rt->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003937 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07003938 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003939 if (iter->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003940 return true;
3941
3942 return false;
3943}
3944
David Ahern8d1c8022018-04-17 17:33:26 -07003945static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003946{
David Ahern8d1c8022018-04-17 17:33:26 -07003947 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003948
3949 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07003950 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003951 iter->should_flush = 1;
3952}
3953
David Ahern8d1c8022018-04-17 17:33:26 -07003954static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003955 const struct net_device *down_dev)
3956{
David Ahern8d1c8022018-04-17 17:33:26 -07003957 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003958 unsigned int dead = 0;
3959
David Ahern5e670d82018-04-17 17:33:14 -07003960 if (rt->fib6_nh.nh_dev == down_dev ||
3961 rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003962 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07003963 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003964 if (iter->fib6_nh.nh_dev == down_dev ||
3965 iter->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003966 dead++;
3967
3968 return dead;
3969}
3970
David Ahern8d1c8022018-04-17 17:33:26 -07003971static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003972 const struct net_device *dev,
3973 unsigned int nh_flags)
3974{
David Ahern8d1c8022018-04-17 17:33:26 -07003975 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003976
David Ahern5e670d82018-04-17 17:33:14 -07003977 if (rt->fib6_nh.nh_dev == dev)
3978 rt->fib6_nh.nh_flags |= nh_flags;
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 == dev)
3981 iter->fib6_nh.nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003982}
3983
David Aherna1a22c12017-01-18 07:40:36 -08003984/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07003985static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986{
Ido Schimmel4c981e22018-01-07 12:45:04 +02003987 const struct arg_netdev_event *arg = p_arg;
3988 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07003989 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003990
David Ahern421842e2018-04-17 17:33:18 -07003991 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003992 return 0;
3993
3994 switch (arg->event) {
3995 case NETDEV_UNREGISTER:
David Ahern5e670d82018-04-17 17:33:14 -07003996 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003997 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02003998 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003999 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004000 if (!rt->fib6_nsiblings)
David Ahern5e670d82018-04-17 17:33:14 -07004001 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004002 if (rt6_multipath_uses_dev(rt, dev)) {
4003 unsigned int count;
4004
4005 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004006 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004007 rt6_multipath_flush(rt);
4008 return -1;
4009 }
4010 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4011 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004012 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004013 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004014 }
4015 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004016 case NETDEV_CHANGE:
David Ahern5e670d82018-04-17 17:33:14 -07004017 if (rt->fib6_nh.nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004018 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004019 break;
David Ahern5e670d82018-04-17 17:33:14 -07004020 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004021 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004022 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004023 }
David S. Millerc159d302011-12-26 15:24:36 -05004024
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 return 0;
4026}
4027
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004028void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004030 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004031 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004032 {
4033 .event = event,
4034 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004035 };
David Ahern7c6bb7d2018-10-11 20:17:21 -07004036 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004037
David Ahern7c6bb7d2018-10-11 20:17:21 -07004038 if (net->ipv6.sysctl.skip_notify_on_dev_down)
4039 fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
4040 else
4041 fib6_clean_all(net, fib6_ifdown, &arg);
Ido Schimmel4c981e22018-01-07 12:45:04 +02004042}
4043
4044void rt6_disable_ip(struct net_device *dev, unsigned long event)
4045{
4046 rt6_sync_down_dev(dev, event);
4047 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4048 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049}
4050
Eric Dumazet95c96172012-04-15 05:58:06 +00004051struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004053 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054};
4055
David Ahern8d1c8022018-04-17 17:33:26 -07004056static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057{
4058 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4059 struct inet6_dev *idev;
4060
4061 /* In IPv6 pmtu discovery is not optional,
4062 so that RTAX_MTU lock cannot disable it.
4063 We still use this lock to block changes
4064 caused by addrconf/ndisc.
4065 */
4066
4067 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004068 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 return 0;
4070
4071 /* For administrative MTU increase, there is no way to discover
4072 IPv6 PMTU increase, so PMTU increase should be updated here.
4073 Since RFC 1981 doesn't include administrative MTU increase
4074 update PMTU increase is a MUST. (i.e. jumbo frame)
4075 */
David Ahern5e670d82018-04-17 17:33:14 -07004076 if (rt->fib6_nh.nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004077 !fib6_metric_locked(rt, RTAX_MTU)) {
4078 u32 mtu = rt->fib6_pmtu;
4079
4080 if (mtu >= arg->mtu ||
4081 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4082 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4083
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004084 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004085 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004086 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 return 0;
4089}
4090
Eric Dumazet95c96172012-04-15 05:58:06 +00004091void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092{
Thomas Grafc71099a2006-08-04 23:20:06 -07004093 struct rt6_mtu_change_arg arg = {
4094 .dev = dev,
4095 .mtu = mtu,
4096 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097
Li RongQing0c3584d2013-12-27 16:32:38 +08004098 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099}
4100
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004101static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004102 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004103 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004104 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004105 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004106 [RTA_PRIORITY] = { .type = NLA_U32 },
4107 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004108 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004109 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004110 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4111 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004112 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004113 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004114 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004115 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004116 [RTA_IP_PROTO] = { .type = NLA_U8 },
4117 [RTA_SPORT] = { .type = NLA_U16 },
4118 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004119};
4120
4121static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004122 struct fib6_config *cfg,
4123 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124{
Thomas Graf86872cb2006-08-22 00:01:08 -07004125 struct rtmsg *rtm;
4126 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004127 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004128 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129
Johannes Bergfceb6432017-04-12 14:34:07 +02004130 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Aherndac9c972018-10-07 20:16:24 -07004131 extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004132 if (err < 0)
4133 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
Thomas Graf86872cb2006-08-22 00:01:08 -07004135 err = -EINVAL;
4136 rtm = nlmsg_data(nlh);
Thomas Graf86872cb2006-08-22 00:01:08 -07004137
Maciej Żenczykowski84db8402018-09-29 23:44:53 -07004138 *cfg = (struct fib6_config){
4139 .fc_table = rtm->rtm_table,
4140 .fc_dst_len = rtm->rtm_dst_len,
4141 .fc_src_len = rtm->rtm_src_len,
4142 .fc_flags = RTF_UP,
4143 .fc_protocol = rtm->rtm_protocol,
4144 .fc_type = rtm->rtm_type,
4145
4146 .fc_nlinfo.portid = NETLINK_CB(skb).portid,
4147 .fc_nlinfo.nlh = nlh,
4148 .fc_nlinfo.nl_net = sock_net(skb->sk),
4149 };
Thomas Graf86872cb2006-08-22 00:01:08 -07004150
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004151 if (rtm->rtm_type == RTN_UNREACHABLE ||
4152 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004153 rtm->rtm_type == RTN_PROHIBIT ||
4154 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004155 cfg->fc_flags |= RTF_REJECT;
4156
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004157 if (rtm->rtm_type == RTN_LOCAL)
4158 cfg->fc_flags |= RTF_LOCAL;
4159
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004160 if (rtm->rtm_flags & RTM_F_CLONED)
4161 cfg->fc_flags |= RTF_CACHE;
4162
David Ahernfc1e64e2018-01-25 16:55:09 -08004163 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4164
Thomas Graf86872cb2006-08-22 00:01:08 -07004165 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004166 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004167 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004169
4170 if (tb[RTA_DST]) {
4171 int plen = (rtm->rtm_dst_len + 7) >> 3;
4172
4173 if (nla_len(tb[RTA_DST]) < plen)
4174 goto errout;
4175
4176 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004178
4179 if (tb[RTA_SRC]) {
4180 int plen = (rtm->rtm_src_len + 7) >> 3;
4181
4182 if (nla_len(tb[RTA_SRC]) < plen)
4183 goto errout;
4184
4185 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004187
Daniel Walterc3968a82011-04-13 21:10:57 +00004188 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004189 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004190
Thomas Graf86872cb2006-08-22 00:01:08 -07004191 if (tb[RTA_OIF])
4192 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4193
4194 if (tb[RTA_PRIORITY])
4195 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4196
4197 if (tb[RTA_METRICS]) {
4198 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4199 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004201
4202 if (tb[RTA_TABLE])
4203 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4204
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004205 if (tb[RTA_MULTIPATH]) {
4206 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4207 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004208
4209 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004210 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004211 if (err < 0)
4212 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004213 }
4214
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004215 if (tb[RTA_PREF]) {
4216 pref = nla_get_u8(tb[RTA_PREF]);
4217 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4218 pref != ICMPV6_ROUTER_PREF_HIGH)
4219 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4220 cfg->fc_flags |= RTF_PREF(pref);
4221 }
4222
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004223 if (tb[RTA_ENCAP])
4224 cfg->fc_encap = tb[RTA_ENCAP];
4225
David Ahern9ed59592017-01-17 14:57:36 -08004226 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004227 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4228
David Ahernc255bd62017-05-27 16:19:27 -06004229 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004230 if (err < 0)
4231 goto errout;
4232 }
4233
Xin Long32bc2012015-12-16 17:50:11 +08004234 if (tb[RTA_EXPIRES]) {
4235 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4236
4237 if (addrconf_finite_timeout(timeout)) {
4238 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4239 cfg->fc_flags |= RTF_EXPIRES;
4240 }
4241 }
4242
Thomas Graf86872cb2006-08-22 00:01:08 -07004243 err = 0;
4244errout:
4245 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246}
4247
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004248struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004249 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004250 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004251 struct list_head next;
4252};
4253
David Ahernd4ead6b2018-04-17 17:33:16 -07004254static int ip6_route_info_append(struct net *net,
4255 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004256 struct fib6_info *rt,
4257 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004258{
4259 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004260 int err = -EEXIST;
4261
4262 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004263 /* check if fib6_info already exists */
4264 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004265 return err;
4266 }
4267
4268 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4269 if (!nh)
4270 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004271 nh->fib6_info = rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004272 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4273 list_add_tail(&nh->next, rt6_nh_list);
4274
4275 return 0;
4276}
4277
David Ahern8d1c8022018-04-17 17:33:26 -07004278static void ip6_route_mpath_notify(struct fib6_info *rt,
4279 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004280 struct nl_info *info,
4281 __u16 nlflags)
4282{
4283 /* if this is an APPEND route, then rt points to the first route
4284 * inserted and rt_last points to last route inserted. Userspace
4285 * wants a consistent dump of the route which starts at the first
4286 * nexthop. Since sibling routes are always added at the end of
4287 * the list, find the first sibling of the last route appended
4288 */
David Ahern93c2fb22018-04-18 15:38:59 -07004289 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4290 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004291 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004292 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004293 }
4294
4295 if (rt)
4296 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4297}
4298
David Ahern333c4302017-05-21 10:12:04 -06004299static int ip6_route_multipath_add(struct fib6_config *cfg,
4300 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004301{
David Ahern8d1c8022018-04-17 17:33:26 -07004302 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004303 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004304 struct fib6_config r_cfg;
4305 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004306 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004307 struct rt6_nh *err_nh;
4308 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004309 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004310 int remaining;
4311 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004312 int err = 1;
4313 int nhn = 0;
4314 int replace = (cfg->fc_nlinfo.nlh &&
4315 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4316 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004317
David Ahern3b1137f2017-02-02 12:37:10 -08004318 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4319 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4320 nlflags |= NLM_F_APPEND;
4321
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004322 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004323 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004324
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004325 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004326 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004327 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004328 while (rtnh_ok(rtnh, remaining)) {
4329 memcpy(&r_cfg, cfg, sizeof(*cfg));
4330 if (rtnh->rtnh_ifindex)
4331 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4332
4333 attrlen = rtnh_attrlen(rtnh);
4334 if (attrlen > 0) {
4335 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4336
4337 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4338 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004339 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004340 r_cfg.fc_flags |= RTF_GATEWAY;
4341 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004342 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4343 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4344 if (nla)
4345 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004346 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004347
David Ahern68e2ffd2018-03-20 10:06:59 -07004348 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004349 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004350 if (IS_ERR(rt)) {
4351 err = PTR_ERR(rt);
4352 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004353 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004354 }
David Ahernb5d2d752018-07-15 09:35:19 -07004355 if (!rt6_qualify_for_ecmp(rt)) {
4356 err = -EINVAL;
4357 NL_SET_ERR_MSG(extack,
4358 "Device only routes can not be added for IPv6 using the multipath API.");
4359 fib6_info_release(rt);
4360 goto cleanup;
4361 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004362
David Ahern5e670d82018-04-17 17:33:14 -07004363 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004364
David Ahernd4ead6b2018-04-17 17:33:16 -07004365 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4366 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004367 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004368 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004369 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004370 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004371
4372 rtnh = rtnh_next(rtnh, &remaining);
4373 }
4374
David Ahern3b1137f2017-02-02 12:37:10 -08004375 /* for add and replace send one notification with all nexthops.
4376 * Skip the notification in fib6_add_rt2node and send one with
4377 * the full route when done
4378 */
4379 info->skip_notify = 1;
4380
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004381 err_nh = NULL;
4382 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004383 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4384 fib6_info_release(nh->fib6_info);
David Ahern3b1137f2017-02-02 12:37:10 -08004385
David Ahernf7225172018-06-04 13:41:42 -07004386 if (!err) {
4387 /* save reference to last route successfully inserted */
4388 rt_last = nh->fib6_info;
4389
4390 /* save reference to first route for notification */
4391 if (!rt_notif)
4392 rt_notif = nh->fib6_info;
4393 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004394
David Ahern8d1c8022018-04-17 17:33:26 -07004395 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4396 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004397 if (err) {
4398 if (replace && nhn)
Jakub Kicinskia5a82d82019-01-14 10:52:45 -08004399 NL_SET_ERR_MSG_MOD(extack,
4400 "multipath route replace failed (check consistency of installed routes)");
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004401 err_nh = nh;
4402 goto add_errout;
4403 }
4404
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004405 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004406 * these flags after the first nexthop: if there is a collision,
4407 * we have already failed to add the first nexthop:
4408 * fib6_add_rt2node() has rejected it; when replacing, old
4409 * nexthops have been replaced by first new, the rest should
4410 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004411 */
Michal Kubeček27596472015-05-18 20:54:00 +02004412 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4413 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004414 nhn++;
4415 }
4416
David Ahern3b1137f2017-02-02 12:37:10 -08004417 /* success ... tell user about new route */
4418 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004419 goto cleanup;
4420
4421add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004422 /* send notification for routes that were added so that
4423 * the delete notifications sent by ip6_route_del are
4424 * coherent
4425 */
4426 if (rt_notif)
4427 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4428
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004429 /* Delete routes that were already added */
4430 list_for_each_entry(nh, &rt6_nh_list, next) {
4431 if (err_nh == nh)
4432 break;
David Ahern333c4302017-05-21 10:12:04 -06004433 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004434 }
4435
4436cleanup:
4437 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004438 if (nh->fib6_info)
4439 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004440 list_del(&nh->next);
4441 kfree(nh);
4442 }
4443
4444 return err;
4445}
4446
David Ahern333c4302017-05-21 10:12:04 -06004447static int ip6_route_multipath_del(struct fib6_config *cfg,
4448 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004449{
4450 struct fib6_config r_cfg;
4451 struct rtnexthop *rtnh;
4452 int remaining;
4453 int attrlen;
4454 int err = 1, last_err = 0;
4455
4456 remaining = cfg->fc_mp_len;
4457 rtnh = (struct rtnexthop *)cfg->fc_mp;
4458
4459 /* Parse a Multipath Entry */
4460 while (rtnh_ok(rtnh, remaining)) {
4461 memcpy(&r_cfg, cfg, sizeof(*cfg));
4462 if (rtnh->rtnh_ifindex)
4463 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4464
4465 attrlen = rtnh_attrlen(rtnh);
4466 if (attrlen > 0) {
4467 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4468
4469 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4470 if (nla) {
4471 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4472 r_cfg.fc_flags |= RTF_GATEWAY;
4473 }
4474 }
David Ahern333c4302017-05-21 10:12:04 -06004475 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004476 if (err)
4477 last_err = err;
4478
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004479 rtnh = rtnh_next(rtnh, &remaining);
4480 }
4481
4482 return last_err;
4483}
4484
David Ahernc21ef3e2017-04-16 09:48:24 -07004485static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4486 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487{
Thomas Graf86872cb2006-08-22 00:01:08 -07004488 struct fib6_config cfg;
4489 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
David Ahern333c4302017-05-21 10:12:04 -06004491 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004492 if (err < 0)
4493 return err;
4494
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004495 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004496 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004497 else {
4498 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004499 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501}
4502
David Ahernc21ef3e2017-04-16 09:48:24 -07004503static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4504 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505{
Thomas Graf86872cb2006-08-22 00:01:08 -07004506 struct fib6_config cfg;
4507 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508
David Ahern333c4302017-05-21 10:12:04 -06004509 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004510 if (err < 0)
4511 return err;
4512
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004513 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004514 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004515 else
David Ahernacb54e32018-04-17 17:33:22 -07004516 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517}
4518
David Ahern8d1c8022018-04-17 17:33:26 -07004519static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004520{
David Ahernbeb1afac52017-02-02 12:37:09 -08004521 int nexthop_len = 0;
4522
David Ahern93c2fb22018-04-18 15:38:59 -07004523 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004524 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4525 + NLA_ALIGN(sizeof(struct rtnexthop))
4526 + nla_total_size(16) /* RTA_GATEWAY */
David Ahern5e670d82018-04-17 17:33:14 -07004527 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
David Ahernbeb1afac52017-02-02 12:37:09 -08004528
David Ahern93c2fb22018-04-18 15:38:59 -07004529 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004530 }
4531
Thomas Graf339bf982006-11-10 14:10:15 -08004532 return NLMSG_ALIGN(sizeof(struct rtmsg))
4533 + nla_total_size(16) /* RTA_SRC */
4534 + nla_total_size(16) /* RTA_DST */
4535 + nla_total_size(16) /* RTA_GATEWAY */
4536 + nla_total_size(16) /* RTA_PREFSRC */
4537 + nla_total_size(4) /* RTA_TABLE */
4538 + nla_total_size(4) /* RTA_IIF */
4539 + nla_total_size(4) /* RTA_OIF */
4540 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004541 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004542 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004543 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004544 + nla_total_size(1) /* RTA_PREF */
David Ahern5e670d82018-04-17 17:33:14 -07004545 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate)
David Ahernbeb1afac52017-02-02 12:37:09 -08004546 + nexthop_len;
4547}
4548
David Ahern8d1c8022018-04-17 17:33:26 -07004549static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004550 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004551{
David Ahern5e670d82018-04-17 17:33:14 -07004552 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004553 *flags |= RTNH_F_DEAD;
4554
David Ahern5e670d82018-04-17 17:33:14 -07004555 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004556 *flags |= RTNH_F_LINKDOWN;
David Aherndcd1f572018-04-18 15:39:05 -07004557
4558 rcu_read_lock();
4559 if (fib6_ignore_linkdown(rt))
David Ahernbeb1afac52017-02-02 12:37:09 -08004560 *flags |= RTNH_F_DEAD;
David Aherndcd1f572018-04-18 15:39:05 -07004561 rcu_read_unlock();
David Ahernbeb1afac52017-02-02 12:37:09 -08004562 }
4563
David Ahern93c2fb22018-04-18 15:38:59 -07004564 if (rt->fib6_flags & RTF_GATEWAY) {
David Ahern5e670d82018-04-17 17:33:14 -07004565 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004566 goto nla_put_failure;
4567 }
4568
David Ahern5e670d82018-04-17 17:33:14 -07004569 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK);
4570 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004571 *flags |= RTNH_F_OFFLOAD;
4572
David Ahern5be083c2017-03-06 15:57:31 -08004573 /* not needed for multipath encoding b/c it has a rtnexthop struct */
David Ahern5e670d82018-04-17 17:33:14 -07004574 if (!skip_oif && rt->fib6_nh.nh_dev &&
4575 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex))
David Ahernbeb1afac52017-02-02 12:37:09 -08004576 goto nla_put_failure;
4577
David Ahern5e670d82018-04-17 17:33:14 -07004578 if (rt->fib6_nh.nh_lwtstate &&
4579 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004580 goto nla_put_failure;
4581
4582 return 0;
4583
4584nla_put_failure:
4585 return -EMSGSIZE;
4586}
4587
David Ahern5be083c2017-03-06 15:57:31 -08004588/* add multipath next hop */
David Ahern8d1c8022018-04-17 17:33:26 -07004589static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt)
David Ahernbeb1afac52017-02-02 12:37:09 -08004590{
David Ahern5e670d82018-04-17 17:33:14 -07004591 const struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernbeb1afac52017-02-02 12:37:09 -08004592 struct rtnexthop *rtnh;
4593 unsigned int flags = 0;
4594
4595 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4596 if (!rtnh)
4597 goto nla_put_failure;
4598
David Ahern5e670d82018-04-17 17:33:14 -07004599 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1;
4600 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
David Ahernbeb1afac52017-02-02 12:37:09 -08004601
David Ahern5be083c2017-03-06 15:57:31 -08004602 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004603 goto nla_put_failure;
4604
4605 rtnh->rtnh_flags = flags;
4606
4607 /* length of rtnetlink header + attributes */
4608 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4609
4610 return 0;
4611
4612nla_put_failure:
4613 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004614}
4615
David Ahernd4ead6b2018-04-17 17:33:16 -07004616static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004617 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004618 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004619 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004620 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621{
Xin Long22d0bd82018-09-11 14:33:58 +08004622 struct rt6_info *rt6 = (struct rt6_info *)dst;
4623 struct rt6key *rt6_dst, *rt6_src;
4624 u32 *pmetrics, table, rt6_flags;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004625 struct nlmsghdr *nlh;
Xin Long22d0bd82018-09-11 14:33:58 +08004626 struct rtmsg *rtm;
David Ahernd4ead6b2018-04-17 17:33:16 -07004627 long expires = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
Eric W. Biederman15e47302012-09-07 20:12:54 +00004629 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004630 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004631 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004632
Xin Long22d0bd82018-09-11 14:33:58 +08004633 if (rt6) {
4634 rt6_dst = &rt6->rt6i_dst;
4635 rt6_src = &rt6->rt6i_src;
4636 rt6_flags = rt6->rt6i_flags;
4637 } else {
4638 rt6_dst = &rt->fib6_dst;
4639 rt6_src = &rt->fib6_src;
4640 rt6_flags = rt->fib6_flags;
4641 }
4642
Thomas Graf2d7202b2006-08-22 00:01:27 -07004643 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 rtm->rtm_family = AF_INET6;
Xin Long22d0bd82018-09-11 14:33:58 +08004645 rtm->rtm_dst_len = rt6_dst->plen;
4646 rtm->rtm_src_len = rt6_src->plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004648 if (rt->fib6_table)
4649 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004650 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004651 table = RT6_TABLE_UNSPEC;
4652 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04004653 if (nla_put_u32(skb, RTA_TABLE, table))
4654 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004655
4656 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 rtm->rtm_flags = 0;
4658 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004659 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Xin Long22d0bd82018-09-11 14:33:58 +08004661 if (rt6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 rtm->rtm_flags |= RTM_F_CLONED;
4663
David Ahernd4ead6b2018-04-17 17:33:16 -07004664 if (dest) {
4665 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004666 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004667 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 } else if (rtm->rtm_dst_len)
Xin Long22d0bd82018-09-11 14:33:58 +08004669 if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004670 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671#ifdef CONFIG_IPV6_SUBTREES
4672 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004673 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004674 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004675 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004676 } else if (rtm->rtm_src_len &&
Xin Long22d0bd82018-09-11 14:33:58 +08004677 nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004678 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004680 if (iif) {
4681#ifdef CONFIG_IPV6_MROUTE
Xin Long22d0bd82018-09-11 14:33:58 +08004682 if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004683 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004684
David Ahernfd61c6b2017-01-17 15:51:07 -08004685 if (err == 0)
4686 return 0;
4687 if (err < 0)
4688 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004689 } else
4690#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004691 if (nla_put_u32(skb, RTA_IIF, iif))
4692 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004693 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004695 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004696 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004697 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004699
David Ahern93c2fb22018-04-18 15:38:59 -07004700 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004701 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004702 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004703 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004704 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004705 }
4706
David Ahernd4ead6b2018-04-17 17:33:16 -07004707 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4708 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004709 goto nla_put_failure;
4710
David Ahern93c2fb22018-04-18 15:38:59 -07004711 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004712 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004713
David Ahernbeb1afac52017-02-02 12:37:09 -08004714 /* For multipath routes, walk the siblings list and add
4715 * each as a nexthop within RTA_MULTIPATH.
4716 */
Xin Long22d0bd82018-09-11 14:33:58 +08004717 if (rt6) {
4718 if (rt6_flags & RTF_GATEWAY &&
4719 nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
4720 goto nla_put_failure;
4721
4722 if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
4723 goto nla_put_failure;
4724 } else if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004725 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004726 struct nlattr *mp;
4727
4728 mp = nla_nest_start(skb, RTA_MULTIPATH);
4729 if (!mp)
4730 goto nla_put_failure;
4731
4732 if (rt6_add_nexthop(skb, rt) < 0)
4733 goto nla_put_failure;
4734
4735 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004736 &rt->fib6_siblings, fib6_siblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004737 if (rt6_add_nexthop(skb, sibling) < 0)
4738 goto nla_put_failure;
4739 }
4740
4741 nla_nest_end(skb, mp);
4742 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004743 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004744 goto nla_put_failure;
4745 }
4746
Xin Long22d0bd82018-09-11 14:33:58 +08004747 if (rt6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004748 expires = dst ? dst->expires : rt->expires;
4749 expires -= jiffies;
4750 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004751
David Ahernd4ead6b2018-04-17 17:33:16 -07004752 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004753 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754
Xin Long22d0bd82018-09-11 14:33:58 +08004755 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004756 goto nla_put_failure;
4757
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004758
Johannes Berg053c0952015-01-16 22:09:00 +01004759 nlmsg_end(skb, nlh);
4760 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004761
4762nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004763 nlmsg_cancel(skb, nlh);
4764 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765}
4766
David Ahern13e38902018-10-15 18:56:44 -07004767static bool fib6_info_uses_dev(const struct fib6_info *f6i,
4768 const struct net_device *dev)
4769{
4770 if (f6i->fib6_nh.nh_dev == dev)
4771 return true;
4772
4773 if (f6i->fib6_nsiblings) {
4774 struct fib6_info *sibling, *next_sibling;
4775
4776 list_for_each_entry_safe(sibling, next_sibling,
4777 &f6i->fib6_siblings, fib6_siblings) {
4778 if (sibling->fib6_nh.nh_dev == dev)
4779 return true;
4780 }
4781 }
4782
4783 return false;
4784}
4785
David Ahern8d1c8022018-04-17 17:33:26 -07004786int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787{
4788 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern13e38902018-10-15 18:56:44 -07004789 struct fib_dump_filter *filter = &arg->filter;
4790 unsigned int flags = NLM_F_MULTI;
David Ahern1f17e2f2017-01-26 13:54:08 -08004791 struct net *net = arg->net;
4792
David Ahern421842e2018-04-17 17:33:18 -07004793 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004794 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
David Ahern13e38902018-10-15 18:56:44 -07004796 if ((filter->flags & RTM_F_PREFIX) &&
4797 !(rt->fib6_flags & RTF_PREFIX_RT)) {
4798 /* success since this is not a prefix route */
4799 return 1;
4800 }
4801 if (filter->filter_set) {
4802 if ((filter->rt_type && rt->fib6_type != filter->rt_type) ||
4803 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) ||
4804 (filter->protocol && rt->fib6_protocol != filter->protocol)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004805 return 1;
4806 }
David Ahern13e38902018-10-15 18:56:44 -07004807 flags |= NLM_F_DUMP_FILTERED;
David Ahernf8cfe2c2017-01-17 15:51:08 -08004808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809
David Ahernd4ead6b2018-04-17 17:33:16 -07004810 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4811 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
David Ahern13e38902018-10-15 18:56:44 -07004812 arg->cb->nlh->nlmsg_seq, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813}
4814
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004815static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
4816 const struct nlmsghdr *nlh,
4817 struct nlattr **tb,
4818 struct netlink_ext_ack *extack)
4819{
4820 struct rtmsg *rtm;
4821 int i, err;
4822
4823 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
4824 NL_SET_ERR_MSG_MOD(extack,
4825 "Invalid header for get route request");
4826 return -EINVAL;
4827 }
4828
4829 if (!netlink_strict_get_check(skb))
4830 return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
4831 rtm_ipv6_policy, extack);
4832
4833 rtm = nlmsg_data(nlh);
4834 if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
4835 (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
4836 rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
4837 rtm->rtm_type) {
4838 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
4839 return -EINVAL;
4840 }
4841 if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
4842 NL_SET_ERR_MSG_MOD(extack,
4843 "Invalid flags for get route request");
4844 return -EINVAL;
4845 }
4846
4847 err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
4848 rtm_ipv6_policy, extack);
4849 if (err)
4850 return err;
4851
4852 if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
4853 (tb[RTA_DST] && !rtm->rtm_dst_len)) {
4854 NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
4855 return -EINVAL;
4856 }
4857
4858 for (i = 0; i <= RTA_MAX; i++) {
4859 if (!tb[i])
4860 continue;
4861
4862 switch (i) {
4863 case RTA_SRC:
4864 case RTA_DST:
4865 case RTA_IIF:
4866 case RTA_OIF:
4867 case RTA_MARK:
4868 case RTA_UID:
4869 case RTA_SPORT:
4870 case RTA_DPORT:
4871 case RTA_IP_PROTO:
4872 break;
4873 default:
4874 NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
4875 return -EINVAL;
4876 }
4877 }
4878
4879 return 0;
4880}
4881
David Ahernc21ef3e2017-04-16 09:48:24 -07004882static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4883 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004885 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004886 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004887 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004888 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004889 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004891 struct sk_buff *skb;
4892 struct rtmsg *rtm;
Maciej Żenczykowski744486d2018-09-29 23:44:54 -07004893 struct flowi6 fl6 = {};
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004894 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004895
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004896 err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004897 if (err < 0)
4898 goto errout;
4899
4900 err = -EINVAL;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004901 rtm = nlmsg_data(nlh);
4902 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004903 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004904
4905 if (tb[RTA_SRC]) {
4906 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4907 goto errout;
4908
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004909 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004910 }
4911
4912 if (tb[RTA_DST]) {
4913 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4914 goto errout;
4915
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004916 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004917 }
4918
4919 if (tb[RTA_IIF])
4920 iif = nla_get_u32(tb[RTA_IIF]);
4921
4922 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004923 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004924
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004925 if (tb[RTA_MARK])
4926 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4927
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004928 if (tb[RTA_UID])
4929 fl6.flowi6_uid = make_kuid(current_user_ns(),
4930 nla_get_u32(tb[RTA_UID]));
4931 else
4932 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4933
Roopa Prabhueacb9382018-05-22 14:03:28 -07004934 if (tb[RTA_SPORT])
4935 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
4936
4937 if (tb[RTA_DPORT])
4938 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
4939
4940 if (tb[RTA_IP_PROTO]) {
4941 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
4942 &fl6.flowi6_proto, extack);
4943 if (err)
4944 goto errout;
4945 }
4946
Thomas Grafab364a62006-08-22 00:01:47 -07004947 if (iif) {
4948 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004949 int flags = 0;
4950
Florian Westphal121622d2017-08-15 16:34:42 +02004951 rcu_read_lock();
4952
4953 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004954 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004955 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004956 err = -ENODEV;
4957 goto errout;
4958 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004959
4960 fl6.flowi6_iif = iif;
4961
4962 if (!ipv6_addr_any(&fl6.saddr))
4963 flags |= RT6_LOOKUP_F_HAS_SADDR;
4964
David Ahernb75cc8f2018-03-02 08:32:17 -08004965 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004966
4967 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004968 } else {
4969 fl6.flowi6_oif = oif;
4970
Ido Schimmel58acfd72017-12-20 12:28:25 +02004971 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004972 }
4973
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004974
4975 rt = container_of(dst, struct rt6_info, dst);
4976 if (rt->dst.error) {
4977 err = rt->dst.error;
4978 ip6_rt_put(rt);
4979 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
WANG Cong9d6acb32017-03-01 20:48:39 -08004982 if (rt == net->ipv6.ip6_null_entry) {
4983 err = rt->dst.error;
4984 ip6_rt_put(rt);
4985 goto errout;
4986 }
4987
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004989 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004990 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07004991 err = -ENOBUFS;
4992 goto errout;
4993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
Changli Gaod8d1f302010-06-10 23:31:35 -07004995 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07004996
4997 rcu_read_lock();
4998 from = rcu_dereference(rt->from);
4999
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005000 if (fibmatch)
David Aherna68886a2018-04-20 15:38:02 -07005001 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005002 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
5003 nlh->nlmsg_seq, 0);
5004 else
David Aherna68886a2018-04-20 15:38:02 -07005005 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5006 &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07005007 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
5008 0);
David Aherna68886a2018-04-20 15:38:02 -07005009 rcu_read_unlock();
5010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07005012 kfree_skb(skb);
5013 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 }
5015
Eric W. Biederman15e47302012-09-07 20:12:54 +00005016 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07005017errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019}
5020
David Ahern8d1c8022018-04-17 17:33:26 -07005021void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07005022 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023{
5024 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08005025 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005026 u32 seq;
5027 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005029 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05005030 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07005031
Roopa Prabhu19e42e42015-07-21 10:43:48 +02005032 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05005033 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07005034 goto errout;
5035
David Ahernd4ead6b2018-04-17 17:33:16 -07005036 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
5037 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08005038 if (err < 0) {
5039 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
5040 WARN_ON(err == -EMSGSIZE);
5041 kfree_skb(skb);
5042 goto errout;
5043 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00005044 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08005045 info->nlh, gfp_any());
5046 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07005047errout:
5048 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08005049 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050}
5051
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005052static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00005053 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005054{
Jiri Pirko351638e2013-05-28 01:30:21 +00005055 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09005056 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005057
WANG Cong242d3a42017-05-08 10:12:13 -07005058 if (!(dev->flags & IFF_LOOPBACK))
5059 return NOTIFY_OK;
5060
5061 if (event == NETDEV_REGISTER) {
David Ahern421842e2018-04-17 17:33:18 -07005062 net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07005063 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005064 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
5065#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07005066 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005067 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07005068 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005069 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
5070#endif
WANG Cong76da0702017-06-20 11:42:27 -07005071 } else if (event == NETDEV_UNREGISTER &&
5072 dev->reg_state != NETREG_UNREGISTERED) {
5073 /* NETDEV_UNREGISTER could be fired for multiple times by
5074 * netdev_wait_allrefs(). Make sure we only call this once.
5075 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07005076 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005077#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005078 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5079 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005080#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005081 }
5082
5083 return NOTIFY_OK;
5084}
5085
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086/*
5087 * /proc
5088 */
5089
5090#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5092{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005093 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005095 net->ipv6.rt6_stats->fib_nodes,
5096 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005097 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005098 net->ipv6.rt6_stats->fib_rt_entries,
5099 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005100 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005101 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102
5103 return 0;
5104}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105#endif /* CONFIG_PROC_FS */
5106
5107#ifdef CONFIG_SYSCTL
5108
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005110int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 void __user *buffer, size_t *lenp, loff_t *ppos)
5112{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005113 struct net *net;
5114 int delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005115 int ret;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005116 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005118
5119 net = (struct net *)ctl->extra1;
5120 delay = net->ipv6.sysctl.flush_delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005121 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
5122 if (ret)
5123 return ret;
5124
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005125 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005126 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127}
5128
David Ahern7c6bb7d2018-10-11 20:17:21 -07005129static int zero;
5130static int one = 1;
5131
David Aherned792e22018-10-08 14:06:34 -07005132static struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005133 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005135 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005137 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005138 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 },
5140 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005142 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 .maxlen = sizeof(int),
5144 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005145 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 },
5147 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005149 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 .maxlen = sizeof(int),
5151 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005152 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 },
5154 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005156 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 .maxlen = sizeof(int),
5158 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005159 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 },
5161 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005163 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 .maxlen = sizeof(int),
5165 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005166 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 },
5168 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005170 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 .maxlen = sizeof(int),
5172 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005173 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 },
5175 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005177 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 .maxlen = sizeof(int),
5179 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005180 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 },
5182 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005184 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 .maxlen = sizeof(int),
5186 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005187 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 },
5189 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005191 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 .maxlen = sizeof(int),
5193 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005194 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 },
5196 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005198 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 .maxlen = sizeof(int),
5200 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005201 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 },
David Ahern7c6bb7d2018-10-11 20:17:21 -07005203 {
5204 .procname = "skip_notify_on_dev_down",
5205 .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
5206 .maxlen = sizeof(int),
5207 .mode = 0644,
5208 .proc_handler = proc_dointvec,
5209 .extra1 = &zero,
5210 .extra2 = &one,
5211 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005212 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213};
5214
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005215struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005216{
5217 struct ctl_table *table;
5218
5219 table = kmemdup(ipv6_route_table_template,
5220 sizeof(ipv6_route_table_template),
5221 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005222
5223 if (table) {
5224 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005225 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005226 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005227 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5228 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5229 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5230 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5231 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5232 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5233 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005234 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005235 table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005236
5237 /* Don't export sysctls to unprivileged users */
5238 if (net->user_ns != &init_user_ns)
5239 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005240 }
5241
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005242 return table;
5243}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244#endif
5245
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005246static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005247{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005248 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005249
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005250 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5251 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005252
Eric Dumazetfc66f952010-10-08 06:37:34 +00005253 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5254 goto out_ip6_dst_ops;
5255
David Ahern421842e2018-04-17 17:33:18 -07005256 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5257 sizeof(*net->ipv6.fib6_null_entry),
5258 GFP_KERNEL);
5259 if (!net->ipv6.fib6_null_entry)
5260 goto out_ip6_dst_entries;
5261
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005262 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5263 sizeof(*net->ipv6.ip6_null_entry),
5264 GFP_KERNEL);
5265 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005266 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005267 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005268 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5269 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005270
5271#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005272 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005273 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5274 sizeof(*net->ipv6.ip6_prohibit_entry),
5275 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005276 if (!net->ipv6.ip6_prohibit_entry)
5277 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005278 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005279 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5280 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005281
5282 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5283 sizeof(*net->ipv6.ip6_blk_hole_entry),
5284 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005285 if (!net->ipv6.ip6_blk_hole_entry)
5286 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005287 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005288 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5289 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005290#endif
5291
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005292 net->ipv6.sysctl.flush_delay = 0;
5293 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5294 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5295 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5296 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5297 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5298 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5299 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005300 net->ipv6.sysctl.skip_notify_on_dev_down = 0;
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005301
Benjamin Thery6891a342008-03-04 13:49:47 -08005302 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5303
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005304 ret = 0;
5305out:
5306 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005307
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005308#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5309out_ip6_prohibit_entry:
5310 kfree(net->ipv6.ip6_prohibit_entry);
5311out_ip6_null_entry:
5312 kfree(net->ipv6.ip6_null_entry);
5313#endif
David Ahern421842e2018-04-17 17:33:18 -07005314out_fib6_null_entry:
5315 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005316out_ip6_dst_entries:
5317 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005318out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005319 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005320}
5321
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005322static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005323{
David Ahern421842e2018-04-17 17:33:18 -07005324 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005325 kfree(net->ipv6.ip6_null_entry);
5326#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5327 kfree(net->ipv6.ip6_prohibit_entry);
5328 kfree(net->ipv6.ip6_blk_hole_entry);
5329#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005330 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005331}
5332
Thomas Grafd1896342012-06-18 12:08:33 +00005333static int __net_init ip6_route_net_init_late(struct net *net)
5334{
5335#ifdef CONFIG_PROC_FS
Christoph Hellwigc3506372018-04-10 19:42:55 +02005336 proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
5337 sizeof(struct ipv6_route_iter));
Christoph Hellwig3617d942018-04-13 20:38:35 +02005338 proc_create_net_single("rt6_stats", 0444, net->proc_net,
5339 rt6_stats_seq_show, NULL);
Thomas Grafd1896342012-06-18 12:08:33 +00005340#endif
5341 return 0;
5342}
5343
5344static void __net_exit ip6_route_net_exit_late(struct net *net)
5345{
5346#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005347 remove_proc_entry("ipv6_route", net->proc_net);
5348 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005349#endif
5350}
5351
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005352static struct pernet_operations ip6_route_net_ops = {
5353 .init = ip6_route_net_init,
5354 .exit = ip6_route_net_exit,
5355};
5356
David S. Millerc3426b42012-06-09 16:27:05 -07005357static int __net_init ipv6_inetpeer_init(struct net *net)
5358{
5359 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5360
5361 if (!bp)
5362 return -ENOMEM;
5363 inet_peer_base_init(bp);
5364 net->ipv6.peers = bp;
5365 return 0;
5366}
5367
5368static void __net_exit ipv6_inetpeer_exit(struct net *net)
5369{
5370 struct inet_peer_base *bp = net->ipv6.peers;
5371
5372 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005373 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005374 kfree(bp);
5375}
5376
David S. Miller2b823f72012-06-09 19:00:16 -07005377static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005378 .init = ipv6_inetpeer_init,
5379 .exit = ipv6_inetpeer_exit,
5380};
5381
Thomas Grafd1896342012-06-18 12:08:33 +00005382static struct pernet_operations ip6_route_net_late_ops = {
5383 .init = ip6_route_net_init_late,
5384 .exit = ip6_route_net_exit_late,
5385};
5386
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005387static struct notifier_block ip6_route_dev_notifier = {
5388 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005389 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005390};
5391
WANG Cong2f460932017-05-03 22:07:31 -07005392void __init ip6_route_init_special_entries(void)
5393{
5394 /* Registering of the loopback is done before this portion of code,
5395 * the loopback reference in rt6_info will not be taken, do it
5396 * manually for init_net */
David Ahern421842e2018-04-17 17:33:18 -07005397 init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005398 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5399 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5400 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5401 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5402 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5403 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5404 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5405 #endif
5406}
5407
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005408int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005410 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005411 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005412
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005413 ret = -ENOMEM;
5414 ip6_dst_ops_template.kmem_cachep =
5415 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5416 SLAB_HWCACHE_ALIGN, NULL);
5417 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005418 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005419
Eric Dumazetfc66f952010-10-08 06:37:34 +00005420 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005421 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005422 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005423
David S. Millerc3426b42012-06-09 16:27:05 -07005424 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5425 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005426 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005427
David S. Miller7e52b332012-06-15 15:51:55 -07005428 ret = register_pernet_subsys(&ip6_route_net_ops);
5429 if (ret)
5430 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005431
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005432 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5433
David S. Millere8803b62012-06-16 01:12:19 -07005434 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005435 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005436 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005437
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005438 ret = xfrm6_init();
5439 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005440 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005441
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005442 ret = fib6_rules_init();
5443 if (ret)
5444 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005445
Thomas Grafd1896342012-06-18 12:08:33 +00005446 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5447 if (ret)
5448 goto fib6_rules_init;
5449
Florian Westphal16feebc2017-12-02 21:44:08 +01005450 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5451 inet6_rtm_newroute, NULL, 0);
5452 if (ret < 0)
5453 goto out_register_late_subsys;
5454
5455 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5456 inet6_rtm_delroute, NULL, 0);
5457 if (ret < 0)
5458 goto out_register_late_subsys;
5459
5460 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5461 inet6_rtm_getroute, NULL,
5462 RTNL_FLAG_DOIT_UNLOCKED);
5463 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005464 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005465
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005466 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005467 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005468 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005469
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005470 for_each_possible_cpu(cpu) {
5471 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5472
5473 INIT_LIST_HEAD(&ul->head);
5474 spin_lock_init(&ul->lock);
5475 }
5476
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005477out:
5478 return ret;
5479
Thomas Grafd1896342012-06-18 12:08:33 +00005480out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005481 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005482 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005483fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005484 fib6_rules_cleanup();
5485xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005486 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005487out_fib6_init:
5488 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005489out_register_subsys:
5490 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005491out_register_inetpeer:
5492 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005493out_dst_entries:
5494 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005495out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005496 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005497 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498}
5499
5500void ip6_route_cleanup(void)
5501{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005502 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005503 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005504 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005507 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005508 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005509 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005510 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511}