blob: 0302e0eb07af1d270a615bcadfcb9bc08ca61d6c [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))
Xin Long1c87e792019-03-20 14:45:48 +08001043 goto fallback;
Wei Wange873e4b2018-07-21 20:56:32 -07001044
David Ahern93531c62018-04-17 17:33:25 -07001045 nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
Xin Long1c87e792019-03-20 14:45:48 +08001046 if (!nrt) {
Wei Wange873e4b2018-07-21 20:56:32 -07001047 fib6_info_release(rt);
Xin Long1c87e792019-03-20 14:45:48 +08001048 goto fallback;
1049 }
David Aherndec9b0e2018-04-17 17:33:19 -07001050
Xin Long1c87e792019-03-20 14:45:48 +08001051 ip6_rt_copy_init(nrt, rt);
1052 return nrt;
1053
1054fallback:
1055 nrt = dev_net(dev)->ipv6.ip6_null_entry;
1056 dst_hold(&nrt->dst);
David Aherndec9b0e2018-04-17 17:33:19 -07001057 return nrt;
1058}
1059
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001060static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1061 struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001062 struct flowi6 *fl6,
1063 const struct sk_buff *skb,
1064 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065{
David Ahern8d1c8022018-04-17 17:33:26 -07001066 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 struct fib6_node *fn;
David Ahern23fb93a2018-04-17 17:33:23 -07001068 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
David Ahernb6cdbc82018-03-29 17:44:57 -07001070 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1071 flags &= ~RT6_LOOKUP_F_IFACE;
1072
Wei Wang66f5d6c2017-10-06 12:06:10 -07001073 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07001074 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -07001075restart:
David Ahern23fb93a2018-04-17 17:33:23 -07001076 f6i = rcu_dereference(fn->leaf);
1077 if (!f6i) {
1078 f6i = net->ipv6.fib6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001079 } else {
David Ahern23fb93a2018-04-17 17:33:23 -07001080 f6i = rt6_device_match(net, f6i, &fl6->saddr,
Wei Wang66f5d6c2017-10-06 12:06:10 -07001081 fl6->flowi6_oif, flags);
David Ahern93c2fb22018-04-18 15:38:59 -07001082 if (f6i->fib6_nsiblings && fl6->flowi6_oif == 0)
David Ahern3b290a32018-05-09 20:34:20 -07001083 f6i = fib6_multipath_select(net, f6i, fl6,
1084 fl6->flowi6_oif, skb,
1085 flags);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001086 }
David Ahern23fb93a2018-04-17 17:33:23 -07001087 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001088 fn = fib6_backtrack(fn, &fl6->saddr);
1089 if (fn)
1090 goto restart;
1091 }
Wei Wang2b760fc2017-10-06 12:06:03 -07001092
David Ahernd4bea422018-05-09 20:34:24 -07001093 trace_fib6_table_lookup(net, f6i, table, fl6);
1094
David S. Miller4c9483b2011-03-12 16:22:43 -05001095 /* Search through exception table */
David Ahern23fb93a2018-04-17 17:33:23 -07001096 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1097 if (rt) {
David Aherndec9b0e2018-04-17 17:33:19 -07001098 if (ip6_hold_safe(net, &rt, true))
1099 dst_use_noref(&rt->dst, jiffies);
David Ahern23fb93a2018-04-17 17:33:23 -07001100 } else if (f6i == net->ipv6.fib6_null_entry) {
David Aherndec9b0e2018-04-17 17:33:19 -07001101 rt = net->ipv6.ip6_null_entry;
1102 dst_hold(&rt->dst);
David Ahern23fb93a2018-04-17 17:33:23 -07001103 } else {
1104 rt = ip6_create_rt_rcu(f6i);
David Aherndec9b0e2018-04-17 17:33:19 -07001105 }
Wei Wangd3843fe2017-10-06 12:06:06 -07001106
Wei Wang66f5d6c2017-10-06 12:06:10 -07001107 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -08001108
Thomas Grafc71099a2006-08-04 23:20:06 -07001109 return rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001110}
1111
Ian Morris67ba4152014-08-24 21:53:10 +01001112struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08001113 const struct sk_buff *skb, int flags)
Florian Westphalea6e5742011-09-05 16:05:44 +02001114{
David Ahernb75cc8f2018-03-02 08:32:17 -08001115 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
Florian Westphalea6e5742011-09-05 16:05:44 +02001116}
1117EXPORT_SYMBOL_GPL(ip6_route_lookup);
1118
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +09001119struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
David Ahernb75cc8f2018-03-02 08:32:17 -08001120 const struct in6_addr *saddr, int oif,
1121 const struct sk_buff *skb, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -07001122{
David S. Miller4c9483b2011-03-12 16:22:43 -05001123 struct flowi6 fl6 = {
1124 .flowi6_oif = oif,
1125 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001126 };
1127 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001128 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07001129
Thomas Grafadaa70b2006-10-13 15:01:03 -07001130 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -05001131 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -07001132 flags |= RT6_LOOKUP_F_HAS_SADDR;
1133 }
1134
David Ahernb75cc8f2018-03-02 08:32:17 -08001135 dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -07001136 if (dst->error == 0)
1137 return (struct rt6_info *) dst;
1138
1139 dst_release(dst);
1140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return NULL;
1142}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001143EXPORT_SYMBOL(rt6_lookup);
1144
Thomas Grafc71099a2006-08-04 23:20:06 -07001145/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -07001146 * It takes new route entry, the addition fails by any reason the
1147 * route is released.
1148 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 */
1150
David Ahern8d1c8022018-04-17 17:33:26 -07001151static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001152 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153{
1154 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001155 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
David Ahern93c2fb22018-04-18 15:38:59 -07001157 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001158 spin_lock_bh(&table->tb6_lock);
David Ahernd4ead6b2018-04-17 17:33:16 -07001159 err = fib6_add(&table->tb6_root, rt, info, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001160 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
1162 return err;
1163}
1164
David Ahern8d1c8022018-04-17 17:33:26 -07001165int ip6_ins_rt(struct net *net, struct fib6_info *rt)
Thomas Graf40e22e82006-08-22 00:00:45 -07001166{
David Ahernafb1d4b52018-04-17 17:33:11 -07001167 struct nl_info info = { .nl_net = net, };
Florian Westphale715b6d2015-01-05 23:57:44 +01001168
David Ahernd4ead6b2018-04-17 17:33:16 -07001169 return __ip6_ins_rt(rt, &info, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001170}
1171
David Ahern8d1c8022018-04-17 17:33:26 -07001172static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001173 const struct in6_addr *daddr,
1174 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
David Ahern4832c302017-08-17 12:17:20 -07001176 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 struct rt6_info *rt;
1178
1179 /*
1180 * Clone the route.
1181 */
1182
Wei Wange873e4b2018-07-21 20:56:32 -07001183 if (!fib6_info_hold_safe(ort))
1184 return NULL;
1185
David Ahern4832c302017-08-17 12:17:20 -07001186 dev = ip6_rt_get_dev_rcu(ort);
David Ahern93531c62018-04-17 17:33:25 -07001187 rt = ip6_dst_alloc(dev_net(dev), dev, 0);
Wei Wange873e4b2018-07-21 20:56:32 -07001188 if (!rt) {
1189 fib6_info_release(ort);
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001190 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001191 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001192
1193 ip6_rt_copy_init(rt, ort);
1194 rt->rt6i_flags |= RTF_CACHE;
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001195 rt->dst.flags |= DST_HOST;
1196 rt->rt6i_dst.addr = *daddr;
1197 rt->rt6i_dst.plen = 128;
1198
1199 if (!rt6_is_gw_or_nonexthop(ort)) {
David Ahern93c2fb22018-04-18 15:38:59 -07001200 if (ort->fib6_dst.plen != 128 &&
1201 ipv6_addr_equal(&ort->fib6_dst.addr, daddr))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001202 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001204 if (rt->rt6i_src.plen && saddr) {
1205 rt->rt6i_src.addr = *saddr;
1206 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001207 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001208#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001211 return rt;
1212}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
David Ahern8d1c8022018-04-17 17:33:26 -07001214static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001215{
David Ahern3b6761d2018-04-17 17:33:20 -07001216 unsigned short flags = fib6_info_dst_flags(rt);
David Ahern4832c302017-08-17 12:17:20 -07001217 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001218 struct rt6_info *pcpu_rt;
1219
Wei Wange873e4b2018-07-21 20:56:32 -07001220 if (!fib6_info_hold_safe(rt))
1221 return NULL;
1222
David Ahern4832c302017-08-17 12:17:20 -07001223 rcu_read_lock();
1224 dev = ip6_rt_get_dev_rcu(rt);
David Ahern93531c62018-04-17 17:33:25 -07001225 pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Ahern4832c302017-08-17 12:17:20 -07001226 rcu_read_unlock();
Wei Wange873e4b2018-07-21 20:56:32 -07001227 if (!pcpu_rt) {
1228 fib6_info_release(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001229 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001230 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001231 ip6_rt_copy_init(pcpu_rt, rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001232 pcpu_rt->rt6i_flags |= RTF_PCPU;
1233 return pcpu_rt;
1234}
1235
Wei Wang66f5d6c2017-10-06 12:06:10 -07001236/* It should be called with rcu_read_lock() acquired */
David Ahern8d1c8022018-04-17 17:33:26 -07001237static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001238{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001239 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001240
1241 p = this_cpu_ptr(rt->rt6i_pcpu);
1242 pcpu_rt = *p;
1243
David Ahernd4ead6b2018-04-17 17:33:16 -07001244 if (pcpu_rt)
1245 ip6_hold_safe(NULL, &pcpu_rt, false);
Wei Wangd3843fe2017-10-06 12:06:06 -07001246
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001247 return pcpu_rt;
1248}
1249
David Ahernafb1d4b52018-04-17 17:33:11 -07001250static struct rt6_info *rt6_make_pcpu_route(struct net *net,
David Ahern8d1c8022018-04-17 17:33:26 -07001251 struct fib6_info *rt)
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001252{
1253 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001254
1255 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1256 if (!pcpu_rt) {
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001257 dst_hold(&net->ipv6.ip6_null_entry->dst);
1258 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001259 }
1260
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001261 dst_hold(&pcpu_rt->dst);
Wei Wanga94b9362017-10-06 12:06:04 -07001262 p = this_cpu_ptr(rt->rt6i_pcpu);
1263 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001264 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001265
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001266 return pcpu_rt;
1267}
1268
Wei Wang35732d02017-10-06 12:05:57 -07001269/* exception hash table implementation
1270 */
1271static DEFINE_SPINLOCK(rt6_exception_lock);
1272
1273/* Remove rt6_ex from hash table and free the memory
1274 * Caller must hold rt6_exception_lock
1275 */
1276static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1277 struct rt6_exception *rt6_ex)
1278{
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001279 struct fib6_info *from;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001280 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001281
Wei Wang35732d02017-10-06 12:05:57 -07001282 if (!bucket || !rt6_ex)
1283 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001284
1285 net = dev_net(rt6_ex->rt6i->dst.dev);
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001286 net->ipv6.rt6_stats->fib_rt_cache--;
1287
1288 /* purge completely the exception to allow releasing the held resources:
1289 * some [sk] cache may keep the dst around for unlimited time
1290 */
1291 from = rcu_dereference_protected(rt6_ex->rt6i->from,
1292 lockdep_is_held(&rt6_exception_lock));
1293 rcu_assign_pointer(rt6_ex->rt6i->from, NULL);
1294 fib6_info_release(from);
1295 dst_dev_put(&rt6_ex->rt6i->dst);
1296
Wei Wang35732d02017-10-06 12:05:57 -07001297 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001298 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001299 kfree_rcu(rt6_ex, rcu);
1300 WARN_ON_ONCE(!bucket->depth);
1301 bucket->depth--;
1302}
1303
1304/* Remove oldest rt6_ex in bucket and free the memory
1305 * Caller must hold rt6_exception_lock
1306 */
1307static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1308{
1309 struct rt6_exception *rt6_ex, *oldest = NULL;
1310
1311 if (!bucket)
1312 return;
1313
1314 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1315 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1316 oldest = rt6_ex;
1317 }
1318 rt6_remove_exception(bucket, oldest);
1319}
1320
1321static u32 rt6_exception_hash(const struct in6_addr *dst,
1322 const struct in6_addr *src)
1323{
1324 static u32 seed __read_mostly;
1325 u32 val;
1326
1327 net_get_random_once(&seed, sizeof(seed));
1328 val = jhash(dst, sizeof(*dst), seed);
1329
1330#ifdef CONFIG_IPV6_SUBTREES
1331 if (src)
1332 val = jhash(src, sizeof(*src), val);
1333#endif
1334 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1335}
1336
1337/* Helper function to find the cached rt in the hash table
1338 * and update bucket pointer to point to the bucket for this
1339 * (daddr, saddr) pair
1340 * Caller must hold rt6_exception_lock
1341 */
1342static struct rt6_exception *
1343__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1344 const struct in6_addr *daddr,
1345 const struct in6_addr *saddr)
1346{
1347 struct rt6_exception *rt6_ex;
1348 u32 hval;
1349
1350 if (!(*bucket) || !daddr)
1351 return NULL;
1352
1353 hval = rt6_exception_hash(daddr, saddr);
1354 *bucket += hval;
1355
1356 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1357 struct rt6_info *rt6 = rt6_ex->rt6i;
1358 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1359
1360#ifdef CONFIG_IPV6_SUBTREES
1361 if (matched && saddr)
1362 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1363#endif
1364 if (matched)
1365 return rt6_ex;
1366 }
1367 return NULL;
1368}
1369
1370/* Helper function to find the cached rt in the hash table
1371 * and update bucket pointer to point to the bucket for this
1372 * (daddr, saddr) pair
1373 * Caller must hold rcu_read_lock()
1374 */
1375static struct rt6_exception *
1376__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1377 const struct in6_addr *daddr,
1378 const struct in6_addr *saddr)
1379{
1380 struct rt6_exception *rt6_ex;
1381 u32 hval;
1382
1383 WARN_ON_ONCE(!rcu_read_lock_held());
1384
1385 if (!(*bucket) || !daddr)
1386 return NULL;
1387
1388 hval = rt6_exception_hash(daddr, saddr);
1389 *bucket += hval;
1390
1391 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1392 struct rt6_info *rt6 = rt6_ex->rt6i;
1393 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1394
1395#ifdef CONFIG_IPV6_SUBTREES
1396 if (matched && saddr)
1397 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1398#endif
1399 if (matched)
1400 return rt6_ex;
1401 }
1402 return NULL;
1403}
1404
David Ahern8d1c8022018-04-17 17:33:26 -07001405static unsigned int fib6_mtu(const struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001406{
David Ahernd4ead6b2018-04-17 17:33:16 -07001407 unsigned int mtu;
1408
David Aherndcd1f572018-04-18 15:39:05 -07001409 if (rt->fib6_pmtu) {
1410 mtu = rt->fib6_pmtu;
1411 } else {
1412 struct net_device *dev = fib6_info_nh_dev(rt);
1413 struct inet6_dev *idev;
1414
1415 rcu_read_lock();
1416 idev = __in6_dev_get(dev);
1417 mtu = idev->cnf.mtu6;
1418 rcu_read_unlock();
1419 }
1420
David Ahernd4ead6b2018-04-17 17:33:16 -07001421 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1422
1423 return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu);
1424}
1425
Wei Wang35732d02017-10-06 12:05:57 -07001426static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern8d1c8022018-04-17 17:33:26 -07001427 struct fib6_info *ort)
Wei Wang35732d02017-10-06 12:05:57 -07001428{
David Ahern5e670d82018-04-17 17:33:14 -07001429 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001430 struct rt6_exception_bucket *bucket;
1431 struct in6_addr *src_key = NULL;
1432 struct rt6_exception *rt6_ex;
1433 int err = 0;
1434
Wei Wang35732d02017-10-06 12:05:57 -07001435 spin_lock_bh(&rt6_exception_lock);
1436
1437 if (ort->exception_bucket_flushed) {
1438 err = -EINVAL;
1439 goto out;
1440 }
1441
1442 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1443 lockdep_is_held(&rt6_exception_lock));
1444 if (!bucket) {
1445 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1446 GFP_ATOMIC);
1447 if (!bucket) {
1448 err = -ENOMEM;
1449 goto out;
1450 }
1451 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1452 }
1453
1454#ifdef CONFIG_IPV6_SUBTREES
1455 /* rt6i_src.plen != 0 indicates ort is in subtree
1456 * and exception table is indexed by a hash of
1457 * both rt6i_dst and rt6i_src.
1458 * Otherwise, the exception table is indexed by
1459 * a hash of only rt6i_dst.
1460 */
David Ahern93c2fb22018-04-18 15:38:59 -07001461 if (ort->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001462 src_key = &nrt->rt6i_src.addr;
1463#endif
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001464 /* rt6_mtu_change() might lower mtu on ort.
1465 * Only insert this exception route if its mtu
1466 * is less than ort's mtu value.
1467 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001468 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(ort)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001469 err = -EINVAL;
1470 goto out;
1471 }
Wei Wang60006a42017-10-06 12:05:58 -07001472
Wei Wang35732d02017-10-06 12:05:57 -07001473 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1474 src_key);
1475 if (rt6_ex)
1476 rt6_remove_exception(bucket, rt6_ex);
1477
1478 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1479 if (!rt6_ex) {
1480 err = -ENOMEM;
1481 goto out;
1482 }
1483 rt6_ex->rt6i = nrt;
1484 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001485 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1486 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001487 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001488
1489 if (bucket->depth > FIB6_MAX_DEPTH)
1490 rt6_exception_remove_oldest(bucket);
1491
1492out:
1493 spin_unlock_bh(&rt6_exception_lock);
1494
1495 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001496 if (!err) {
David Ahern93c2fb22018-04-18 15:38:59 -07001497 spin_lock_bh(&ort->fib6_table->tb6_lock);
David Ahern7aef6852018-04-17 17:33:10 -07001498 fib6_update_sernum(net, ort);
David Ahern93c2fb22018-04-18 15:38:59 -07001499 spin_unlock_bh(&ort->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001500 fib6_force_start_gc(net);
1501 }
Wei Wang35732d02017-10-06 12:05:57 -07001502
1503 return err;
1504}
1505
David Ahern8d1c8022018-04-17 17:33:26 -07001506void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001507{
1508 struct rt6_exception_bucket *bucket;
1509 struct rt6_exception *rt6_ex;
1510 struct hlist_node *tmp;
1511 int i;
1512
1513 spin_lock_bh(&rt6_exception_lock);
1514 /* Prevent rt6_insert_exception() to recreate the bucket list */
1515 rt->exception_bucket_flushed = 1;
1516
1517 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1518 lockdep_is_held(&rt6_exception_lock));
1519 if (!bucket)
1520 goto out;
1521
1522 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1523 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1524 rt6_remove_exception(bucket, rt6_ex);
1525 WARN_ON_ONCE(bucket->depth);
1526 bucket++;
1527 }
1528
1529out:
1530 spin_unlock_bh(&rt6_exception_lock);
1531}
1532
1533/* Find cached rt in the hash table inside passed in rt
1534 * Caller has to hold rcu_read_lock()
1535 */
David Ahern8d1c8022018-04-17 17:33:26 -07001536static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -07001537 struct in6_addr *daddr,
1538 struct in6_addr *saddr)
1539{
1540 struct rt6_exception_bucket *bucket;
1541 struct in6_addr *src_key = NULL;
1542 struct rt6_exception *rt6_ex;
1543 struct rt6_info *res = NULL;
1544
1545 bucket = rcu_dereference(rt->rt6i_exception_bucket);
1546
1547#ifdef CONFIG_IPV6_SUBTREES
1548 /* rt6i_src.plen != 0 indicates rt is in subtree
1549 * and exception table is indexed by a hash of
1550 * both rt6i_dst and rt6i_src.
1551 * Otherwise, the exception table is indexed by
1552 * a hash of only rt6i_dst.
1553 */
David Ahern93c2fb22018-04-18 15:38:59 -07001554 if (rt->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001555 src_key = saddr;
1556#endif
1557 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1558
1559 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1560 res = rt6_ex->rt6i;
1561
1562 return res;
1563}
1564
1565/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001566static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001567{
Wei Wang35732d02017-10-06 12:05:57 -07001568 struct rt6_exception_bucket *bucket;
1569 struct in6_addr *src_key = NULL;
1570 struct rt6_exception *rt6_ex;
David Ahern8a14e462018-04-23 11:32:07 -07001571 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001572 int err;
1573
Eric Dumazet091311d2018-04-24 09:22:49 -07001574 from = rcu_dereference(rt->from);
Wei Wang35732d02017-10-06 12:05:57 -07001575 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001576 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001577 return -EINVAL;
1578
1579 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1580 return -ENOENT;
1581
1582 spin_lock_bh(&rt6_exception_lock);
1583 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1584 lockdep_is_held(&rt6_exception_lock));
1585#ifdef CONFIG_IPV6_SUBTREES
1586 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1587 * and exception table is indexed by a hash of
1588 * both rt6i_dst and rt6i_src.
1589 * Otherwise, the exception table is indexed by
1590 * a hash of only rt6i_dst.
1591 */
David Ahern93c2fb22018-04-18 15:38:59 -07001592 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001593 src_key = &rt->rt6i_src.addr;
1594#endif
1595 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1596 &rt->rt6i_dst.addr,
1597 src_key);
1598 if (rt6_ex) {
1599 rt6_remove_exception(bucket, rt6_ex);
1600 err = 0;
1601 } else {
1602 err = -ENOENT;
1603 }
1604
1605 spin_unlock_bh(&rt6_exception_lock);
1606 return err;
1607}
1608
1609/* Find rt6_ex which contains the passed in rt cache and
1610 * refresh its stamp
1611 */
1612static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1613{
Wei Wang35732d02017-10-06 12:05:57 -07001614 struct rt6_exception_bucket *bucket;
1615 struct in6_addr *src_key = NULL;
1616 struct rt6_exception *rt6_ex;
Paolo Abeni193f3682019-02-21 11:19:41 +01001617 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001618
1619 rcu_read_lock();
Paolo Abeni193f3682019-02-21 11:19:41 +01001620 from = rcu_dereference(rt->from);
1621 if (!from || !(rt->rt6i_flags & RTF_CACHE))
1622 goto unlock;
1623
Wei Wang35732d02017-10-06 12:05:57 -07001624 bucket = rcu_dereference(from->rt6i_exception_bucket);
1625
1626#ifdef CONFIG_IPV6_SUBTREES
1627 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1628 * and exception table is indexed by a hash of
1629 * both rt6i_dst and rt6i_src.
1630 * Otherwise, the exception table is indexed by
1631 * a hash of only rt6i_dst.
1632 */
David Ahern93c2fb22018-04-18 15:38:59 -07001633 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001634 src_key = &rt->rt6i_src.addr;
1635#endif
1636 rt6_ex = __rt6_find_exception_rcu(&bucket,
1637 &rt->rt6i_dst.addr,
1638 src_key);
1639 if (rt6_ex)
1640 rt6_ex->stamp = jiffies;
1641
Paolo Abeni193f3682019-02-21 11:19:41 +01001642unlock:
Wei Wang35732d02017-10-06 12:05:57 -07001643 rcu_read_unlock();
1644}
1645
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001646static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1647 struct rt6_info *rt, int mtu)
1648{
1649 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1650 * lowest MTU in the path: always allow updating the route PMTU to
1651 * reflect PMTU decreases.
1652 *
1653 * If the new MTU is higher, and the route PMTU is equal to the local
1654 * MTU, this means the old MTU is the lowest in the path, so allow
1655 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1656 * handle this.
1657 */
1658
1659 if (dst_mtu(&rt->dst) >= mtu)
1660 return true;
1661
1662 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1663 return true;
1664
1665 return false;
1666}
1667
1668static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001669 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001670{
1671 struct rt6_exception_bucket *bucket;
1672 struct rt6_exception *rt6_ex;
1673 int i;
1674
1675 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1676 lockdep_is_held(&rt6_exception_lock));
1677
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001678 if (!bucket)
1679 return;
1680
1681 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1682 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1683 struct rt6_info *entry = rt6_ex->rt6i;
1684
1685 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001686 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001687 * been updated.
1688 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001689 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001690 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001691 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001692 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001693 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001694 }
1695}
1696
Wei Wangb16cb452017-10-06 12:06:00 -07001697#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1698
David Ahern8d1c8022018-04-17 17:33:26 -07001699static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001700 struct in6_addr *gateway)
1701{
1702 struct rt6_exception_bucket *bucket;
1703 struct rt6_exception *rt6_ex;
1704 struct hlist_node *tmp;
1705 int i;
1706
1707 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1708 return;
1709
1710 spin_lock_bh(&rt6_exception_lock);
1711 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1712 lockdep_is_held(&rt6_exception_lock));
1713
1714 if (bucket) {
1715 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1716 hlist_for_each_entry_safe(rt6_ex, tmp,
1717 &bucket->chain, hlist) {
1718 struct rt6_info *entry = rt6_ex->rt6i;
1719
1720 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1721 RTF_CACHE_GATEWAY &&
1722 ipv6_addr_equal(gateway,
1723 &entry->rt6i_gateway)) {
1724 rt6_remove_exception(bucket, rt6_ex);
1725 }
1726 }
1727 bucket++;
1728 }
1729 }
1730
1731 spin_unlock_bh(&rt6_exception_lock);
1732}
1733
Wei Wangc757faa2017-10-06 12:06:01 -07001734static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1735 struct rt6_exception *rt6_ex,
1736 struct fib6_gc_args *gc_args,
1737 unsigned long now)
1738{
1739 struct rt6_info *rt = rt6_ex->rt6i;
1740
Paolo Abeni1859bac2017-10-19 16:07:11 +02001741 /* we are pruning and obsoleting aged-out and non gateway exceptions
1742 * even if others have still references to them, so that on next
1743 * dst_check() such references can be dropped.
1744 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1745 * expired, independently from their aging, as per RFC 8201 section 4
1746 */
Wei Wang31afeb42018-01-26 11:40:17 -08001747 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1748 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1749 RT6_TRACE("aging clone %p\n", rt);
1750 rt6_remove_exception(bucket, rt6_ex);
1751 return;
1752 }
1753 } else if (time_after(jiffies, rt->dst.expires)) {
1754 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001755 rt6_remove_exception(bucket, rt6_ex);
1756 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001757 }
1758
1759 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001760 struct neighbour *neigh;
1761 __u8 neigh_flags = 0;
1762
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001763 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1764 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001765 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001766
Wei Wangc757faa2017-10-06 12:06:01 -07001767 if (!(neigh_flags & NTF_ROUTER)) {
1768 RT6_TRACE("purging route %p via non-router but gateway\n",
1769 rt);
1770 rt6_remove_exception(bucket, rt6_ex);
1771 return;
1772 }
1773 }
Wei Wang31afeb42018-01-26 11:40:17 -08001774
Wei Wangc757faa2017-10-06 12:06:01 -07001775 gc_args->more++;
1776}
1777
David Ahern8d1c8022018-04-17 17:33:26 -07001778void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001779 struct fib6_gc_args *gc_args,
1780 unsigned long now)
1781{
1782 struct rt6_exception_bucket *bucket;
1783 struct rt6_exception *rt6_ex;
1784 struct hlist_node *tmp;
1785 int i;
1786
1787 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1788 return;
1789
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001790 rcu_read_lock_bh();
1791 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001792 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1793 lockdep_is_held(&rt6_exception_lock));
1794
1795 if (bucket) {
1796 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1797 hlist_for_each_entry_safe(rt6_ex, tmp,
1798 &bucket->chain, hlist) {
1799 rt6_age_examine_exception(bucket, rt6_ex,
1800 gc_args, now);
1801 }
1802 bucket++;
1803 }
1804 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001805 spin_unlock(&rt6_exception_lock);
1806 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001807}
1808
David Ahern1d053da2018-05-09 20:34:21 -07001809/* must be called with rcu lock held */
1810struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
1811 int oif, struct flowi6 *fl6, int strict)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001813 struct fib6_node *fn, *saved_fn;
David Ahern8d1c8022018-04-17 17:33:26 -07001814 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
David Ahern64547432018-05-09 20:34:19 -07001816 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001817 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
David Ahernca254492015-10-12 11:47:10 -07001819 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1820 oif = 0;
1821
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001822redo_rt6_select:
David Ahern23fb93a2018-04-17 17:33:23 -07001823 f6i = rt6_select(net, fn, oif, strict);
David Ahern23fb93a2018-04-17 17:33:23 -07001824 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001825 fn = fib6_backtrack(fn, &fl6->saddr);
1826 if (fn)
1827 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001828 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1829 /* also consider unreachable route */
1830 strict &= ~RT6_LOOKUP_F_REACHABLE;
1831 fn = saved_fn;
1832 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001833 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001834 }
1835
David Ahernd4bea422018-05-09 20:34:24 -07001836 trace_fib6_table_lookup(net, f6i, table, fl6);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001837
David Ahern1d053da2018-05-09 20:34:21 -07001838 return f6i;
1839}
1840
1841struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1842 int oif, struct flowi6 *fl6,
1843 const struct sk_buff *skb, int flags)
1844{
1845 struct fib6_info *f6i;
1846 struct rt6_info *rt;
1847 int strict = 0;
1848
1849 strict |= flags & RT6_LOOKUP_F_IFACE;
1850 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1851 if (net->ipv6.devconf_all->forwarding == 0)
1852 strict |= RT6_LOOKUP_F_REACHABLE;
1853
1854 rcu_read_lock();
1855
1856 f6i = fib6_table_lookup(net, table, oif, fl6, strict);
1857 if (f6i->fib6_nsiblings)
1858 f6i = fib6_multipath_select(net, f6i, fl6, oif, skb, strict);
1859
David Ahern23fb93a2018-04-17 17:33:23 -07001860 if (f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001861 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001862 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001863 dst_hold(&rt->dst);
Wei Wangd3843fe2017-10-06 12:06:06 -07001864 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001865 }
1866
1867 /*Search through exception table */
1868 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1869 if (rt) {
David Ahernd4ead6b2018-04-17 17:33:16 -07001870 if (ip6_hold_safe(net, &rt, true))
Wei Wangd3843fe2017-10-06 12:06:06 -07001871 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001872
Wei Wang66f5d6c2017-10-06 12:06:10 -07001873 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001874 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001875 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahern93c2fb22018-04-18 15:38:59 -07001876 !(f6i->fib6_flags & RTF_GATEWAY))) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001877 /* Create a RTF_CACHE clone which will not be
1878 * owned by the fib6 tree. It is for the special case where
1879 * the daddr in the skb during the neighbor look-up is different
1880 * from the fl6->daddr used to look-up route here.
1881 */
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001882 struct rt6_info *uncached_rt;
1883
David Ahern23fb93a2018-04-17 17:33:23 -07001884 uncached_rt = ip6_rt_cache_alloc(f6i, &fl6->daddr, NULL);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001885
David Ahern4d85cd02018-04-20 15:37:59 -07001886 rcu_read_unlock();
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001887
Wei Wang1cfb71e2017-06-17 10:42:33 -07001888 if (uncached_rt) {
1889 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1890 * No need for another dst_hold()
1891 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001892 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001893 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001894 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001895 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001896 dst_hold(&uncached_rt->dst);
1897 }
David Ahernb8115802015-11-19 12:24:22 -08001898
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001899 return uncached_rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001900 } else {
1901 /* Get a percpu copy */
1902
1903 struct rt6_info *pcpu_rt;
1904
Eric Dumazet951f7882017-10-08 21:07:18 -07001905 local_bh_disable();
David Ahern23fb93a2018-04-17 17:33:23 -07001906 pcpu_rt = rt6_get_pcpu_route(f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001907
David Ahern93531c62018-04-17 17:33:25 -07001908 if (!pcpu_rt)
1909 pcpu_rt = rt6_make_pcpu_route(net, f6i);
1910
Eric Dumazet951f7882017-10-08 21:07:18 -07001911 local_bh_enable();
1912 rcu_read_unlock();
David Ahernd4bea422018-05-09 20:34:24 -07001913
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001914 return pcpu_rt;
1915 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001916}
David Ahern9ff74382016-06-13 13:44:19 -07001917EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001918
David Ahernb75cc8f2018-03-02 08:32:17 -08001919static struct rt6_info *ip6_pol_route_input(struct net *net,
1920 struct fib6_table *table,
1921 struct flowi6 *fl6,
1922 const struct sk_buff *skb,
1923 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001924{
David Ahernb75cc8f2018-03-02 08:32:17 -08001925 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001926}
1927
Mahesh Bandeward409b842016-09-16 12:59:08 -07001928struct dst_entry *ip6_route_input_lookup(struct net *net,
1929 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001930 struct flowi6 *fl6,
1931 const struct sk_buff *skb,
1932 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001933{
1934 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1935 flags |= RT6_LOOKUP_F_IFACE;
1936
David Ahernb75cc8f2018-03-02 08:32:17 -08001937 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001938}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001939EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001940
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001941static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001942 struct flow_keys *keys,
1943 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001944{
1945 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1946 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001947 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001948 const struct ipv6hdr *inner_iph;
1949 const struct icmp6hdr *icmph;
1950 struct ipv6hdr _inner_iph;
Eric Dumazetcea67a22018-04-29 09:54:59 -07001951 struct icmp6hdr _icmph;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001952
1953 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1954 goto out;
1955
Eric Dumazetcea67a22018-04-29 09:54:59 -07001956 icmph = skb_header_pointer(skb, skb_transport_offset(skb),
1957 sizeof(_icmph), &_icmph);
1958 if (!icmph)
1959 goto out;
1960
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001961 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1962 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1963 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1964 icmph->icmp6_type != ICMPV6_PARAMPROB)
1965 goto out;
1966
1967 inner_iph = skb_header_pointer(skb,
1968 skb_transport_offset(skb) + sizeof(*icmph),
1969 sizeof(_inner_iph), &_inner_iph);
1970 if (!inner_iph)
1971 goto out;
1972
1973 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001974 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001975out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001976 if (_flkeys) {
1977 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1978 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1979 keys->tags.flow_label = _flkeys->tags.flow_label;
1980 keys->basic.ip_proto = _flkeys->basic.ip_proto;
1981 } else {
1982 keys->addrs.v6addrs.src = key_iph->saddr;
1983 keys->addrs.v6addrs.dst = key_iph->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02001984 keys->tags.flow_label = ip6_flowlabel(key_iph);
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001985 keys->basic.ip_proto = key_iph->nexthdr;
1986 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001987}
1988
1989/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08001990u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
1991 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001992{
1993 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08001994 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001995
David S. Millerbbfa0472018-03-12 11:09:33 -04001996 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08001997 case 0:
1998 memset(&hash_keys, 0, sizeof(hash_keys));
1999 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2000 if (skb) {
2001 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2002 } else {
2003 hash_keys.addrs.v6addrs.src = fl6->saddr;
2004 hash_keys.addrs.v6addrs.dst = fl6->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02002005 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
David Ahernb4bac172018-03-02 08:32:18 -08002006 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2007 }
2008 break;
2009 case 1:
2010 if (skb) {
2011 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2012 struct flow_keys keys;
2013
2014 /* short-circuit if we already have L4 hash present */
2015 if (skb->l4_hash)
2016 return skb_get_hash_raw(skb) >> 1;
2017
2018 memset(&hash_keys, 0, sizeof(hash_keys));
2019
2020 if (!flkeys) {
2021 skb_flow_dissect_flow_keys(skb, &keys, flag);
2022 flkeys = &keys;
2023 }
2024 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2025 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2026 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2027 hash_keys.ports.src = flkeys->ports.src;
2028 hash_keys.ports.dst = flkeys->ports.dst;
2029 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2030 } else {
2031 memset(&hash_keys, 0, sizeof(hash_keys));
2032 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2033 hash_keys.addrs.v6addrs.src = fl6->saddr;
2034 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2035 hash_keys.ports.src = fl6->fl6_sport;
2036 hash_keys.ports.dst = fl6->fl6_dport;
2037 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2038 }
2039 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002040 }
David Ahern9a2a5372018-03-02 08:32:15 -08002041 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002042
David Ahern9a2a5372018-03-02 08:32:15 -08002043 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002044}
2045
Thomas Grafc71099a2006-08-04 23:20:06 -07002046void ip6_route_input(struct sk_buff *skb)
2047{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002048 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002049 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002050 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002051 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002052 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002053 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002054 .daddr = iph->daddr,
2055 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002056 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002057 .flowi6_mark = skb->mark,
2058 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002059 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002060 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002061
Jiri Benc904af042015-08-20 13:56:31 +02002062 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002063 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002064 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002065
2066 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2067 flkeys = &_flkeys;
2068
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002069 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002070 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002071 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002072 skb_dst_set(skb,
2073 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002074}
2075
David Ahernb75cc8f2018-03-02 08:32:17 -08002076static struct rt6_info *ip6_pol_route_output(struct net *net,
2077 struct fib6_table *table,
2078 struct flowi6 *fl6,
2079 const struct sk_buff *skb,
2080 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002081{
David Ahernb75cc8f2018-03-02 08:32:17 -08002082 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002083}
2084
Paolo Abeni6f21c962016-01-29 12:30:19 +01002085struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2086 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002087{
David Ahernd46a9d62015-10-21 08:42:22 -07002088 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002089
Robert Shearman3ede0bb2018-09-19 13:56:53 +01002090 if (ipv6_addr_type(&fl6->daddr) &
2091 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
David Ahern4c1feac2016-09-10 12:09:56 -07002092 struct dst_entry *dst;
2093
2094 dst = l3mdev_link_scope_lookup(net, fl6);
2095 if (dst)
2096 return dst;
2097 }
David Ahernca254492015-10-12 11:47:10 -07002098
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002099 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002100
David Ahernd46a9d62015-10-21 08:42:22 -07002101 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002102 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002103 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002104 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002105
David Ahernd46a9d62015-10-21 08:42:22 -07002106 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002107 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002108 else if (sk)
2109 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002110
David Ahernb75cc8f2018-03-02 08:32:17 -08002111 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002113EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
David S. Miller2774c132011-03-01 14:59:04 -08002115struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002116{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002117 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002118 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002119 struct dst_entry *new = NULL;
2120
Wei Wang1dbe32522017-06-17 10:42:26 -07002121 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002122 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002123 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002124 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002125 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002126
Changli Gaod8d1f302010-06-10 23:31:35 -07002127 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002128 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002129 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002130 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002131
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002132 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002133
Wei Wang1dbe32522017-06-17 10:42:26 -07002134 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002135 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002136 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002137
2138 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2139#ifdef CONFIG_IPV6_SUBTREES
2140 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2141#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002142 }
2143
David S. Miller69ead7a2011-03-01 14:45:33 -08002144 dst_release(dst_orig);
2145 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002146}
David S. Miller14e50e52007-05-24 18:17:54 -07002147
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148/*
2149 * Destination cache support functions
2150 */
2151
David Ahern8d1c8022018-04-17 17:33:26 -07002152static bool fib6_check(struct fib6_info *f6i, u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002153{
Steffen Klassert36143642017-08-25 09:05:42 +02002154 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002155
David Ahern8ae86972018-04-20 15:38:03 -07002156 if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
David Ahern93531c62018-04-17 17:33:25 -07002157 return false;
2158
2159 if (fib6_check_expired(f6i))
2160 return false;
2161
2162 return true;
2163}
2164
David Aherna68886a2018-04-20 15:38:02 -07002165static struct dst_entry *rt6_check(struct rt6_info *rt,
2166 struct fib6_info *from,
2167 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002168{
Wei Wangc5cff852017-08-21 09:47:10 -07002169 u32 rt_cookie = 0;
2170
David Aherna68886a2018-04-20 15:38:02 -07002171 if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
David Ahern93531c62018-04-17 17:33:25 -07002172 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002173 return NULL;
2174
2175 if (rt6_check_expired(rt))
2176 return NULL;
2177
2178 return &rt->dst;
2179}
2180
David Aherna68886a2018-04-20 15:38:02 -07002181static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2182 struct fib6_info *from,
2183 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002184{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002185 if (!__rt6_check_expired(rt) &&
2186 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Aherna68886a2018-04-20 15:38:02 -07002187 fib6_check(from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002188 return &rt->dst;
2189 else
2190 return NULL;
2191}
2192
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2194{
David Aherna87b7dc2018-04-20 15:38:00 -07002195 struct dst_entry *dst_ret;
David Aherna68886a2018-04-20 15:38:02 -07002196 struct fib6_info *from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 struct rt6_info *rt;
2198
David Aherna87b7dc2018-04-20 15:38:00 -07002199 rt = container_of(dst, struct rt6_info, dst);
2200
2201 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002203 /* All IPV6 dsts are created with ->obsolete set to the value
2204 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2205 * into this function always.
2206 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002207
David Aherna68886a2018-04-20 15:38:02 -07002208 from = rcu_dereference(rt->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002209
David Aherna68886a2018-04-20 15:38:02 -07002210 if (from && (rt->rt6i_flags & RTF_PCPU ||
2211 unlikely(!list_empty(&rt->rt6i_uncached))))
2212 dst_ret = rt6_dst_from_check(rt, from, cookie);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002213 else
David Aherna68886a2018-04-20 15:38:02 -07002214 dst_ret = rt6_check(rt, from, cookie);
David Aherna87b7dc2018-04-20 15:38:00 -07002215
2216 rcu_read_unlock();
2217
2218 return dst_ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219}
2220
2221static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2222{
2223 struct rt6_info *rt = (struct rt6_info *) dst;
2224
2225 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002226 if (rt->rt6i_flags & RTF_CACHE) {
David Ahernc3c14da2018-04-23 11:32:06 -07002227 rcu_read_lock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002228 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002229 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002230 dst = NULL;
2231 }
David Ahernc3c14da2018-04-23 11:32:06 -07002232 rcu_read_unlock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002233 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002235 dst = NULL;
2236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002238 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239}
2240
2241static void ip6_link_failure(struct sk_buff *skb)
2242{
2243 struct rt6_info *rt;
2244
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002245 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Eric Dumazetadf30902009-06-02 05:19:30 +00002247 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 if (rt) {
David Ahern8a14e462018-04-23 11:32:07 -07002249 rcu_read_lock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002250 if (rt->rt6i_flags & RTF_CACHE) {
Xin Long761f6022018-11-14 00:48:28 +08002251 rt6_remove_exception_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002252 } else {
David Aherna68886a2018-04-20 15:38:02 -07002253 struct fib6_info *from;
Wei Wangc5cff852017-08-21 09:47:10 -07002254 struct fib6_node *fn;
2255
David Aherna68886a2018-04-20 15:38:02 -07002256 from = rcu_dereference(rt->from);
2257 if (from) {
2258 fn = rcu_dereference(from->fib6_node);
2259 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2260 fn->fn_sernum = -1;
2261 }
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002262 }
David Ahern8a14e462018-04-23 11:32:07 -07002263 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 }
2265}
2266
David Ahern6a3e0302018-04-20 15:37:57 -07002267static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2268{
David Aherna68886a2018-04-20 15:38:02 -07002269 if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2270 struct fib6_info *from;
2271
2272 rcu_read_lock();
2273 from = rcu_dereference(rt0->from);
2274 if (from)
2275 rt0->dst.expires = from->expires;
2276 rcu_read_unlock();
2277 }
David Ahern6a3e0302018-04-20 15:37:57 -07002278
2279 dst_set_expires(&rt0->dst, timeout);
2280 rt0->rt6i_flags |= RTF_EXPIRES;
2281}
2282
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002283static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2284{
2285 struct net *net = dev_net(rt->dst.dev);
2286
David Ahernd4ead6b2018-04-17 17:33:16 -07002287 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002288 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002289 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2290}
2291
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002292static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2293{
2294 return !(rt->rt6i_flags & RTF_CACHE) &&
Paolo Abeni1490ed22019-02-15 18:15:37 +01002295 (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from));
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002296}
2297
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002298static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2299 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002301 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002302 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
Xin Long19bda362016-10-28 18:18:01 +08002304 if (dst_metric_locked(dst, RTAX_MTU))
2305 return;
2306
Julian Anastasov0dec8792017-02-06 23:14:16 +02002307 if (iph) {
2308 daddr = &iph->daddr;
2309 saddr = &iph->saddr;
2310 } else if (sk) {
2311 daddr = &sk->sk_v6_daddr;
2312 saddr = &inet6_sk(sk)->saddr;
2313 } else {
2314 daddr = NULL;
2315 saddr = NULL;
2316 }
2317 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002318 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2319 if (mtu >= dst_mtu(dst))
2320 return;
David S. Miller81aded22012-06-15 14:54:11 -07002321
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002322 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002323 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002324 /* update rt6_ex->stamp for cache */
2325 if (rt6->rt6i_flags & RTF_CACHE)
2326 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002327 } else if (daddr) {
David Aherna68886a2018-04-20 15:38:02 -07002328 struct fib6_info *from;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002329 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002330
David Ahern4d85cd02018-04-20 15:37:59 -07002331 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07002332 from = rcu_dereference(rt6->from);
2333 nrt6 = ip6_rt_cache_alloc(from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002334 if (nrt6) {
2335 rt6_do_update_pmtu(nrt6, mtu);
David Aherna68886a2018-04-20 15:38:02 -07002336 if (rt6_insert_exception(nrt6, from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002337 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002338 }
David Aherna68886a2018-04-20 15:38:02 -07002339 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 }
2341}
2342
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002343static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2344 struct sk_buff *skb, u32 mtu)
2345{
2346 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2347}
2348
David S. Miller42ae66c2012-06-15 20:01:57 -07002349void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002350 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002351{
2352 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2353 struct dst_entry *dst;
Maciej Żenczykowskidc920952018-09-29 23:44:51 -07002354 struct flowi6 fl6 = {
2355 .flowi6_oif = oif,
2356 .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark),
2357 .daddr = iph->daddr,
2358 .saddr = iph->saddr,
2359 .flowlabel = ip6_flowinfo(iph),
2360 .flowi6_uid = uid,
2361 };
David S. Miller81aded22012-06-15 14:54:11 -07002362
2363 dst = ip6_route_output(net, NULL, &fl6);
2364 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002365 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002366 dst_release(dst);
2367}
2368EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2369
2370void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2371{
David Ahern7ddacfa2018-11-18 10:45:30 -08002372 int oif = sk->sk_bound_dev_if;
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002373 struct dst_entry *dst;
2374
David Ahern7ddacfa2018-11-18 10:45:30 -08002375 if (!oif && skb->dev)
2376 oif = l3mdev_master_ifindex(skb->dev);
2377
2378 ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002379
2380 dst = __sk_dst_get(sk);
2381 if (!dst || !dst->obsolete ||
2382 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2383 return;
2384
2385 bh_lock_sock(sk);
2386 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2387 ip6_datagram_dst_update(sk, false);
2388 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002389}
2390EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2391
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002392void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2393 const struct flowi6 *fl6)
2394{
2395#ifdef CONFIG_IPV6_SUBTREES
2396 struct ipv6_pinfo *np = inet6_sk(sk);
2397#endif
2398
2399 ip6_dst_store(sk, dst,
2400 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2401 &sk->sk_v6_daddr : NULL,
2402#ifdef CONFIG_IPV6_SUBTREES
2403 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2404 &np->saddr :
2405#endif
2406 NULL);
2407}
2408
Duan Jiongb55b76b2013-09-04 19:44:21 +08002409/* Handle redirects */
2410struct ip6rd_flowi {
2411 struct flowi6 fl6;
2412 struct in6_addr gateway;
2413};
2414
2415static struct rt6_info *__ip6_route_redirect(struct net *net,
2416 struct fib6_table *table,
2417 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002418 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002419 int flags)
2420{
2421 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern23fb93a2018-04-17 17:33:23 -07002422 struct rt6_info *ret = NULL, *rt_cache;
David Ahern8d1c8022018-04-17 17:33:26 -07002423 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002424 struct fib6_node *fn;
2425
2426 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002427 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002428 *
2429 * RFC 4861 specifies that redirects should only be
2430 * accepted if they come from the nexthop to the target.
2431 * Due to the way the routes are chosen, this notion
2432 * is a bit fuzzy and one might need to check all possible
2433 * routes.
2434 */
2435
Wei Wang66f5d6c2017-10-06 12:06:10 -07002436 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002437 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002438restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002439 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07002440 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +02002441 continue;
David Ahern14895682018-04-17 17:33:17 -07002442 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002443 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002444 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002445 break;
David Ahern93c2fb22018-04-18 15:38:59 -07002446 if (!(rt->fib6_flags & RTF_GATEWAY))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002447 continue;
David Ahern5e670d82018-04-17 17:33:14 -07002448 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002449 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002450 /* rt_cache's gateway might be different from its 'parent'
2451 * in the case of an ip redirect.
2452 * So we keep searching in the exception table if the gateway
2453 * is different.
2454 */
David Ahern5e670d82018-04-17 17:33:14 -07002455 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002456 rt_cache = rt6_find_cached_rt(rt,
2457 &fl6->daddr,
2458 &fl6->saddr);
2459 if (rt_cache &&
2460 ipv6_addr_equal(&rdfl->gateway,
2461 &rt_cache->rt6i_gateway)) {
David Ahern23fb93a2018-04-17 17:33:23 -07002462 ret = rt_cache;
Wei Wang2b760fc2017-10-06 12:06:03 -07002463 break;
2464 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002465 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002466 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002467 break;
2468 }
2469
2470 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002471 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002472 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002473 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002474 goto out;
2475 }
2476
David Ahern421842e2018-04-17 17:33:18 -07002477 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002478 fn = fib6_backtrack(fn, &fl6->saddr);
2479 if (fn)
2480 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002481 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002482
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002483out:
David Ahern23fb93a2018-04-17 17:33:23 -07002484 if (ret)
Wei Wange873e4b2018-07-21 20:56:32 -07002485 ip6_hold_safe(net, &ret, true);
David Ahern23fb93a2018-04-17 17:33:23 -07002486 else
2487 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002488
Wei Wang66f5d6c2017-10-06 12:06:10 -07002489 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002490
Paolo Abenib65f1642017-10-19 09:31:43 +02002491 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002492 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002493};
2494
2495static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002496 const struct flowi6 *fl6,
2497 const struct sk_buff *skb,
2498 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002499{
2500 int flags = RT6_LOOKUP_F_HAS_SADDR;
2501 struct ip6rd_flowi rdfl;
2502
2503 rdfl.fl6 = *fl6;
2504 rdfl.gateway = *gateway;
2505
David Ahernb75cc8f2018-03-02 08:32:17 -08002506 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002507 flags, __ip6_route_redirect);
2508}
2509
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002510void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2511 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002512{
2513 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2514 struct dst_entry *dst;
Maciej Żenczykowski1f7f10a2018-09-29 23:44:48 -07002515 struct flowi6 fl6 = {
2516 .flowi6_iif = LOOPBACK_IFINDEX,
2517 .flowi6_oif = oif,
2518 .flowi6_mark = mark,
2519 .daddr = iph->daddr,
2520 .saddr = iph->saddr,
2521 .flowlabel = ip6_flowinfo(iph),
2522 .flowi6_uid = uid,
2523 };
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002524
David Ahernb75cc8f2018-03-02 08:32:17 -08002525 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002526 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002527 dst_release(dst);
2528}
2529EXPORT_SYMBOL_GPL(ip6_redirect);
2530
Maciej Żenczykowskid4563362018-09-29 23:44:50 -07002531void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
Duan Jiongc92a59e2013-08-22 12:07:35 +08002532{
2533 const struct ipv6hdr *iph = ipv6_hdr(skb);
2534 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2535 struct dst_entry *dst;
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002536 struct flowi6 fl6 = {
2537 .flowi6_iif = LOOPBACK_IFINDEX,
2538 .flowi6_oif = oif,
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002539 .daddr = msg->dest,
2540 .saddr = iph->daddr,
2541 .flowi6_uid = sock_net_uid(net, NULL),
2542 };
Duan Jiongc92a59e2013-08-22 12:07:35 +08002543
David Ahernb75cc8f2018-03-02 08:32:17 -08002544 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002545 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002546 dst_release(dst);
2547}
2548
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002549void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2550{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002551 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2552 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002553}
2554EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2555
David S. Miller0dbaee32010-12-13 12:52:14 -08002556static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557{
David S. Miller0dbaee32010-12-13 12:52:14 -08002558 struct net_device *dev = dst->dev;
2559 unsigned int mtu = dst_mtu(dst);
2560 struct net *net = dev_net(dev);
2561
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2563
Daniel Lezcano55786892008-03-04 13:47:47 -08002564 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2565 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
2567 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002568 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2569 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2570 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 * rely only on pmtu discovery"
2572 */
2573 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2574 mtu = IPV6_MAXPLEN;
2575 return mtu;
2576}
2577
Steffen Klassertebb762f2011-11-23 02:12:51 +00002578static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002579{
David S. Millerd33e4552010-12-14 13:01:14 -08002580 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002581 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002582
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002583 mtu = dst_metric_raw(dst, RTAX_MTU);
2584 if (mtu)
2585 goto out;
2586
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002587 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002588
2589 rcu_read_lock();
2590 idev = __in6_dev_get(dst->dev);
2591 if (idev)
2592 mtu = idev->cnf.mtu6;
2593 rcu_read_unlock();
2594
Eric Dumazet30f78d82014-04-10 21:23:36 -07002595out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002596 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2597
2598 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002599}
2600
David Ahern901731b2018-05-21 09:08:14 -07002601/* MTU selection:
2602 * 1. mtu on route is locked - use it
2603 * 2. mtu from nexthop exception
2604 * 3. mtu from egress device
2605 *
2606 * based on ip6_dst_mtu_forward and exception logic of
2607 * rt6_find_cached_rt; called with rcu_read_lock
2608 */
2609u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
2610 struct in6_addr *saddr)
2611{
2612 struct rt6_exception_bucket *bucket;
2613 struct rt6_exception *rt6_ex;
2614 struct in6_addr *src_key;
2615 struct inet6_dev *idev;
2616 u32 mtu = 0;
2617
2618 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2619 mtu = f6i->fib6_pmtu;
2620 if (mtu)
2621 goto out;
2622 }
2623
2624 src_key = NULL;
2625#ifdef CONFIG_IPV6_SUBTREES
2626 if (f6i->fib6_src.plen)
2627 src_key = saddr;
2628#endif
2629
2630 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2631 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2632 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2633 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2634
2635 if (likely(!mtu)) {
2636 struct net_device *dev = fib6_info_nh_dev(f6i);
2637
2638 mtu = IPV6_MIN_MTU;
2639 idev = __in6_dev_get(dev);
2640 if (idev && idev->cnf.mtu6 > mtu)
2641 mtu = idev->cnf.mtu6;
2642 }
2643
2644 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2645out:
2646 return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu);
2647}
2648
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002649struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002650 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651{
David S. Miller87a11572011-12-06 17:04:13 -05002652 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 struct rt6_info *rt;
2654 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002655 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
David S. Miller38308472011-12-03 18:02:47 -05002657 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002658 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
Martin KaFai Lauad706862015-08-14 11:05:52 -07002660 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002661 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002663 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 goto out;
2665 }
2666
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002667 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002668 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002669 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002670 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002671 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002672 rt->rt6i_dst.plen = 128;
2673 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002674 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Ido Schimmel4c981e22018-01-07 12:45:04 +02002676 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002677 * do proper release of the net_device
2678 */
2679 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002680 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
David S. Miller87a11572011-12-06 17:04:13 -05002682 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684out:
David S. Miller87a11572011-12-06 17:04:13 -05002685 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686}
2687
Daniel Lezcano569d3642008-01-18 03:56:57 -08002688static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002690 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002691 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2692 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2693 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2694 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2695 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002696 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Eric Dumazetfc66f952010-10-08 06:37:34 +00002698 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002699 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002700 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 goto out;
2702
Benjamin Thery6891a342008-03-04 13:49:47 -08002703 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002704 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002705 entries = dst_entries_get_slow(ops);
2706 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002707 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002709 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002710 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711}
2712
David Ahern8c145862016-04-24 21:26:04 -07002713static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2714 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002715 const struct in6_addr *gw_addr,
2716 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002717{
2718 struct flowi6 fl6 = {
2719 .flowi6_oif = cfg->fc_ifindex,
2720 .daddr = *gw_addr,
2721 .saddr = cfg->fc_prefsrc,
2722 };
2723 struct fib6_table *table;
2724 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002725
David Ahernf4797b32018-01-25 16:55:08 -08002726 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002727 if (!table)
2728 return NULL;
2729
2730 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2731 flags |= RT6_LOOKUP_F_HAS_SADDR;
2732
David Ahernf4797b32018-01-25 16:55:08 -08002733 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002734 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002735
2736 /* if table lookup failed, fall back to full lookup */
2737 if (rt == net->ipv6.ip6_null_entry) {
2738 ip6_rt_put(rt);
2739 rt = NULL;
2740 }
2741
2742 return rt;
2743}
2744
David Ahernfc1e64e2018-01-25 16:55:09 -08002745static int ip6_route_check_nh_onlink(struct net *net,
2746 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002747 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002748 struct netlink_ext_ack *extack)
2749{
David Ahern44750f82018-02-06 13:17:06 -08002750 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002751 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2752 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002753 struct fib6_info *from;
David Ahernfc1e64e2018-01-25 16:55:09 -08002754 struct rt6_info *grt;
2755 int err;
2756
2757 err = 0;
2758 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2759 if (grt) {
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002760 rcu_read_lock();
2761 from = rcu_dereference(grt->from);
David Ahern58e354c2018-02-06 12:14:12 -08002762 if (!grt->dst.error &&
David Ahern4ed591c2018-10-24 13:58:39 -07002763 /* ignore match if it is the default route */
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002764 from && !ipv6_addr_any(&from->fib6_dst.addr) &&
David Ahern58e354c2018-02-06 12:14:12 -08002765 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002766 NL_SET_ERR_MSG(extack,
2767 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002768 err = -EINVAL;
2769 }
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002770 rcu_read_unlock();
David Ahernfc1e64e2018-01-25 16:55:09 -08002771
2772 ip6_rt_put(grt);
2773 }
2774
2775 return err;
2776}
2777
David Ahern1edce992018-01-25 16:55:07 -08002778static int ip6_route_check_nh(struct net *net,
2779 struct fib6_config *cfg,
2780 struct net_device **_dev,
2781 struct inet6_dev **idev)
2782{
2783 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2784 struct net_device *dev = _dev ? *_dev : NULL;
2785 struct rt6_info *grt = NULL;
2786 int err = -EHOSTUNREACH;
2787
2788 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002789 int flags = RT6_LOOKUP_F_IFACE;
2790
2791 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2792 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002793 if (grt) {
2794 if (grt->rt6i_flags & RTF_GATEWAY ||
2795 (dev && dev != grt->dst.dev)) {
2796 ip6_rt_put(grt);
2797 grt = NULL;
2798 }
2799 }
2800 }
2801
2802 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002803 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002804
2805 if (!grt)
2806 goto out;
2807
2808 if (dev) {
2809 if (dev != grt->dst.dev) {
2810 ip6_rt_put(grt);
2811 goto out;
2812 }
2813 } else {
2814 *_dev = dev = grt->dst.dev;
2815 *idev = grt->rt6i_idev;
2816 dev_hold(dev);
2817 in6_dev_hold(grt->rt6i_idev);
2818 }
2819
2820 if (!(grt->rt6i_flags & RTF_GATEWAY))
2821 err = 0;
2822
2823 ip6_rt_put(grt);
2824
2825out:
2826 return err;
2827}
2828
David Ahern9fbb7042018-03-13 08:29:36 -07002829static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2830 struct net_device **_dev, struct inet6_dev **idev,
2831 struct netlink_ext_ack *extack)
2832{
2833 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2834 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002835 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002836 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002837 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002838 int err = -EINVAL;
2839
2840 /* if gw_addr is local we will fail to detect this in case
2841 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2842 * will return already-added prefix route via interface that
2843 * prefix route was assigned to, which might be non-loopback.
2844 */
David Ahern232378e2018-03-13 08:29:37 -07002845 if (dev &&
2846 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2847 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002848 goto out;
2849 }
2850
2851 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2852 /* IPv6 strictly inhibits using not link-local
2853 * addresses as nexthop address.
2854 * Otherwise, router will not able to send redirects.
2855 * It is very good, but in some (rare!) circumstances
2856 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2857 * some exceptions. --ANK
2858 * We allow IPv4-mapped nexthops to support RFC4798-type
2859 * addressing
2860 */
2861 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2862 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2863 goto out;
2864 }
2865
2866 if (cfg->fc_flags & RTNH_F_ONLINK)
2867 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2868 else
2869 err = ip6_route_check_nh(net, cfg, _dev, idev);
2870
2871 if (err)
2872 goto out;
2873 }
2874
2875 /* reload in case device was changed */
2876 dev = *_dev;
2877
2878 err = -EINVAL;
2879 if (!dev) {
2880 NL_SET_ERR_MSG(extack, "Egress device not specified");
2881 goto out;
2882 } else if (dev->flags & IFF_LOOPBACK) {
2883 NL_SET_ERR_MSG(extack,
2884 "Egress device can not be loopback device for this route");
2885 goto out;
2886 }
David Ahern232378e2018-03-13 08:29:37 -07002887
2888 /* if we did not check gw_addr above, do so now that the
2889 * egress device has been resolved.
2890 */
2891 if (need_addr_check &&
2892 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2893 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2894 goto out;
2895 }
2896
David Ahern9fbb7042018-03-13 08:29:36 -07002897 err = 0;
2898out:
2899 return err;
2900}
2901
David Ahern8d1c8022018-04-17 17:33:26 -07002902static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07002903 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06002904 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905{
Daniel Lezcano55786892008-03-04 13:47:47 -08002906 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07002907 struct fib6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 struct net_device *dev = NULL;
2909 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002910 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002912 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
David Ahern557c44b2017-04-19 14:19:43 -07002914 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002915 if (cfg->fc_flags & RTF_PCPU) {
2916 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002917 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002918 }
David Ahern557c44b2017-04-19 14:19:43 -07002919
Wei Wang2ea23522017-10-27 17:30:12 -07002920 /* RTF_CACHE is an internal flag; can not be set by userspace */
2921 if (cfg->fc_flags & RTF_CACHE) {
2922 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2923 goto out;
2924 }
2925
David Aherne8478e82018-04-17 17:33:13 -07002926 if (cfg->fc_type > RTN_MAX) {
2927 NL_SET_ERR_MSG(extack, "Invalid route type");
2928 goto out;
2929 }
2930
David Ahernd5d531c2017-05-21 10:12:05 -06002931 if (cfg->fc_dst_len > 128) {
2932 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002933 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002934 }
2935 if (cfg->fc_src_len > 128) {
2936 NL_SET_ERR_MSG(extack, "Invalid source address length");
2937 goto out;
2938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002940 if (cfg->fc_src_len) {
2941 NL_SET_ERR_MSG(extack,
2942 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002943 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002946 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002948 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 if (!dev)
2950 goto out;
2951 idev = in6_dev_get(dev);
2952 if (!idev)
2953 goto out;
2954 }
2955
Thomas Graf86872cb2006-08-22 00:01:08 -07002956 if (cfg->fc_metric == 0)
2957 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
David Ahernfc1e64e2018-01-25 16:55:09 -08002959 if (cfg->fc_flags & RTNH_F_ONLINK) {
2960 if (!dev) {
2961 NL_SET_ERR_MSG(extack,
2962 "Nexthop device required for onlink");
2963 err = -ENODEV;
2964 goto out;
2965 }
2966
2967 if (!(dev->flags & IFF_UP)) {
2968 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2969 err = -ENETDOWN;
2970 goto out;
2971 }
2972 }
2973
Matti Vaittinend71314b2011-11-14 00:14:49 +00002974 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002975 if (cfg->fc_nlinfo.nlh &&
2976 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00002977 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002978 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00002979 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00002980 table = fib6_new_table(net, cfg->fc_table);
2981 }
2982 } else {
2983 table = fib6_new_table(net, cfg->fc_table);
2984 }
David S. Miller38308472011-12-03 18:02:47 -05002985
2986 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002987 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07002988
David Ahern93531c62018-04-17 17:33:25 -07002989 err = -ENOMEM;
2990 rt = fib6_info_alloc(gfp_flags);
2991 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 goto out;
David Ahern93531c62018-04-17 17:33:25 -07002993
David Ahernd7e774f2018-11-06 12:51:15 -08002994 rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
2995 extack);
David Ahern767a2212018-10-04 20:07:51 -07002996 if (IS_ERR(rt->fib6_metrics)) {
2997 err = PTR_ERR(rt->fib6_metrics);
Eric Dumazetfda21d42018-10-05 09:17:50 -07002998 /* Do not leave garbage there. */
2999 rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
David Ahern767a2212018-10-04 20:07:51 -07003000 goto out;
3001 }
3002
David Ahern93531c62018-04-17 17:33:25 -07003003 if (cfg->fc_flags & RTF_ADDRCONF)
3004 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
Gao feng1716a962012-04-06 00:13:10 +00003006 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07003007 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00003008 clock_t_to_jiffies(cfg->fc_expires));
3009 else
David Ahern14895682018-04-17 17:33:17 -07003010 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Thomas Graf86872cb2006-08-22 00:01:08 -07003012 if (cfg->fc_protocol == RTPROT_UNSPEC)
3013 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003014 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003015
3016 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003018 if (cfg->fc_encap) {
3019 struct lwtunnel_state *lwtstate;
3020
David Ahern30357d72017-01-30 12:07:37 -08003021 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07003022 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06003023 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003024 if (err)
3025 goto out;
David Ahern5e670d82018-04-17 17:33:14 -07003026 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003027 }
3028
David Ahern93c2fb22018-04-18 15:38:59 -07003029 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3030 rt->fib6_dst.plen = cfg->fc_dst_len;
3031 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003032 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003033
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003035 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3036 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037#endif
3038
David Ahern93c2fb22018-04-18 15:38:59 -07003039 rt->fib6_metric = cfg->fc_metric;
David Ahern5e670d82018-04-17 17:33:14 -07003040 rt->fib6_nh.nh_weight = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
David Aherne8478e82018-04-17 17:33:13 -07003042 rt->fib6_type = cfg->fc_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
3044 /* We cannot add true routes via loopback here,
3045 they would result in kernel looping; promote them to reject routes
3046 */
Thomas Graf86872cb2006-08-22 00:01:08 -07003047 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05003048 (dev && (dev->flags & IFF_LOOPBACK) &&
3049 !(addr_type & IPV6_ADDR_LOOPBACK) &&
3050 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08003052 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 if (dev) {
3054 dev_put(dev);
3055 in6_dev_put(idev);
3056 }
Daniel Lezcano55786892008-03-04 13:47:47 -08003057 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 dev_hold(dev);
3059 idev = in6_dev_get(dev);
3060 if (!idev) {
3061 err = -ENODEV;
3062 goto out;
3063 }
3064 }
David Ahern93c2fb22018-04-18 15:38:59 -07003065 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 goto install_route;
3067 }
3068
Thomas Graf86872cb2006-08-22 00:01:08 -07003069 if (cfg->fc_flags & RTF_GATEWAY) {
David Ahern9fbb7042018-03-13 08:29:36 -07003070 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3071 if (err)
Florian Westphal48ed7b22015-05-21 00:25:41 +02003072 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
David Ahern93531c62018-04-17 17:33:25 -07003074 rt->fib6_nh.nh_gw = cfg->fc_gateway;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 }
3076
3077 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05003078 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 goto out;
3080
Lorenzo Bianconi428604f2018-03-29 11:02:24 +02003081 if (idev->cnf.disable_ipv6) {
3082 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3083 err = -EACCES;
3084 goto out;
3085 }
3086
David Ahern955ec4c2018-01-24 19:45:29 -08003087 if (!(dev->flags & IFF_UP)) {
3088 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3089 err = -ENETDOWN;
3090 goto out;
3091 }
3092
Daniel Walterc3968a82011-04-13 21:10:57 +00003093 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
3094 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003095 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003096 err = -EINVAL;
3097 goto out;
3098 }
David Ahern93c2fb22018-04-18 15:38:59 -07003099 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3100 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003101 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003102 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003103
David Ahern93c2fb22018-04-18 15:38:59 -07003104 rt->fib6_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
3106install_route:
David Ahern93c2fb22018-04-18 15:38:59 -07003107 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
Ido Schimmel5609b802018-01-07 12:45:06 +02003108 !netif_carrier_ok(dev))
David Ahern5e670d82018-04-17 17:33:14 -07003109 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
3110 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
David Ahern93531c62018-04-17 17:33:25 -07003111 rt->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07003112 rt->fib6_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003113
David Aherndcd1f572018-04-18 15:39:05 -07003114 if (idev)
3115 in6_dev_put(idev);
3116
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003117 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118out:
3119 if (dev)
3120 dev_put(dev);
3121 if (idev)
3122 in6_dev_put(idev);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003123
David Ahern93531c62018-04-17 17:33:25 -07003124 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003125 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003126}
3127
David Ahernacb54e32018-04-17 17:33:22 -07003128int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003129 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003130{
David Ahern8d1c8022018-04-17 17:33:26 -07003131 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003132 int err;
3133
David Ahernacb54e32018-04-17 17:33:22 -07003134 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003135 if (IS_ERR(rt))
3136 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003137
David Ahernd4ead6b2018-04-17 17:33:16 -07003138 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003139 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003140
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 return err;
3142}
3143
David Ahern8d1c8022018-04-17 17:33:26 -07003144static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145{
David Ahernafb1d4b52018-04-17 17:33:11 -07003146 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003147 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003148 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
David Ahern421842e2018-04-17 17:33:18 -07003150 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003151 err = -ENOENT;
3152 goto out;
3153 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003154
David Ahern93c2fb22018-04-18 15:38:59 -07003155 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003156 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003157 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003158 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159
Gao feng6825a262012-09-19 19:25:34 +00003160out:
David Ahern93531c62018-04-17 17:33:25 -07003161 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 return err;
3163}
3164
David Ahern8d1c8022018-04-17 17:33:26 -07003165int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003166{
David Ahernafb1d4b52018-04-17 17:33:11 -07003167 struct nl_info info = { .nl_net = net };
3168
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003169 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003170}
3171
David Ahern8d1c8022018-04-17 17:33:26 -07003172static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003173{
3174 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003175 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003176 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003177 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003178 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003179
David Ahern421842e2018-04-17 17:33:18 -07003180 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003181 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003182 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003183 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003184
David Ahern93c2fb22018-04-18 15:38:59 -07003185 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003186 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003187
David Ahern16a16cd2017-02-02 12:37:11 -08003188 /* prefer to send a single notification with all hops */
3189 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3190 if (skb) {
3191 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3192
David Ahernd4ead6b2018-04-17 17:33:16 -07003193 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003194 NULL, NULL, 0, RTM_DELROUTE,
3195 info->portid, seq, 0) < 0) {
3196 kfree_skb(skb);
3197 skb = NULL;
3198 } else
3199 info->skip_notify = 1;
3200 }
3201
David Ahern0ae81332017-02-02 12:37:08 -08003202 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003203 &rt->fib6_siblings,
3204 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003205 err = fib6_del(sibling, info);
3206 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003207 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003208 }
3209 }
3210
3211 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003212out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003213 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003214out_put:
David Ahern93531c62018-04-17 17:33:25 -07003215 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003216
3217 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003218 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003219 info->nlh, gfp_any());
3220 }
David Ahern0ae81332017-02-02 12:37:08 -08003221 return err;
3222}
3223
David Ahern23fb93a2018-04-17 17:33:23 -07003224static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3225{
3226 int rc = -ESRCH;
3227
3228 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3229 goto out;
3230
3231 if (cfg->fc_flags & RTF_GATEWAY &&
3232 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3233 goto out;
Xin Long761f6022018-11-14 00:48:28 +08003234
3235 rc = rt6_remove_exception_rt(rt);
David Ahern23fb93a2018-04-17 17:33:23 -07003236out:
3237 return rc;
3238}
3239
David Ahern333c4302017-05-21 10:12:04 -06003240static int ip6_route_del(struct fib6_config *cfg,
3241 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242{
David Ahern8d1c8022018-04-17 17:33:26 -07003243 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003244 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003245 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 int err = -ESRCH;
3248
Daniel Lezcano55786892008-03-04 13:47:47 -08003249 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003250 if (!table) {
3251 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003252 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
Wei Wang66f5d6c2017-10-06 12:06:10 -07003255 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003256
3257 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003258 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003259 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003260 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003261
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003263 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003264 if (cfg->fc_flags & RTF_CACHE) {
David Ahern23fb93a2018-04-17 17:33:23 -07003265 int rc;
3266
Wei Wang2b760fc2017-10-06 12:06:03 -07003267 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
3268 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003269 if (rt_cache) {
3270 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003271 if (rc != -ESRCH) {
3272 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003273 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003274 }
David Ahern23fb93a2018-04-17 17:33:23 -07003275 }
3276 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003277 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003278 if (cfg->fc_ifindex &&
David Ahern5e670d82018-04-17 17:33:14 -07003279 (!rt->fib6_nh.nh_dev ||
3280 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003282 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahern5e670d82018-04-17 17:33:14 -07003283 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003285 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003287 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003288 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003289 if (!fib6_info_hold_safe(rt))
3290 continue;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003291 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
David Ahern0ae81332017-02-02 12:37:08 -08003293 /* if gateway was specified only delete the one hop */
3294 if (cfg->fc_flags & RTF_GATEWAY)
3295 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3296
3297 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 }
3299 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003300 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301
3302 return err;
3303}
3304
David S. Miller6700c272012-07-17 03:29:28 -07003305static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003306{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003307 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003308 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003309 struct ndisc_options ndopts;
3310 struct inet6_dev *in6_dev;
3311 struct neighbour *neigh;
David Aherna68886a2018-04-20 15:38:02 -07003312 struct fib6_info *from;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003313 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003314 int optlen, on_link;
3315 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003316
Simon Horman29a3cad2013-05-28 20:34:26 +00003317 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003318 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003319
3320 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003321 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003322 return;
3323 }
3324
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003325 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003326
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003327 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003328 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003329 return;
3330 }
3331
David S. Miller6e157b62012-07-12 00:05:02 -07003332 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003333 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003334 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003335 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003336 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003337 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003338 return;
3339 }
3340
3341 in6_dev = __in6_dev_get(skb->dev);
3342 if (!in6_dev)
3343 return;
3344 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3345 return;
3346
3347 /* RFC2461 8.1:
3348 * The IP source address of the Redirect MUST be the same as the current
3349 * first-hop router for the specified ICMP Destination Address.
3350 */
3351
Alexander Aringf997c552016-06-15 21:20:23 +02003352 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003353 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3354 return;
3355 }
David S. Miller6e157b62012-07-12 00:05:02 -07003356
3357 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003358 if (ndopts.nd_opts_tgt_lladdr) {
3359 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3360 skb->dev);
3361 if (!lladdr) {
3362 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3363 return;
3364 }
3365 }
3366
David S. Miller6e157b62012-07-12 00:05:02 -07003367 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003368 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003369 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3370 return;
3371 }
3372
3373 /* Redirect received -> path was valid.
3374 * Look, redirects are sent only in response to data packets,
3375 * so that this nexthop apparently is reachable. --ANK
3376 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003377 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003378
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003379 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003380 if (!neigh)
3381 return;
3382
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 /*
3384 * We have finally decided to accept it.
3385 */
3386
Alexander Aringf997c552016-06-15 21:20:23 +02003387 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3389 NEIGH_UPDATE_F_OVERRIDE|
3390 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003391 NEIGH_UPDATE_F_ISROUTER)),
3392 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
David Ahern4d85cd02018-04-20 15:37:59 -07003394 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07003395 from = rcu_dereference(rt->from);
Wei Wange873e4b2018-07-21 20:56:32 -07003396 /* This fib6_info_hold() is safe here because we hold reference to rt
3397 * and rt already holds reference to fib6_info.
3398 */
David Ahern8a14e462018-04-23 11:32:07 -07003399 fib6_info_hold(from);
David Ahern4d85cd02018-04-20 15:37:59 -07003400 rcu_read_unlock();
David Ahern8a14e462018-04-23 11:32:07 -07003401
3402 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003403 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 goto out;
3405
3406 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3407 if (on_link)
3408 nrt->rt6i_flags &= ~RTF_GATEWAY;
3409
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003410 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411
Wei Wang2b760fc2017-10-06 12:06:03 -07003412 /* No need to remove rt from the exception table if rt is
3413 * a cached route because rt6_insert_exception() will
3414 * takes care of it
3415 */
David Ahern8a14e462018-04-23 11:32:07 -07003416 if (rt6_insert_exception(nrt, from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003417 dst_release_immediate(&nrt->dst);
3418 goto out;
3419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
Changli Gaod8d1f302010-06-10 23:31:35 -07003421 netevent.old = &rt->dst;
3422 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003423 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003424 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003425 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3426
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427out:
David Ahern8a14e462018-04-23 11:32:07 -07003428 fib6_info_release(from);
David S. Millere8599ff2012-07-11 23:43:53 -07003429 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003430}
3431
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003432#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003433static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003434 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003435 const struct in6_addr *gwaddr,
3436 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003437{
David Ahern830218c2016-10-24 10:52:35 -07003438 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3439 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003440 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003441 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003442 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003443
David Ahern830218c2016-10-24 10:52:35 -07003444 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003445 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003446 return NULL;
3447
Wei Wang66f5d6c2017-10-06 12:06:10 -07003448 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003449 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003450 if (!fn)
3451 goto out;
3452
Wei Wang66f5d6c2017-10-06 12:06:10 -07003453 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07003454 if (rt->fib6_nh.nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003455 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003456 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003457 continue;
David Ahern5e670d82018-04-17 17:33:14 -07003458 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003459 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003460 if (!fib6_info_hold_safe(rt))
3461 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003462 break;
3463 }
3464out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003465 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003466 return rt;
3467}
3468
David Ahern8d1c8022018-04-17 17:33:26 -07003469static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003470 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003471 const struct in6_addr *gwaddr,
3472 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003473 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003474{
Thomas Graf86872cb2006-08-22 00:01:08 -07003475 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003476 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003477 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003478 .fc_dst_len = prefixlen,
3479 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3480 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003481 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003482 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003483 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003484 .fc_nlinfo.nlh = NULL,
3485 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003486 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003487
David Ahern830218c2016-10-24 10:52:35 -07003488 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003489 cfg.fc_dst = *prefix;
3490 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003491
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003492 /* We should treat it as a default route if prefix length is 0. */
3493 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003494 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003495
David Ahernacb54e32018-04-17 17:33:22 -07003496 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003497
David Ahern830218c2016-10-24 10:52:35 -07003498 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003499}
3500#endif
3501
David Ahern8d1c8022018-04-17 17:33:26 -07003502struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003503 const struct in6_addr *addr,
3504 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003505{
David Ahern830218c2016-10-24 10:52:35 -07003506 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003507 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003508 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509
David Ahernafb1d4b52018-04-17 17:33:11 -07003510 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003511 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003512 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513
Wei Wang66f5d6c2017-10-06 12:06:10 -07003514 rcu_read_lock();
3515 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern5e670d82018-04-17 17:33:14 -07003516 if (dev == rt->fib6_nh.nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003517 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahern5e670d82018-04-17 17:33:14 -07003518 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 break;
3520 }
Wei Wange873e4b2018-07-21 20:56:32 -07003521 if (rt && !fib6_info_hold_safe(rt))
3522 rt = NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003523 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 return rt;
3525}
3526
David Ahern8d1c8022018-04-17 17:33:26 -07003527struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003528 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003529 struct net_device *dev,
3530 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531{
Thomas Graf86872cb2006-08-22 00:01:08 -07003532 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003533 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003534 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003535 .fc_ifindex = dev->ifindex,
3536 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3537 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003538 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003539 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003540 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003541 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003542 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003543 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003545 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
David Ahernacb54e32018-04-17 17:33:22 -07003547 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003548 struct fib6_table *table;
3549
3550 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3551 if (table)
3552 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
David Ahernafb1d4b52018-04-17 17:33:11 -07003555 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556}
3557
David Ahernafb1d4b52018-04-17 17:33:11 -07003558static void __rt6_purge_dflt_routers(struct net *net,
3559 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560{
David Ahern8d1c8022018-04-17 17:33:26 -07003561 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
3563restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003564 rcu_read_lock();
3565 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003566 struct net_device *dev = fib6_info_nh_dev(rt);
3567 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3568
David Ahern93c2fb22018-04-18 15:38:59 -07003569 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
Wei Wange873e4b2018-07-21 20:56:32 -07003570 (!idev || idev->cnf.accept_ra != 2) &&
3571 fib6_info_hold_safe(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07003572 rcu_read_unlock();
3573 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 goto restart;
3575 }
3576 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003577 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003578
3579 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3580}
3581
3582void rt6_purge_dflt_routers(struct net *net)
3583{
3584 struct fib6_table *table;
3585 struct hlist_head *head;
3586 unsigned int h;
3587
3588 rcu_read_lock();
3589
3590 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3591 head = &net->ipv6.fib_table_hash[h];
3592 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3593 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003594 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003595 }
3596 }
3597
3598 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599}
3600
Daniel Lezcano55786892008-03-04 13:47:47 -08003601static void rtmsg_to_fib6_config(struct net *net,
3602 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003603 struct fib6_config *cfg)
3604{
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003605 *cfg = (struct fib6_config){
3606 .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3607 : RT6_TABLE_MAIN,
3608 .fc_ifindex = rtmsg->rtmsg_ifindex,
3609 .fc_metric = rtmsg->rtmsg_metric,
3610 .fc_expires = rtmsg->rtmsg_info,
3611 .fc_dst_len = rtmsg->rtmsg_dst_len,
3612 .fc_src_len = rtmsg->rtmsg_src_len,
3613 .fc_flags = rtmsg->rtmsg_flags,
3614 .fc_type = rtmsg->rtmsg_type,
Thomas Graf86872cb2006-08-22 00:01:08 -07003615
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003616 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003617
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003618 .fc_dst = rtmsg->rtmsg_dst,
3619 .fc_src = rtmsg->rtmsg_src,
3620 .fc_gateway = rtmsg->rtmsg_gateway,
3621 };
Thomas Graf86872cb2006-08-22 00:01:08 -07003622}
3623
Daniel Lezcano55786892008-03-04 13:47:47 -08003624int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625{
Thomas Graf86872cb2006-08-22 00:01:08 -07003626 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 struct in6_rtmsg rtmsg;
3628 int err;
3629
Ian Morris67ba4152014-08-24 21:53:10 +01003630 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 case SIOCADDRT: /* Add a route */
3632 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003633 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 return -EPERM;
3635 err = copy_from_user(&rtmsg, arg,
3636 sizeof(struct in6_rtmsg));
3637 if (err)
3638 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003639
Daniel Lezcano55786892008-03-04 13:47:47 -08003640 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003641
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 rtnl_lock();
3643 switch (cmd) {
3644 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003645 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 break;
3647 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003648 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 break;
3650 default:
3651 err = -EINVAL;
3652 }
3653 rtnl_unlock();
3654
3655 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657
3658 return -EINVAL;
3659}
3660
3661/*
3662 * Drop the packet on the floor
3663 */
3664
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003665static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003667 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003668 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003669 switch (ipstats_mib_noroutes) {
3670 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003671 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003672 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003673 IP6_INC_STATS(dev_net(dst->dev),
3674 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003675 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003676 break;
3677 }
3678 /* FALLTHROUGH */
3679 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003680 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3681 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003682 break;
3683 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003684 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 kfree_skb(skb);
3686 return 0;
3687}
3688
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003689static int ip6_pkt_discard(struct sk_buff *skb)
3690{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003691 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003692}
3693
Eric W. Biedermanede20592015-10-07 16:48:47 -05003694static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695{
Eric Dumazetadf30902009-06-02 05:19:30 +00003696 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003697 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698}
3699
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003700static int ip6_pkt_prohibit(struct sk_buff *skb)
3701{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003702 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003703}
3704
Eric W. Biedermanede20592015-10-07 16:48:47 -05003705static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003706{
Eric Dumazetadf30902009-06-02 05:19:30 +00003707 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003708 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003709}
3710
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711/*
3712 * Allocate a dst for local (unicast / anycast) address.
3713 */
3714
David Ahern360a9882018-04-18 15:39:00 -07003715struct fib6_info *addrconf_f6i_alloc(struct net *net,
3716 struct inet6_dev *idev,
3717 const struct in6_addr *addr,
3718 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719{
David Ahernca254492015-10-12 11:47:10 -07003720 u32 tb_id;
David Ahern4832c302017-08-17 12:17:20 -07003721 struct net_device *dev = idev->dev;
David Ahern360a9882018-04-18 15:39:00 -07003722 struct fib6_info *f6i;
David Ahern5f02ce242016-09-10 12:09:54 -07003723
David Ahern360a9882018-04-18 15:39:00 -07003724 f6i = fib6_info_alloc(gfp_flags);
3725 if (!f6i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 return ERR_PTR(-ENOMEM);
3727
David Ahernd7e774f2018-11-06 12:51:15 -08003728 f6i->fib6_metrics = ip_fib_metrics_init(net, NULL, 0, NULL);
David Ahern360a9882018-04-18 15:39:00 -07003729 f6i->dst_nocount = true;
David Ahern360a9882018-04-18 15:39:00 -07003730 f6i->dst_host = true;
3731 f6i->fib6_protocol = RTPROT_KERNEL;
3732 f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
David Aherne8478e82018-04-17 17:33:13 -07003733 if (anycast) {
David Ahern360a9882018-04-18 15:39:00 -07003734 f6i->fib6_type = RTN_ANYCAST;
3735 f6i->fib6_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003736 } else {
David Ahern360a9882018-04-18 15:39:00 -07003737 f6i->fib6_type = RTN_LOCAL;
3738 f6i->fib6_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
David Ahern360a9882018-04-18 15:39:00 -07003741 f6i->fib6_nh.nh_gw = *addr;
David Ahern93531c62018-04-17 17:33:25 -07003742 dev_hold(dev);
David Ahern360a9882018-04-18 15:39:00 -07003743 f6i->fib6_nh.nh_dev = dev;
3744 f6i->fib6_dst.addr = *addr;
3745 f6i->fib6_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003746 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
David Ahern360a9882018-04-18 15:39:00 -07003747 f6i->fib6_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748
David Ahern360a9882018-04-18 15:39:00 -07003749 return f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750}
3751
Daniel Walterc3968a82011-04-13 21:10:57 +00003752/* remove deleted ip from prefsrc entries */
3753struct arg_dev_net_ip {
3754 struct net_device *dev;
3755 struct net *net;
3756 struct in6_addr *addr;
3757};
3758
David Ahern8d1c8022018-04-17 17:33:26 -07003759static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003760{
3761 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3762 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3763 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3764
David Ahern5e670d82018-04-17 17:33:14 -07003765 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003766 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003767 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003768 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003769 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003770 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003771 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003772 }
3773 return 0;
3774}
3775
3776void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3777{
3778 struct net *net = dev_net(ifp->idev->dev);
3779 struct arg_dev_net_ip adni = {
3780 .dev = ifp->idev->dev,
3781 .net = net,
3782 .addr = &ifp->addr,
3783 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003784 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003785}
3786
Duan Jiongbe7a0102014-05-15 15:56:14 +08003787#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003788
3789/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003790static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003791{
3792 struct in6_addr *gateway = (struct in6_addr *)arg;
3793
David Ahern93c2fb22018-04-18 15:38:59 -07003794 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahern5e670d82018-04-17 17:33:14 -07003795 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003796 return -1;
3797 }
Wei Wangb16cb452017-10-06 12:06:00 -07003798
3799 /* Further clean up cached routes in exception table.
3800 * This is needed because cached route may have a different
3801 * gateway than its 'parent' in the case of an ip redirect.
3802 */
3803 rt6_exceptions_clean_tohost(rt, gateway);
3804
Duan Jiongbe7a0102014-05-15 15:56:14 +08003805 return 0;
3806}
3807
3808void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3809{
3810 fib6_clean_all(net, fib6_clean_tohost, gateway);
3811}
3812
Ido Schimmel2127d952018-01-07 12:45:03 +02003813struct arg_netdev_event {
3814 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003815 union {
3816 unsigned int nh_flags;
3817 unsigned long event;
3818 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003819};
3820
David Ahern8d1c8022018-04-17 17:33:26 -07003821static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003822{
David Ahern8d1c8022018-04-17 17:33:26 -07003823 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003824 struct fib6_node *fn;
3825
David Ahern93c2fb22018-04-18 15:38:59 -07003826 fn = rcu_dereference_protected(rt->fib6_node,
3827 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003828 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003829 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003830 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003831 if (iter->fib6_metric == rt->fib6_metric &&
David Ahern33bd5ac2018-07-03 14:36:21 -07003832 rt6_qualify_for_ecmp(iter))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003833 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003834 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003835 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003836 }
3837
3838 return NULL;
3839}
3840
David Ahern8d1c8022018-04-17 17:33:26 -07003841static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003842{
David Ahern5e670d82018-04-17 17:33:14 -07003843 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
3844 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Aherndcd1f572018-04-18 15:39:05 -07003845 fib6_ignore_linkdown(rt)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003846 return true;
3847
3848 return false;
3849}
3850
David Ahern8d1c8022018-04-17 17:33:26 -07003851static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003852{
David Ahern8d1c8022018-04-17 17:33:26 -07003853 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003854 int total = 0;
3855
3856 if (!rt6_is_dead(rt))
David Ahern5e670d82018-04-17 17:33:14 -07003857 total += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003858
David Ahern93c2fb22018-04-18 15:38:59 -07003859 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003860 if (!rt6_is_dead(iter))
David Ahern5e670d82018-04-17 17:33:14 -07003861 total += iter->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003862 }
3863
3864 return total;
3865}
3866
David Ahern8d1c8022018-04-17 17:33:26 -07003867static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003868{
3869 int upper_bound = -1;
3870
3871 if (!rt6_is_dead(rt)) {
David Ahern5e670d82018-04-17 17:33:14 -07003872 *weight += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003873 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3874 total) - 1;
3875 }
David Ahern5e670d82018-04-17 17:33:14 -07003876 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003877}
3878
David Ahern8d1c8022018-04-17 17:33:26 -07003879static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003880{
David Ahern8d1c8022018-04-17 17:33:26 -07003881 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003882 int weight = 0;
3883
3884 rt6_upper_bound_set(rt, &weight, total);
3885
David Ahern93c2fb22018-04-18 15:38:59 -07003886 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003887 rt6_upper_bound_set(iter, &weight, total);
3888}
3889
David Ahern8d1c8022018-04-17 17:33:26 -07003890void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003891{
David Ahern8d1c8022018-04-17 17:33:26 -07003892 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003893 int total;
3894
3895 /* In case the entire multipath route was marked for flushing,
3896 * then there is no need to rebalance upon the removal of every
3897 * sibling route.
3898 */
David Ahern93c2fb22018-04-18 15:38:59 -07003899 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003900 return;
3901
3902 /* During lookup routes are evaluated in order, so we need to
3903 * make sure upper bounds are assigned from the first sibling
3904 * onwards.
3905 */
3906 first = rt6_multipath_first_sibling(rt);
3907 if (WARN_ON_ONCE(!first))
3908 return;
3909
3910 total = rt6_multipath_total_weight(first);
3911 rt6_multipath_upper_bound_set(first, total);
3912}
3913
David Ahern8d1c8022018-04-17 17:33:26 -07003914static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003915{
3916 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003917 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003918
David Ahern421842e2018-04-17 17:33:18 -07003919 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
David Ahern5e670d82018-04-17 17:33:14 -07003920 rt->fib6_nh.nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003921 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003922 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003923 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003924
3925 return 0;
3926}
3927
3928void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3929{
3930 struct arg_netdev_event arg = {
3931 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003932 {
3933 .nh_flags = nh_flags,
3934 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003935 };
3936
3937 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3938 arg.nh_flags |= RTNH_F_LINKDOWN;
3939
3940 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3941}
3942
David Ahern8d1c8022018-04-17 17:33:26 -07003943static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003944 const struct net_device *dev)
3945{
David Ahern8d1c8022018-04-17 17:33:26 -07003946 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003947
David Ahern5e670d82018-04-17 17:33:14 -07003948 if (rt->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003949 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07003950 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003951 if (iter->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003952 return true;
3953
3954 return false;
3955}
3956
David Ahern8d1c8022018-04-17 17:33:26 -07003957static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003958{
David Ahern8d1c8022018-04-17 17:33:26 -07003959 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003960
3961 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07003962 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003963 iter->should_flush = 1;
3964}
3965
David Ahern8d1c8022018-04-17 17:33:26 -07003966static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003967 const struct net_device *down_dev)
3968{
David Ahern8d1c8022018-04-17 17:33:26 -07003969 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003970 unsigned int dead = 0;
3971
David Ahern5e670d82018-04-17 17:33:14 -07003972 if (rt->fib6_nh.nh_dev == down_dev ||
3973 rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003974 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07003975 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003976 if (iter->fib6_nh.nh_dev == down_dev ||
3977 iter->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003978 dead++;
3979
3980 return dead;
3981}
3982
David Ahern8d1c8022018-04-17 17:33:26 -07003983static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003984 const struct net_device *dev,
3985 unsigned int nh_flags)
3986{
David Ahern8d1c8022018-04-17 17:33:26 -07003987 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003988
David Ahern5e670d82018-04-17 17:33:14 -07003989 if (rt->fib6_nh.nh_dev == dev)
3990 rt->fib6_nh.nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07003991 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003992 if (iter->fib6_nh.nh_dev == dev)
3993 iter->fib6_nh.nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003994}
3995
David Aherna1a22c12017-01-18 07:40:36 -08003996/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07003997static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998{
Ido Schimmel4c981e22018-01-07 12:45:04 +02003999 const struct arg_netdev_event *arg = p_arg;
4000 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07004001 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004002
David Ahern421842e2018-04-17 17:33:18 -07004003 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004004 return 0;
4005
4006 switch (arg->event) {
4007 case NETDEV_UNREGISTER:
David Ahern5e670d82018-04-17 17:33:14 -07004008 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004009 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02004010 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004011 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004012 if (!rt->fib6_nsiblings)
David Ahern5e670d82018-04-17 17:33:14 -07004013 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004014 if (rt6_multipath_uses_dev(rt, dev)) {
4015 unsigned int count;
4016
4017 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004018 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004019 rt6_multipath_flush(rt);
4020 return -1;
4021 }
4022 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4023 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004024 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004025 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004026 }
4027 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004028 case NETDEV_CHANGE:
David Ahern5e670d82018-04-17 17:33:14 -07004029 if (rt->fib6_nh.nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004030 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004031 break;
David Ahern5e670d82018-04-17 17:33:14 -07004032 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004033 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004034 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004035 }
David S. Millerc159d302011-12-26 15:24:36 -05004036
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 return 0;
4038}
4039
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004040void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004042 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004043 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004044 {
4045 .event = event,
4046 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004047 };
David Ahern7c6bb7d2018-10-11 20:17:21 -07004048 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004049
David Ahern7c6bb7d2018-10-11 20:17:21 -07004050 if (net->ipv6.sysctl.skip_notify_on_dev_down)
4051 fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
4052 else
4053 fib6_clean_all(net, fib6_ifdown, &arg);
Ido Schimmel4c981e22018-01-07 12:45:04 +02004054}
4055
4056void rt6_disable_ip(struct net_device *dev, unsigned long event)
4057{
4058 rt6_sync_down_dev(dev, event);
4059 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4060 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061}
4062
Eric Dumazet95c96172012-04-15 05:58:06 +00004063struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004065 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066};
4067
David Ahern8d1c8022018-04-17 17:33:26 -07004068static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069{
4070 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4071 struct inet6_dev *idev;
4072
4073 /* In IPv6 pmtu discovery is not optional,
4074 so that RTAX_MTU lock cannot disable it.
4075 We still use this lock to block changes
4076 caused by addrconf/ndisc.
4077 */
4078
4079 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004080 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 return 0;
4082
4083 /* For administrative MTU increase, there is no way to discover
4084 IPv6 PMTU increase, so PMTU increase should be updated here.
4085 Since RFC 1981 doesn't include administrative MTU increase
4086 update PMTU increase is a MUST. (i.e. jumbo frame)
4087 */
David Ahern5e670d82018-04-17 17:33:14 -07004088 if (rt->fib6_nh.nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004089 !fib6_metric_locked(rt, RTAX_MTU)) {
4090 u32 mtu = rt->fib6_pmtu;
4091
4092 if (mtu >= arg->mtu ||
4093 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4094 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4095
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004096 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004097 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004098 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 return 0;
4101}
4102
Eric Dumazet95c96172012-04-15 05:58:06 +00004103void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104{
Thomas Grafc71099a2006-08-04 23:20:06 -07004105 struct rt6_mtu_change_arg arg = {
4106 .dev = dev,
4107 .mtu = mtu,
4108 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109
Li RongQing0c3584d2013-12-27 16:32:38 +08004110 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111}
4112
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004113static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004114 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004115 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004116 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004117 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004118 [RTA_PRIORITY] = { .type = NLA_U32 },
4119 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004120 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004121 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004122 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4123 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004124 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004125 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004126 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004127 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004128 [RTA_IP_PROTO] = { .type = NLA_U8 },
4129 [RTA_SPORT] = { .type = NLA_U16 },
4130 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004131};
4132
4133static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004134 struct fib6_config *cfg,
4135 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136{
Thomas Graf86872cb2006-08-22 00:01:08 -07004137 struct rtmsg *rtm;
4138 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004139 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004140 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141
Johannes Bergfceb6432017-04-12 14:34:07 +02004142 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Aherndac9c972018-10-07 20:16:24 -07004143 extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004144 if (err < 0)
4145 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
Thomas Graf86872cb2006-08-22 00:01:08 -07004147 err = -EINVAL;
4148 rtm = nlmsg_data(nlh);
Thomas Graf86872cb2006-08-22 00:01:08 -07004149
Maciej Żenczykowski84db8402018-09-29 23:44:53 -07004150 *cfg = (struct fib6_config){
4151 .fc_table = rtm->rtm_table,
4152 .fc_dst_len = rtm->rtm_dst_len,
4153 .fc_src_len = rtm->rtm_src_len,
4154 .fc_flags = RTF_UP,
4155 .fc_protocol = rtm->rtm_protocol,
4156 .fc_type = rtm->rtm_type,
4157
4158 .fc_nlinfo.portid = NETLINK_CB(skb).portid,
4159 .fc_nlinfo.nlh = nlh,
4160 .fc_nlinfo.nl_net = sock_net(skb->sk),
4161 };
Thomas Graf86872cb2006-08-22 00:01:08 -07004162
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004163 if (rtm->rtm_type == RTN_UNREACHABLE ||
4164 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004165 rtm->rtm_type == RTN_PROHIBIT ||
4166 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004167 cfg->fc_flags |= RTF_REJECT;
4168
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004169 if (rtm->rtm_type == RTN_LOCAL)
4170 cfg->fc_flags |= RTF_LOCAL;
4171
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004172 if (rtm->rtm_flags & RTM_F_CLONED)
4173 cfg->fc_flags |= RTF_CACHE;
4174
David Ahernfc1e64e2018-01-25 16:55:09 -08004175 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4176
Thomas Graf86872cb2006-08-22 00:01:08 -07004177 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004178 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004179 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 }
David Aherne3818542019-02-26 09:00:03 -08004181 if (tb[RTA_VIA]) {
4182 NL_SET_ERR_MSG(extack, "IPv6 does not support RTA_VIA attribute");
4183 goto errout;
4184 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004185
4186 if (tb[RTA_DST]) {
4187 int plen = (rtm->rtm_dst_len + 7) >> 3;
4188
4189 if (nla_len(tb[RTA_DST]) < plen)
4190 goto errout;
4191
4192 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004194
4195 if (tb[RTA_SRC]) {
4196 int plen = (rtm->rtm_src_len + 7) >> 3;
4197
4198 if (nla_len(tb[RTA_SRC]) < plen)
4199 goto errout;
4200
4201 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004203
Daniel Walterc3968a82011-04-13 21:10:57 +00004204 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004205 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004206
Thomas Graf86872cb2006-08-22 00:01:08 -07004207 if (tb[RTA_OIF])
4208 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4209
4210 if (tb[RTA_PRIORITY])
4211 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4212
4213 if (tb[RTA_METRICS]) {
4214 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4215 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004217
4218 if (tb[RTA_TABLE])
4219 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4220
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004221 if (tb[RTA_MULTIPATH]) {
4222 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4223 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004224
4225 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004226 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004227 if (err < 0)
4228 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004229 }
4230
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004231 if (tb[RTA_PREF]) {
4232 pref = nla_get_u8(tb[RTA_PREF]);
4233 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4234 pref != ICMPV6_ROUTER_PREF_HIGH)
4235 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4236 cfg->fc_flags |= RTF_PREF(pref);
4237 }
4238
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004239 if (tb[RTA_ENCAP])
4240 cfg->fc_encap = tb[RTA_ENCAP];
4241
David Ahern9ed59592017-01-17 14:57:36 -08004242 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004243 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4244
David Ahernc255bd62017-05-27 16:19:27 -06004245 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004246 if (err < 0)
4247 goto errout;
4248 }
4249
Xin Long32bc2012015-12-16 17:50:11 +08004250 if (tb[RTA_EXPIRES]) {
4251 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4252
4253 if (addrconf_finite_timeout(timeout)) {
4254 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4255 cfg->fc_flags |= RTF_EXPIRES;
4256 }
4257 }
4258
Thomas Graf86872cb2006-08-22 00:01:08 -07004259 err = 0;
4260errout:
4261 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262}
4263
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004264struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004265 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004266 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004267 struct list_head next;
4268};
4269
David Ahernd4ead6b2018-04-17 17:33:16 -07004270static int ip6_route_info_append(struct net *net,
4271 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004272 struct fib6_info *rt,
4273 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004274{
4275 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004276 int err = -EEXIST;
4277
4278 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004279 /* check if fib6_info already exists */
4280 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004281 return err;
4282 }
4283
4284 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4285 if (!nh)
4286 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004287 nh->fib6_info = rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004288 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4289 list_add_tail(&nh->next, rt6_nh_list);
4290
4291 return 0;
4292}
4293
David Ahern8d1c8022018-04-17 17:33:26 -07004294static void ip6_route_mpath_notify(struct fib6_info *rt,
4295 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004296 struct nl_info *info,
4297 __u16 nlflags)
4298{
4299 /* if this is an APPEND route, then rt points to the first route
4300 * inserted and rt_last points to last route inserted. Userspace
4301 * wants a consistent dump of the route which starts at the first
4302 * nexthop. Since sibling routes are always added at the end of
4303 * the list, find the first sibling of the last route appended
4304 */
David Ahern93c2fb22018-04-18 15:38:59 -07004305 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4306 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004307 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004308 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004309 }
4310
4311 if (rt)
4312 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4313}
4314
David Ahern333c4302017-05-21 10:12:04 -06004315static int ip6_route_multipath_add(struct fib6_config *cfg,
4316 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004317{
David Ahern8d1c8022018-04-17 17:33:26 -07004318 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004319 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004320 struct fib6_config r_cfg;
4321 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004322 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004323 struct rt6_nh *err_nh;
4324 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004325 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004326 int remaining;
4327 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004328 int err = 1;
4329 int nhn = 0;
4330 int replace = (cfg->fc_nlinfo.nlh &&
4331 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4332 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004333
David Ahern3b1137f2017-02-02 12:37:10 -08004334 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4335 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4336 nlflags |= NLM_F_APPEND;
4337
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004338 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004339 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004340
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004341 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004342 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004343 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004344 while (rtnh_ok(rtnh, remaining)) {
4345 memcpy(&r_cfg, cfg, sizeof(*cfg));
4346 if (rtnh->rtnh_ifindex)
4347 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4348
4349 attrlen = rtnh_attrlen(rtnh);
4350 if (attrlen > 0) {
4351 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4352
4353 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4354 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004355 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004356 r_cfg.fc_flags |= RTF_GATEWAY;
4357 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004358 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4359 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4360 if (nla)
4361 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004362 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004363
David Ahern68e2ffd2018-03-20 10:06:59 -07004364 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004365 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004366 if (IS_ERR(rt)) {
4367 err = PTR_ERR(rt);
4368 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004369 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004370 }
David Ahernb5d2d752018-07-15 09:35:19 -07004371 if (!rt6_qualify_for_ecmp(rt)) {
4372 err = -EINVAL;
4373 NL_SET_ERR_MSG(extack,
4374 "Device only routes can not be added for IPv6 using the multipath API.");
4375 fib6_info_release(rt);
4376 goto cleanup;
4377 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004378
David Ahern5e670d82018-04-17 17:33:14 -07004379 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004380
David Ahernd4ead6b2018-04-17 17:33:16 -07004381 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4382 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004383 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004384 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004385 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004386 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004387
4388 rtnh = rtnh_next(rtnh, &remaining);
4389 }
4390
David Ahern3b1137f2017-02-02 12:37:10 -08004391 /* for add and replace send one notification with all nexthops.
4392 * Skip the notification in fib6_add_rt2node and send one with
4393 * the full route when done
4394 */
4395 info->skip_notify = 1;
4396
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004397 err_nh = NULL;
4398 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004399 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4400 fib6_info_release(nh->fib6_info);
David Ahern3b1137f2017-02-02 12:37:10 -08004401
David Ahernf7225172018-06-04 13:41:42 -07004402 if (!err) {
4403 /* save reference to last route successfully inserted */
4404 rt_last = nh->fib6_info;
4405
4406 /* save reference to first route for notification */
4407 if (!rt_notif)
4408 rt_notif = nh->fib6_info;
4409 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004410
David Ahern8d1c8022018-04-17 17:33:26 -07004411 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4412 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004413 if (err) {
4414 if (replace && nhn)
Jakub Kicinskia5a82d82019-01-14 10:52:45 -08004415 NL_SET_ERR_MSG_MOD(extack,
4416 "multipath route replace failed (check consistency of installed routes)");
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004417 err_nh = nh;
4418 goto add_errout;
4419 }
4420
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004421 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004422 * these flags after the first nexthop: if there is a collision,
4423 * we have already failed to add the first nexthop:
4424 * fib6_add_rt2node() has rejected it; when replacing, old
4425 * nexthops have been replaced by first new, the rest should
4426 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004427 */
Michal Kubeček27596472015-05-18 20:54:00 +02004428 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4429 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004430 nhn++;
4431 }
4432
David Ahern3b1137f2017-02-02 12:37:10 -08004433 /* success ... tell user about new route */
4434 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004435 goto cleanup;
4436
4437add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004438 /* send notification for routes that were added so that
4439 * the delete notifications sent by ip6_route_del are
4440 * coherent
4441 */
4442 if (rt_notif)
4443 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4444
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004445 /* Delete routes that were already added */
4446 list_for_each_entry(nh, &rt6_nh_list, next) {
4447 if (err_nh == nh)
4448 break;
David Ahern333c4302017-05-21 10:12:04 -06004449 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004450 }
4451
4452cleanup:
4453 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004454 if (nh->fib6_info)
4455 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004456 list_del(&nh->next);
4457 kfree(nh);
4458 }
4459
4460 return err;
4461}
4462
David Ahern333c4302017-05-21 10:12:04 -06004463static int ip6_route_multipath_del(struct fib6_config *cfg,
4464 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004465{
4466 struct fib6_config r_cfg;
4467 struct rtnexthop *rtnh;
4468 int remaining;
4469 int attrlen;
4470 int err = 1, last_err = 0;
4471
4472 remaining = cfg->fc_mp_len;
4473 rtnh = (struct rtnexthop *)cfg->fc_mp;
4474
4475 /* Parse a Multipath Entry */
4476 while (rtnh_ok(rtnh, remaining)) {
4477 memcpy(&r_cfg, cfg, sizeof(*cfg));
4478 if (rtnh->rtnh_ifindex)
4479 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4480
4481 attrlen = rtnh_attrlen(rtnh);
4482 if (attrlen > 0) {
4483 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4484
4485 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4486 if (nla) {
4487 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4488 r_cfg.fc_flags |= RTF_GATEWAY;
4489 }
4490 }
David Ahern333c4302017-05-21 10:12:04 -06004491 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004492 if (err)
4493 last_err = err;
4494
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004495 rtnh = rtnh_next(rtnh, &remaining);
4496 }
4497
4498 return last_err;
4499}
4500
David Ahernc21ef3e2017-04-16 09:48:24 -07004501static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4502 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503{
Thomas Graf86872cb2006-08-22 00:01:08 -07004504 struct fib6_config cfg;
4505 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506
David Ahern333c4302017-05-21 10:12:04 -06004507 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004508 if (err < 0)
4509 return err;
4510
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004511 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004512 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004513 else {
4514 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004515 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517}
4518
David Ahernc21ef3e2017-04-16 09:48:24 -07004519static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4520 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521{
Thomas Graf86872cb2006-08-22 00:01:08 -07004522 struct fib6_config cfg;
4523 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
David Ahern333c4302017-05-21 10:12:04 -06004525 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004526 if (err < 0)
4527 return err;
4528
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004529 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004530 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004531 else
David Ahernacb54e32018-04-17 17:33:22 -07004532 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533}
4534
David Ahern8d1c8022018-04-17 17:33:26 -07004535static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004536{
David Ahernbeb1afac52017-02-02 12:37:09 -08004537 int nexthop_len = 0;
4538
David Ahern93c2fb22018-04-18 15:38:59 -07004539 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004540 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4541 + NLA_ALIGN(sizeof(struct rtnexthop))
4542 + nla_total_size(16) /* RTA_GATEWAY */
David Ahern5e670d82018-04-17 17:33:14 -07004543 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
David Ahernbeb1afac52017-02-02 12:37:09 -08004544
David Ahern93c2fb22018-04-18 15:38:59 -07004545 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004546 }
4547
Thomas Graf339bf982006-11-10 14:10:15 -08004548 return NLMSG_ALIGN(sizeof(struct rtmsg))
4549 + nla_total_size(16) /* RTA_SRC */
4550 + nla_total_size(16) /* RTA_DST */
4551 + nla_total_size(16) /* RTA_GATEWAY */
4552 + nla_total_size(16) /* RTA_PREFSRC */
4553 + nla_total_size(4) /* RTA_TABLE */
4554 + nla_total_size(4) /* RTA_IIF */
4555 + nla_total_size(4) /* RTA_OIF */
4556 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004557 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004558 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004559 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004560 + nla_total_size(1) /* RTA_PREF */
David Ahern5e670d82018-04-17 17:33:14 -07004561 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate)
David Ahernbeb1afac52017-02-02 12:37:09 -08004562 + nexthop_len;
4563}
4564
David Ahern8d1c8022018-04-17 17:33:26 -07004565static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004566 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004567{
David Ahern5e670d82018-04-17 17:33:14 -07004568 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004569 *flags |= RTNH_F_DEAD;
4570
David Ahern5e670d82018-04-17 17:33:14 -07004571 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004572 *flags |= RTNH_F_LINKDOWN;
David Aherndcd1f572018-04-18 15:39:05 -07004573
4574 rcu_read_lock();
4575 if (fib6_ignore_linkdown(rt))
David Ahernbeb1afac52017-02-02 12:37:09 -08004576 *flags |= RTNH_F_DEAD;
David Aherndcd1f572018-04-18 15:39:05 -07004577 rcu_read_unlock();
David Ahernbeb1afac52017-02-02 12:37:09 -08004578 }
4579
David Ahern93c2fb22018-04-18 15:38:59 -07004580 if (rt->fib6_flags & RTF_GATEWAY) {
David Ahern5e670d82018-04-17 17:33:14 -07004581 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004582 goto nla_put_failure;
4583 }
4584
David Ahern5e670d82018-04-17 17:33:14 -07004585 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK);
4586 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004587 *flags |= RTNH_F_OFFLOAD;
4588
David Ahern5be083c2017-03-06 15:57:31 -08004589 /* not needed for multipath encoding b/c it has a rtnexthop struct */
David Ahern5e670d82018-04-17 17:33:14 -07004590 if (!skip_oif && rt->fib6_nh.nh_dev &&
4591 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex))
David Ahernbeb1afac52017-02-02 12:37:09 -08004592 goto nla_put_failure;
4593
David Ahern5e670d82018-04-17 17:33:14 -07004594 if (rt->fib6_nh.nh_lwtstate &&
4595 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004596 goto nla_put_failure;
4597
4598 return 0;
4599
4600nla_put_failure:
4601 return -EMSGSIZE;
4602}
4603
David Ahern5be083c2017-03-06 15:57:31 -08004604/* add multipath next hop */
David Ahern8d1c8022018-04-17 17:33:26 -07004605static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt)
David Ahernbeb1afac52017-02-02 12:37:09 -08004606{
David Ahern5e670d82018-04-17 17:33:14 -07004607 const struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernbeb1afac52017-02-02 12:37:09 -08004608 struct rtnexthop *rtnh;
4609 unsigned int flags = 0;
4610
4611 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4612 if (!rtnh)
4613 goto nla_put_failure;
4614
David Ahern5e670d82018-04-17 17:33:14 -07004615 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1;
4616 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
David Ahernbeb1afac52017-02-02 12:37:09 -08004617
David Ahern5be083c2017-03-06 15:57:31 -08004618 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004619 goto nla_put_failure;
4620
4621 rtnh->rtnh_flags = flags;
4622
4623 /* length of rtnetlink header + attributes */
4624 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4625
4626 return 0;
4627
4628nla_put_failure:
4629 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004630}
4631
David Ahernd4ead6b2018-04-17 17:33:16 -07004632static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004633 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004634 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004635 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004636 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637{
Xin Long22d0bd82018-09-11 14:33:58 +08004638 struct rt6_info *rt6 = (struct rt6_info *)dst;
4639 struct rt6key *rt6_dst, *rt6_src;
4640 u32 *pmetrics, table, rt6_flags;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004641 struct nlmsghdr *nlh;
Xin Long22d0bd82018-09-11 14:33:58 +08004642 struct rtmsg *rtm;
David Ahernd4ead6b2018-04-17 17:33:16 -07004643 long expires = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644
Eric W. Biederman15e47302012-09-07 20:12:54 +00004645 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004646 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004647 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004648
Xin Long22d0bd82018-09-11 14:33:58 +08004649 if (rt6) {
4650 rt6_dst = &rt6->rt6i_dst;
4651 rt6_src = &rt6->rt6i_src;
4652 rt6_flags = rt6->rt6i_flags;
4653 } else {
4654 rt6_dst = &rt->fib6_dst;
4655 rt6_src = &rt->fib6_src;
4656 rt6_flags = rt->fib6_flags;
4657 }
4658
Thomas Graf2d7202b2006-08-22 00:01:27 -07004659 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 rtm->rtm_family = AF_INET6;
Xin Long22d0bd82018-09-11 14:33:58 +08004661 rtm->rtm_dst_len = rt6_dst->plen;
4662 rtm->rtm_src_len = rt6_src->plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004664 if (rt->fib6_table)
4665 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004666 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004667 table = RT6_TABLE_UNSPEC;
Kalash Nainwal97f00822019-02-20 16:23:04 -08004668 rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT;
David S. Millerc78679e2012-04-01 20:27:33 -04004669 if (nla_put_u32(skb, RTA_TABLE, table))
4670 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004671
4672 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 rtm->rtm_flags = 0;
4674 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004675 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
Xin Long22d0bd82018-09-11 14:33:58 +08004677 if (rt6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 rtm->rtm_flags |= RTM_F_CLONED;
4679
David Ahernd4ead6b2018-04-17 17:33:16 -07004680 if (dest) {
4681 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004682 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004683 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 } else if (rtm->rtm_dst_len)
Xin Long22d0bd82018-09-11 14:33:58 +08004685 if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004686 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687#ifdef CONFIG_IPV6_SUBTREES
4688 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004689 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004690 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004691 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004692 } else if (rtm->rtm_src_len &&
Xin Long22d0bd82018-09-11 14:33:58 +08004693 nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004694 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004696 if (iif) {
4697#ifdef CONFIG_IPV6_MROUTE
Xin Long22d0bd82018-09-11 14:33:58 +08004698 if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004699 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004700
David Ahernfd61c6b2017-01-17 15:51:07 -08004701 if (err == 0)
4702 return 0;
4703 if (err < 0)
4704 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004705 } else
4706#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004707 if (nla_put_u32(skb, RTA_IIF, iif))
4708 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004709 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004711 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004712 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004713 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004715
David Ahern93c2fb22018-04-18 15:38:59 -07004716 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004717 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004718 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004719 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004720 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004721 }
4722
David Ahernd4ead6b2018-04-17 17:33:16 -07004723 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4724 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004725 goto nla_put_failure;
4726
David Ahern93c2fb22018-04-18 15:38:59 -07004727 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004728 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004729
David Ahernbeb1afac52017-02-02 12:37:09 -08004730 /* For multipath routes, walk the siblings list and add
4731 * each as a nexthop within RTA_MULTIPATH.
4732 */
Xin Long22d0bd82018-09-11 14:33:58 +08004733 if (rt6) {
4734 if (rt6_flags & RTF_GATEWAY &&
4735 nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
4736 goto nla_put_failure;
4737
4738 if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
4739 goto nla_put_failure;
4740 } else if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004741 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004742 struct nlattr *mp;
4743
4744 mp = nla_nest_start(skb, RTA_MULTIPATH);
4745 if (!mp)
4746 goto nla_put_failure;
4747
4748 if (rt6_add_nexthop(skb, rt) < 0)
4749 goto nla_put_failure;
4750
4751 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004752 &rt->fib6_siblings, fib6_siblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004753 if (rt6_add_nexthop(skb, sibling) < 0)
4754 goto nla_put_failure;
4755 }
4756
4757 nla_nest_end(skb, mp);
4758 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004759 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004760 goto nla_put_failure;
4761 }
4762
Xin Long22d0bd82018-09-11 14:33:58 +08004763 if (rt6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004764 expires = dst ? dst->expires : rt->expires;
4765 expires -= jiffies;
4766 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004767
David Ahernd4ead6b2018-04-17 17:33:16 -07004768 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004769 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Xin Long22d0bd82018-09-11 14:33:58 +08004771 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004772 goto nla_put_failure;
4773
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004774
Johannes Berg053c0952015-01-16 22:09:00 +01004775 nlmsg_end(skb, nlh);
4776 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004777
4778nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004779 nlmsg_cancel(skb, nlh);
4780 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781}
4782
David Ahern13e38902018-10-15 18:56:44 -07004783static bool fib6_info_uses_dev(const struct fib6_info *f6i,
4784 const struct net_device *dev)
4785{
4786 if (f6i->fib6_nh.nh_dev == dev)
4787 return true;
4788
4789 if (f6i->fib6_nsiblings) {
4790 struct fib6_info *sibling, *next_sibling;
4791
4792 list_for_each_entry_safe(sibling, next_sibling,
4793 &f6i->fib6_siblings, fib6_siblings) {
4794 if (sibling->fib6_nh.nh_dev == dev)
4795 return true;
4796 }
4797 }
4798
4799 return false;
4800}
4801
David Ahern8d1c8022018-04-17 17:33:26 -07004802int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803{
4804 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern13e38902018-10-15 18:56:44 -07004805 struct fib_dump_filter *filter = &arg->filter;
4806 unsigned int flags = NLM_F_MULTI;
David Ahern1f17e2f2017-01-26 13:54:08 -08004807 struct net *net = arg->net;
4808
David Ahern421842e2018-04-17 17:33:18 -07004809 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004810 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811
David Ahern13e38902018-10-15 18:56:44 -07004812 if ((filter->flags & RTM_F_PREFIX) &&
4813 !(rt->fib6_flags & RTF_PREFIX_RT)) {
4814 /* success since this is not a prefix route */
4815 return 1;
4816 }
4817 if (filter->filter_set) {
4818 if ((filter->rt_type && rt->fib6_type != filter->rt_type) ||
4819 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) ||
4820 (filter->protocol && rt->fib6_protocol != filter->protocol)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004821 return 1;
4822 }
David Ahern13e38902018-10-15 18:56:44 -07004823 flags |= NLM_F_DUMP_FILTERED;
David Ahernf8cfe2c2017-01-17 15:51:08 -08004824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825
David Ahernd4ead6b2018-04-17 17:33:16 -07004826 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4827 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
David Ahern13e38902018-10-15 18:56:44 -07004828 arg->cb->nlh->nlmsg_seq, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829}
4830
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004831static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
4832 const struct nlmsghdr *nlh,
4833 struct nlattr **tb,
4834 struct netlink_ext_ack *extack)
4835{
4836 struct rtmsg *rtm;
4837 int i, err;
4838
4839 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
4840 NL_SET_ERR_MSG_MOD(extack,
4841 "Invalid header for get route request");
4842 return -EINVAL;
4843 }
4844
4845 if (!netlink_strict_get_check(skb))
4846 return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
4847 rtm_ipv6_policy, extack);
4848
4849 rtm = nlmsg_data(nlh);
4850 if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
4851 (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
4852 rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
4853 rtm->rtm_type) {
4854 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
4855 return -EINVAL;
4856 }
4857 if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
4858 NL_SET_ERR_MSG_MOD(extack,
4859 "Invalid flags for get route request");
4860 return -EINVAL;
4861 }
4862
4863 err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
4864 rtm_ipv6_policy, extack);
4865 if (err)
4866 return err;
4867
4868 if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
4869 (tb[RTA_DST] && !rtm->rtm_dst_len)) {
4870 NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
4871 return -EINVAL;
4872 }
4873
4874 for (i = 0; i <= RTA_MAX; i++) {
4875 if (!tb[i])
4876 continue;
4877
4878 switch (i) {
4879 case RTA_SRC:
4880 case RTA_DST:
4881 case RTA_IIF:
4882 case RTA_OIF:
4883 case RTA_MARK:
4884 case RTA_UID:
4885 case RTA_SPORT:
4886 case RTA_DPORT:
4887 case RTA_IP_PROTO:
4888 break;
4889 default:
4890 NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
4891 return -EINVAL;
4892 }
4893 }
4894
4895 return 0;
4896}
4897
David Ahernc21ef3e2017-04-16 09:48:24 -07004898static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4899 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004901 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004902 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004903 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004904 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004905 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004907 struct sk_buff *skb;
4908 struct rtmsg *rtm;
Maciej Żenczykowski744486d2018-09-29 23:44:54 -07004909 struct flowi6 fl6 = {};
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004910 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004911
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004912 err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004913 if (err < 0)
4914 goto errout;
4915
4916 err = -EINVAL;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004917 rtm = nlmsg_data(nlh);
4918 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004919 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004920
4921 if (tb[RTA_SRC]) {
4922 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4923 goto errout;
4924
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004925 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004926 }
4927
4928 if (tb[RTA_DST]) {
4929 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4930 goto errout;
4931
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004932 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004933 }
4934
4935 if (tb[RTA_IIF])
4936 iif = nla_get_u32(tb[RTA_IIF]);
4937
4938 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004939 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004940
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004941 if (tb[RTA_MARK])
4942 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4943
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004944 if (tb[RTA_UID])
4945 fl6.flowi6_uid = make_kuid(current_user_ns(),
4946 nla_get_u32(tb[RTA_UID]));
4947 else
4948 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4949
Roopa Prabhueacb9382018-05-22 14:03:28 -07004950 if (tb[RTA_SPORT])
4951 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
4952
4953 if (tb[RTA_DPORT])
4954 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
4955
4956 if (tb[RTA_IP_PROTO]) {
4957 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
Hangbin Liu5e1a99e2019-02-27 16:15:29 +08004958 &fl6.flowi6_proto, AF_INET6,
4959 extack);
Roopa Prabhueacb9382018-05-22 14:03:28 -07004960 if (err)
4961 goto errout;
4962 }
4963
Thomas Grafab364a62006-08-22 00:01:47 -07004964 if (iif) {
4965 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004966 int flags = 0;
4967
Florian Westphal121622d2017-08-15 16:34:42 +02004968 rcu_read_lock();
4969
4970 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004971 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004972 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004973 err = -ENODEV;
4974 goto errout;
4975 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004976
4977 fl6.flowi6_iif = iif;
4978
4979 if (!ipv6_addr_any(&fl6.saddr))
4980 flags |= RT6_LOOKUP_F_HAS_SADDR;
4981
David Ahernb75cc8f2018-03-02 08:32:17 -08004982 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004983
4984 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004985 } else {
4986 fl6.flowi6_oif = oif;
4987
Ido Schimmel58acfd72017-12-20 12:28:25 +02004988 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004989 }
4990
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004991
4992 rt = container_of(dst, struct rt6_info, dst);
4993 if (rt->dst.error) {
4994 err = rt->dst.error;
4995 ip6_rt_put(rt);
4996 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998
WANG Cong9d6acb32017-03-01 20:48:39 -08004999 if (rt == net->ipv6.ip6_null_entry) {
5000 err = rt->dst.error;
5001 ip6_rt_put(rt);
5002 goto errout;
5003 }
5004
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05005006 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00005007 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07005008 err = -ENOBUFS;
5009 goto errout;
5010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
Changli Gaod8d1f302010-06-10 23:31:35 -07005012 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07005013
5014 rcu_read_lock();
5015 from = rcu_dereference(rt->from);
5016
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005017 if (fibmatch)
David Aherna68886a2018-04-20 15:38:02 -07005018 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005019 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
5020 nlh->nlmsg_seq, 0);
5021 else
David Aherna68886a2018-04-20 15:38:02 -07005022 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5023 &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07005024 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
5025 0);
David Aherna68886a2018-04-20 15:38:02 -07005026 rcu_read_unlock();
5027
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07005029 kfree_skb(skb);
5030 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 }
5032
Eric W. Biederman15e47302012-09-07 20:12:54 +00005033 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07005034errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036}
5037
David Ahern8d1c8022018-04-17 17:33:26 -07005038void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07005039 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040{
5041 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08005042 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005043 u32 seq;
5044 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005046 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05005047 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07005048
Roopa Prabhu19e42e42015-07-21 10:43:48 +02005049 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05005050 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07005051 goto errout;
5052
David Ahernd4ead6b2018-04-17 17:33:16 -07005053 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
5054 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08005055 if (err < 0) {
5056 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
5057 WARN_ON(err == -EMSGSIZE);
5058 kfree_skb(skb);
5059 goto errout;
5060 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00005061 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08005062 info->nlh, gfp_any());
5063 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07005064errout:
5065 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08005066 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067}
5068
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005069static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00005070 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005071{
Jiri Pirko351638e2013-05-28 01:30:21 +00005072 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09005073 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005074
WANG Cong242d3a42017-05-08 10:12:13 -07005075 if (!(dev->flags & IFF_LOOPBACK))
5076 return NOTIFY_OK;
5077
5078 if (event == NETDEV_REGISTER) {
David Ahern421842e2018-04-17 17:33:18 -07005079 net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07005080 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005081 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
5082#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07005083 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005084 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07005085 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005086 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
5087#endif
WANG Cong76da0702017-06-20 11:42:27 -07005088 } else if (event == NETDEV_UNREGISTER &&
5089 dev->reg_state != NETREG_UNREGISTERED) {
5090 /* NETDEV_UNREGISTER could be fired for multiple times by
5091 * netdev_wait_allrefs(). Make sure we only call this once.
5092 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07005093 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005094#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005095 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5096 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005097#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005098 }
5099
5100 return NOTIFY_OK;
5101}
5102
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103/*
5104 * /proc
5105 */
5106
5107#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5109{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005110 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005112 net->ipv6.rt6_stats->fib_nodes,
5113 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005114 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005115 net->ipv6.rt6_stats->fib_rt_entries,
5116 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005117 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005118 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
5120 return 0;
5121}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122#endif /* CONFIG_PROC_FS */
5123
5124#ifdef CONFIG_SYSCTL
5125
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005127int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 void __user *buffer, size_t *lenp, loff_t *ppos)
5129{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005130 struct net *net;
5131 int delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005132 int ret;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005133 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005135
5136 net = (struct net *)ctl->extra1;
5137 delay = net->ipv6.sysctl.flush_delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005138 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
5139 if (ret)
5140 return ret;
5141
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005142 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005143 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144}
5145
David Ahern7c6bb7d2018-10-11 20:17:21 -07005146static int zero;
5147static int one = 1;
5148
David Aherned792e22018-10-08 14:06:34 -07005149static struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005150 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005152 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005154 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005155 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 },
5157 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005159 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 .maxlen = sizeof(int),
5161 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005162 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 },
5164 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005166 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 .maxlen = sizeof(int),
5168 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005169 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 },
5171 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005173 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 .maxlen = sizeof(int),
5175 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005176 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 },
5178 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005180 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 .maxlen = sizeof(int),
5182 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005183 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 },
5185 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005187 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 .maxlen = sizeof(int),
5189 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005190 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 },
5192 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005194 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 .maxlen = sizeof(int),
5196 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005197 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 },
5199 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005201 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 .maxlen = sizeof(int),
5203 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005204 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 },
5206 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005208 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 .maxlen = sizeof(int),
5210 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005211 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 },
5213 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005215 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 .maxlen = sizeof(int),
5217 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005218 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 },
David Ahern7c6bb7d2018-10-11 20:17:21 -07005220 {
5221 .procname = "skip_notify_on_dev_down",
5222 .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
5223 .maxlen = sizeof(int),
5224 .mode = 0644,
5225 .proc_handler = proc_dointvec,
5226 .extra1 = &zero,
5227 .extra2 = &one,
5228 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005229 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230};
5231
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005232struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005233{
5234 struct ctl_table *table;
5235
5236 table = kmemdup(ipv6_route_table_template,
5237 sizeof(ipv6_route_table_template),
5238 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005239
5240 if (table) {
5241 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005242 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005243 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005244 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5245 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5246 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5247 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5248 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5249 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5250 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005251 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005252 table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005253
5254 /* Don't export sysctls to unprivileged users */
5255 if (net->user_ns != &init_user_ns)
5256 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005257 }
5258
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005259 return table;
5260}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261#endif
5262
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005263static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005264{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005265 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005266
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005267 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5268 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005269
Eric Dumazetfc66f952010-10-08 06:37:34 +00005270 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5271 goto out_ip6_dst_ops;
5272
David Ahern421842e2018-04-17 17:33:18 -07005273 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5274 sizeof(*net->ipv6.fib6_null_entry),
5275 GFP_KERNEL);
5276 if (!net->ipv6.fib6_null_entry)
5277 goto out_ip6_dst_entries;
5278
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005279 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5280 sizeof(*net->ipv6.ip6_null_entry),
5281 GFP_KERNEL);
5282 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005283 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005284 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005285 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5286 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005287
5288#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005289 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005290 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5291 sizeof(*net->ipv6.ip6_prohibit_entry),
5292 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005293 if (!net->ipv6.ip6_prohibit_entry)
5294 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005295 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005296 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5297 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005298
5299 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5300 sizeof(*net->ipv6.ip6_blk_hole_entry),
5301 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005302 if (!net->ipv6.ip6_blk_hole_entry)
5303 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005304 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005305 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5306 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005307#endif
5308
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005309 net->ipv6.sysctl.flush_delay = 0;
5310 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5311 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5312 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5313 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5314 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5315 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5316 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005317 net->ipv6.sysctl.skip_notify_on_dev_down = 0;
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005318
Benjamin Thery6891a342008-03-04 13:49:47 -08005319 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5320
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005321 ret = 0;
5322out:
5323 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005324
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005325#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5326out_ip6_prohibit_entry:
5327 kfree(net->ipv6.ip6_prohibit_entry);
5328out_ip6_null_entry:
5329 kfree(net->ipv6.ip6_null_entry);
5330#endif
David Ahern421842e2018-04-17 17:33:18 -07005331out_fib6_null_entry:
5332 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005333out_ip6_dst_entries:
5334 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005335out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005336 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005337}
5338
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005339static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005340{
David Ahern421842e2018-04-17 17:33:18 -07005341 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005342 kfree(net->ipv6.ip6_null_entry);
5343#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5344 kfree(net->ipv6.ip6_prohibit_entry);
5345 kfree(net->ipv6.ip6_blk_hole_entry);
5346#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005347 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005348}
5349
Thomas Grafd1896342012-06-18 12:08:33 +00005350static int __net_init ip6_route_net_init_late(struct net *net)
5351{
5352#ifdef CONFIG_PROC_FS
Christoph Hellwigc3506372018-04-10 19:42:55 +02005353 proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
5354 sizeof(struct ipv6_route_iter));
Christoph Hellwig3617d942018-04-13 20:38:35 +02005355 proc_create_net_single("rt6_stats", 0444, net->proc_net,
5356 rt6_stats_seq_show, NULL);
Thomas Grafd1896342012-06-18 12:08:33 +00005357#endif
5358 return 0;
5359}
5360
5361static void __net_exit ip6_route_net_exit_late(struct net *net)
5362{
5363#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005364 remove_proc_entry("ipv6_route", net->proc_net);
5365 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005366#endif
5367}
5368
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005369static struct pernet_operations ip6_route_net_ops = {
5370 .init = ip6_route_net_init,
5371 .exit = ip6_route_net_exit,
5372};
5373
David S. Millerc3426b42012-06-09 16:27:05 -07005374static int __net_init ipv6_inetpeer_init(struct net *net)
5375{
5376 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5377
5378 if (!bp)
5379 return -ENOMEM;
5380 inet_peer_base_init(bp);
5381 net->ipv6.peers = bp;
5382 return 0;
5383}
5384
5385static void __net_exit ipv6_inetpeer_exit(struct net *net)
5386{
5387 struct inet_peer_base *bp = net->ipv6.peers;
5388
5389 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005390 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005391 kfree(bp);
5392}
5393
David S. Miller2b823f72012-06-09 19:00:16 -07005394static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005395 .init = ipv6_inetpeer_init,
5396 .exit = ipv6_inetpeer_exit,
5397};
5398
Thomas Grafd1896342012-06-18 12:08:33 +00005399static struct pernet_operations ip6_route_net_late_ops = {
5400 .init = ip6_route_net_init_late,
5401 .exit = ip6_route_net_exit_late,
5402};
5403
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005404static struct notifier_block ip6_route_dev_notifier = {
5405 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005406 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005407};
5408
WANG Cong2f460932017-05-03 22:07:31 -07005409void __init ip6_route_init_special_entries(void)
5410{
5411 /* Registering of the loopback is done before this portion of code,
5412 * the loopback reference in rt6_info will not be taken, do it
5413 * manually for init_net */
David Ahern421842e2018-04-17 17:33:18 -07005414 init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005415 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5416 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5417 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5418 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5419 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5420 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5421 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5422 #endif
5423}
5424
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005425int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005427 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005428 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005429
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005430 ret = -ENOMEM;
5431 ip6_dst_ops_template.kmem_cachep =
5432 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5433 SLAB_HWCACHE_ALIGN, NULL);
5434 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005435 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005436
Eric Dumazetfc66f952010-10-08 06:37:34 +00005437 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005438 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005439 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005440
David S. Millerc3426b42012-06-09 16:27:05 -07005441 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5442 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005443 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005444
David S. Miller7e52b332012-06-15 15:51:55 -07005445 ret = register_pernet_subsys(&ip6_route_net_ops);
5446 if (ret)
5447 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005448
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005449 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5450
David S. Millere8803b62012-06-16 01:12:19 -07005451 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005452 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005453 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005454
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005455 ret = xfrm6_init();
5456 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005457 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005458
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005459 ret = fib6_rules_init();
5460 if (ret)
5461 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005462
Thomas Grafd1896342012-06-18 12:08:33 +00005463 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5464 if (ret)
5465 goto fib6_rules_init;
5466
Florian Westphal16feebc2017-12-02 21:44:08 +01005467 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5468 inet6_rtm_newroute, NULL, 0);
5469 if (ret < 0)
5470 goto out_register_late_subsys;
5471
5472 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5473 inet6_rtm_delroute, NULL, 0);
5474 if (ret < 0)
5475 goto out_register_late_subsys;
5476
5477 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5478 inet6_rtm_getroute, NULL,
5479 RTNL_FLAG_DOIT_UNLOCKED);
5480 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005481 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005482
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005483 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005484 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005485 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005486
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005487 for_each_possible_cpu(cpu) {
5488 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5489
5490 INIT_LIST_HEAD(&ul->head);
5491 spin_lock_init(&ul->lock);
5492 }
5493
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005494out:
5495 return ret;
5496
Thomas Grafd1896342012-06-18 12:08:33 +00005497out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005498 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005499 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005500fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005501 fib6_rules_cleanup();
5502xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005503 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005504out_fib6_init:
5505 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005506out_register_subsys:
5507 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005508out_register_inetpeer:
5509 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005510out_dst_entries:
5511 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005512out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005513 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005514 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515}
5516
5517void ip6_route_cleanup(void)
5518{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005519 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005520 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005521 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005524 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005525 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005526 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005527 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528}