blob: 8cf4f062322964c7eecb6040471a1fb12e1d7c29 [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>
David Ahernb8115802015-11-19 12:24:22 -080066#include <trace/events/fib6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080068#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70#ifdef CONFIG_SYSCTL
71#include <linux/sysctl.h>
72#endif
73
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020074enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010075 RT6_NUD_FAIL_HARD = -3,
76 RT6_NUD_FAIL_PROBE = -2,
77 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020078 RT6_NUD_SUCCEED = 1
79};
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080082static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000083static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static struct dst_entry *ip6_negative_advice(struct dst_entry *);
85static void ip6_dst_destroy(struct dst_entry *);
86static void ip6_dst_ifdown(struct dst_entry *,
87 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080088static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050091static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053092static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050093static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070095static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
96 struct sk_buff *skb, u32 mtu);
97static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
98 struct sk_buff *skb);
David Ahern8d1c8022018-04-17 17:33:26 -070099static int rt6_score_route(struct fib6_info *rt, int oif, int strict);
100static size_t rt6_nlmsg_size(struct fib6_info *rt);
David Ahernd4ead6b2018-04-17 17:33:16 -0700101static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -0700102 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -0700103 struct in6_addr *dest, struct in6_addr *src,
David Ahern16a16cd2017-02-02 12:37:11 -0800104 int iif, int type, u32 portid, u32 seq,
105 unsigned int flags);
David Ahern8d1c8022018-04-17 17:33:26 -0700106static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -0700107 struct in6_addr *daddr,
108 struct in6_addr *saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800110#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -0700111static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000112 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700113 const struct in6_addr *gwaddr,
114 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000115 unsigned int pref);
David Ahern8d1c8022018-04-17 17:33:26 -0700116static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000117 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700118 const struct in6_addr *gwaddr,
119 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800120#endif
121
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700122struct uncached_list {
123 spinlock_t lock;
124 struct list_head head;
125};
126
127static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
128
Xin Long510c3212018-02-14 19:06:02 +0800129void rt6_uncached_list_add(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700130{
131 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
132
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700133 rt->rt6i_uncached_list = ul;
134
135 spin_lock_bh(&ul->lock);
136 list_add_tail(&rt->rt6i_uncached, &ul->head);
137 spin_unlock_bh(&ul->lock);
138}
139
Xin Long510c3212018-02-14 19:06:02 +0800140void rt6_uncached_list_del(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700141{
142 if (!list_empty(&rt->rt6i_uncached)) {
143 struct uncached_list *ul = rt->rt6i_uncached_list;
Wei Wang81eb8442017-10-06 12:06:11 -0700144 struct net *net = dev_net(rt->dst.dev);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700145
146 spin_lock_bh(&ul->lock);
147 list_del(&rt->rt6i_uncached);
Wei Wang81eb8442017-10-06 12:06:11 -0700148 atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700149 spin_unlock_bh(&ul->lock);
150 }
151}
152
153static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
154{
155 struct net_device *loopback_dev = net->loopback_dev;
156 int cpu;
157
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500158 if (dev == loopback_dev)
159 return;
160
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700161 for_each_possible_cpu(cpu) {
162 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
163 struct rt6_info *rt;
164
165 spin_lock_bh(&ul->lock);
166 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
167 struct inet6_dev *rt_idev = rt->rt6i_idev;
168 struct net_device *rt_dev = rt->dst.dev;
169
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500170 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700171 rt->rt6i_idev = in6_dev_get(loopback_dev);
172 in6_dev_put(rt_idev);
173 }
174
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500175 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700176 rt->dst.dev = loopback_dev;
177 dev_hold(rt->dst.dev);
178 dev_put(rt_dev);
179 }
180 }
181 spin_unlock_bh(&ul->lock);
182 }
183}
184
David Ahernf8a1b432018-04-17 17:33:21 -0700185static inline const void *choose_neigh_daddr(const struct in6_addr *p,
David S. Millerf894cbf2012-07-02 21:52:24 -0700186 struct sk_buff *skb,
187 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500188{
David S. Millera7563f32012-01-26 16:29:16 -0500189 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500190 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700191 else if (skb)
192 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500193 return daddr;
194}
195
David Ahernf8a1b432018-04-17 17:33:21 -0700196struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
197 struct net_device *dev,
198 struct sk_buff *skb,
199 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700200{
David S. Miller39232972012-01-26 15:22:32 -0500201 struct neighbour *n;
202
David Ahernf8a1b432018-04-17 17:33:21 -0700203 daddr = choose_neigh_daddr(gw, skb, daddr);
204 n = __ipv6_neigh_lookup(dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500205 if (n)
206 return n;
David Ahernf8a1b432018-04-17 17:33:21 -0700207 return neigh_create(&nd_tbl, daddr, dev);
208}
209
210static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
211 struct sk_buff *skb,
212 const void *daddr)
213{
214 const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
215
216 return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500217}
218
Julian Anastasov63fca652017-02-06 23:14:15 +0200219static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
220{
221 struct net_device *dev = dst->dev;
222 struct rt6_info *rt = (struct rt6_info *)dst;
223
David Ahernf8a1b432018-04-17 17:33:21 -0700224 daddr = choose_neigh_daddr(&rt->rt6i_gateway, NULL, daddr);
Julian Anastasov63fca652017-02-06 23:14:15 +0200225 if (!daddr)
226 return;
227 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
228 return;
229 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
230 return;
231 __ipv6_confirm_neigh(dev, daddr);
232}
233
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800234static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 .gc = ip6_dst_gc,
237 .gc_thresh = 1024,
238 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800239 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000240 .mtu = ip6_mtu,
David Ahernd4ead6b2018-04-17 17:33:16 -0700241 .cow_metrics = dst_cow_metrics_generic,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .destroy = ip6_dst_destroy,
243 .ifdown = ip6_dst_ifdown,
244 .negative_advice = ip6_negative_advice,
245 .link_failure = ip6_link_failure,
246 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700247 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500248 .local_out = __ip6_local_out,
David Ahernf8a1b432018-04-17 17:33:21 -0700249 .neigh_lookup = ip6_dst_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200250 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251};
252
Steffen Klassertebb762f2011-11-23 02:12:51 +0000253static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800254{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000255 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
256
257 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800258}
259
David S. Miller6700c272012-07-17 03:29:28 -0700260static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
261 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700262{
263}
264
David S. Miller6700c272012-07-17 03:29:28 -0700265static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
266 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700267{
268}
269
David S. Miller14e50e52007-05-24 18:17:54 -0700270static struct dst_ops ip6_dst_blackhole_ops = {
271 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700272 .destroy = ip6_dst_destroy,
273 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000274 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800275 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700276 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700277 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700278 .cow_metrics = dst_cow_metrics_generic,
David Ahernf8a1b432018-04-17 17:33:21 -0700279 .neigh_lookup = ip6_dst_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700280};
281
David S. Miller62fa8a82011-01-26 20:51:05 -0800282static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800283 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800284};
285
David Ahern8d1c8022018-04-17 17:33:26 -0700286static const struct fib6_info fib6_null_entry_template = {
David Ahern93c2fb22018-04-18 15:38:59 -0700287 .fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
288 .fib6_protocol = RTPROT_KERNEL,
289 .fib6_metric = ~(u32)0,
290 .fib6_ref = ATOMIC_INIT(1),
David Ahern421842e2018-04-17 17:33:18 -0700291 .fib6_type = RTN_UNREACHABLE,
292 .fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
293};
294
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000295static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700296 .dst = {
297 .__refcnt = ATOMIC_INIT(1),
298 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000299 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700300 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700301 .input = ip6_pkt_discard,
302 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 },
304 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305};
306
Thomas Graf101367c2006-08-04 03:39:02 -0700307#ifdef CONFIG_IPV6_MULTIPLE_TABLES
308
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000309static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700310 .dst = {
311 .__refcnt = ATOMIC_INIT(1),
312 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000313 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700314 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700315 .input = ip6_pkt_prohibit,
316 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700317 },
318 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700319};
320
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000321static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700322 .dst = {
323 .__refcnt = ATOMIC_INIT(1),
324 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000325 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700326 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700327 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500328 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700329 },
330 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700331};
332
333#endif
334
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700335static void rt6_info_init(struct rt6_info *rt)
336{
337 struct dst_entry *dst = &rt->dst;
338
339 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700340 INIT_LIST_HEAD(&rt->rt6i_uncached);
341}
342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343/* allocate dst with ip6_dst_ops */
David Ahern93531c62018-04-17 17:33:25 -0700344struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
345 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
David S. Miller97bab732012-06-09 22:36:36 -0700347 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700348 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700349
Wei Wang81eb8442017-10-06 12:06:11 -0700350 if (rt) {
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700351 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -0700352 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
353 }
Steffen Klassert81048912012-07-05 23:37:09 +0000354
David S. Millercf911662011-04-28 14:31:47 -0700355 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
David Ahern9ab179d2016-04-07 11:10:06 -0700357EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359static void ip6_dst_destroy(struct dst_entry *dst)
360{
361 struct rt6_info *rt = (struct rt6_info *)dst;
David Ahern8d1c8022018-04-17 17:33:26 -0700362 struct fib6_info *from = rt->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700363 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700365 dst_destroy_metrics_generic(dst);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700366 rt6_uncached_list_del(rt);
367
368 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500369 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 rt->rt6i_idev = NULL;
371 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900372 }
David Ahernd4ead6b2018-04-17 17:33:16 -0700373
David Miller3a2232e2017-11-28 15:40:40 -0500374 rt->from = NULL;
David Ahern93531c62018-04-17 17:33:25 -0700375 fib6_info_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800376}
377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
379 int how)
380{
381 struct rt6_info *rt = (struct rt6_info *)dst;
382 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800383 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900384 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Wei Wange5645f52017-08-14 10:44:59 -0700386 if (idev && idev->dev != loopback_dev) {
387 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
388 if (loopback_idev) {
389 rt->rt6i_idev = loopback_idev;
390 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393}
394
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800395static bool __rt6_check_expired(const struct rt6_info *rt)
396{
397 if (rt->rt6i_flags & RTF_EXPIRES)
398 return time_after(jiffies, rt->dst.expires);
399 else
400 return false;
401}
402
Eric Dumazeta50feda2012-05-18 18:57:34 +0000403static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Gao feng1716a962012-04-06 00:13:10 +0000405 if (rt->rt6i_flags & RTF_EXPIRES) {
406 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000407 return true;
David Miller3a2232e2017-11-28 15:40:40 -0500408 } else if (rt->from) {
Xin Long1e2ea8a2017-08-26 20:10:10 +0800409 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
David Ahern14895682018-04-17 17:33:17 -0700410 fib6_check_expired(rt->from);
Gao feng1716a962012-04-06 00:13:10 +0000411 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000412 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
David Ahern8d1c8022018-04-17 17:33:26 -0700415static struct fib6_info *rt6_multipath_select(const struct net *net,
416 struct fib6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200417 struct flowi6 *fl6, int oif,
David Ahernb75cc8f2018-03-02 08:32:17 -0800418 const struct sk_buff *skb,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200419 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000420{
David Ahern8d1c8022018-04-17 17:33:26 -0700421 struct fib6_info *sibling, *next_sibling;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000422
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200423 /* We might have already computed the hash for ICMPv6 errors. In such
424 * case it will always be non-zero. Otherwise now is the time to do it.
425 */
426 if (!fl6->mp_hash)
David Ahernb4bac172018-03-02 08:32:18 -0800427 fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL);
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200428
David Ahern5e670d82018-04-17 17:33:14 -0700429 if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound))
Ido Schimmel3d709f62018-01-09 16:40:27 +0200430 return match;
Ido Schimmelbbfcd772017-11-21 09:50:12 +0200431
David Ahern93c2fb22018-04-18 15:38:59 -0700432 list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
433 fib6_siblings) {
David Ahern5e670d82018-04-17 17:33:14 -0700434 int nh_upper_bound;
435
436 nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound);
437 if (fl6->mp_hash > nh_upper_bound)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200438 continue;
439 if (rt6_score_route(sibling, oif, strict) < 0)
440 break;
441 match = sibling;
442 break;
443 }
444
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000445 return match;
446}
447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448/*
Wei Wang66f5d6c2017-10-06 12:06:10 -0700449 * Route lookup. rcu_read_lock() should be held.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 */
451
David Ahern8d1c8022018-04-17 17:33:26 -0700452static inline struct fib6_info *rt6_device_match(struct net *net,
453 struct fib6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000454 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700456 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
David Ahern8d1c8022018-04-17 17:33:26 -0700458 struct fib6_info *sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
David Ahern5e670d82018-04-17 17:33:14 -0700460 if (!oif && ipv6_addr_any(saddr) &&
461 !(rt->fib6_nh.nh_flags & RTNH_F_DEAD))
Ido Schimmel8067bb82018-01-07 12:45:09 +0200462 return rt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900463
David Miller071fb372017-11-28 15:40:15 -0500464 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) {
David Ahern5e670d82018-04-17 17:33:14 -0700465 const struct net_device *dev = sprt->fib6_nh.nh_dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900466
David Ahern5e670d82018-04-17 17:33:14 -0700467 if (sprt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200468 continue;
469
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900470 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (dev->ifindex == oif)
472 return sprt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900473 } else {
474 if (ipv6_chk_addr(net, saddr, dev,
475 flags & RT6_LOOKUP_F_IFACE))
476 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
David Aherneea68cd2018-04-18 15:39:02 -0700480 if (oif && flags & RT6_LOOKUP_F_IFACE)
481 return net->ipv6.fib6_null_entry;
Ido Schimmel8067bb82018-01-07 12:45:09 +0200482
David Ahern421842e2018-04-17 17:33:18 -0700483 return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800486#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200487struct __rt6_probe_work {
488 struct work_struct work;
489 struct in6_addr target;
490 struct net_device *dev;
491};
492
493static void rt6_probe_deferred(struct work_struct *w)
494{
495 struct in6_addr mcaddr;
496 struct __rt6_probe_work *work =
497 container_of(w, struct __rt6_probe_work, work);
498
499 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800500 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200501 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100502 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200503}
504
David Ahern8d1c8022018-04-17 17:33:26 -0700505static void rt6_probe(struct fib6_info *rt)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800506{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700507 struct __rt6_probe_work *work;
David Ahern5e670d82018-04-17 17:33:14 -0700508 const struct in6_addr *nh_gw;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000509 struct neighbour *neigh;
David Ahern5e670d82018-04-17 17:33:14 -0700510 struct net_device *dev;
511
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800512 /*
513 * Okay, this does not seem to be appropriate
514 * for now, however, we need to check if it
515 * is really so; aka Router Reachability Probing.
516 *
517 * Router Reachability Probe MUST be rate-limited
518 * to no more than one per minute.
519 */
David Ahern93c2fb22018-04-18 15:38:59 -0700520 if (!rt || !(rt->fib6_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000521 return;
David Ahern5e670d82018-04-17 17:33:14 -0700522
523 nh_gw = &rt->fib6_nh.nh_gw;
524 dev = rt->fib6_nh.nh_dev;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000525 rcu_read_lock_bh();
David Ahern5e670d82018-04-17 17:33:14 -0700526 neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000527 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700528 if (neigh->nud_state & NUD_VALID)
529 goto out;
530
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700531 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000532 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700533 if (!(neigh->nud_state & NUD_VALID) &&
534 time_after(jiffies,
535 neigh->updated +
David Ahern93c2fb22018-04-18 15:38:59 -0700536 rt->fib6_idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700537 work = kmalloc(sizeof(*work), GFP_ATOMIC);
538 if (work)
539 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200540 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000541 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700542 } else {
543 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000544 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700545
546 if (work) {
547 INIT_WORK(&work->work, rt6_probe_deferred);
David Ahern5e670d82018-04-17 17:33:14 -0700548 work->target = *nh_gw;
549 dev_hold(dev);
550 work->dev = dev;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700551 schedule_work(&work->work);
552 }
553
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700554out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000555 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800556}
557#else
David Ahern8d1c8022018-04-17 17:33:26 -0700558static inline void rt6_probe(struct fib6_info *rt)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800559{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800560}
561#endif
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800564 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 */
David Ahern8d1c8022018-04-17 17:33:26 -0700566static inline int rt6_check_dev(struct fib6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
David Ahern5e670d82018-04-17 17:33:14 -0700568 const struct net_device *dev = rt->fib6_nh.nh_dev;
569
David S. Miller161980f2007-04-06 11:42:27 -0700570 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800571 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700572 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
David Ahern8d1c8022018-04-17 17:33:26 -0700575static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200577 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
David Ahern5e670d82018-04-17 17:33:14 -0700578 struct neighbour *neigh;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000579
David Ahern93c2fb22018-04-18 15:38:59 -0700580 if (rt->fib6_flags & RTF_NONEXTHOP ||
581 !(rt->fib6_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200582 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000583
584 rcu_read_lock_bh();
David Ahern5e670d82018-04-17 17:33:14 -0700585 neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev,
586 &rt->fib6_nh.nh_gw);
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000587 if (neigh) {
588 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800589 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200590 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800591#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000592 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200593 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100594 else
595 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800596#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000597 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200598 } else {
599 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100600 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000601 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000602 rcu_read_unlock_bh();
603
Paul Marksa5a81f02012-12-03 10:26:54 +0000604 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800605}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
David Ahern8d1c8022018-04-17 17:33:26 -0700607static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800608{
Paul Marksa5a81f02012-12-03 10:26:54 +0000609 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900610
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700611 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700612 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200613 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800614#ifdef CONFIG_IPV6_ROUTER_PREF
David Ahern93c2fb22018-04-18 15:38:59 -0700615 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->fib6_flags)) << 2;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800616#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200617 if (strict & RT6_LOOKUP_F_REACHABLE) {
618 int n = rt6_check_neigh(rt);
619 if (n < 0)
620 return n;
621 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800622 return m;
623}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
David Ahern8d1c8022018-04-17 17:33:26 -0700625static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict,
626 int *mpri, struct fib6_info *match,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200627 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800628{
David S. Millerf11e6652007-03-24 20:36:25 -0700629 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200630 bool match_do_rr = false;
David Ahern93c2fb22018-04-18 15:38:59 -0700631 struct inet6_dev *idev = rt->fib6_idev;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400632
David Ahern5e670d82018-04-17 17:33:14 -0700633 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200634 goto out;
635
Ido Schimmel14c52062018-01-07 12:45:07 +0200636 if (idev->cnf.ignore_routes_with_linkdown &&
David Ahern5e670d82018-04-17 17:33:14 -0700637 rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Ahernd5d32e42016-10-24 12:27:23 -0700638 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400639 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700640
David Ahern14895682018-04-17 17:33:17 -0700641 if (fib6_check_expired(rt))
David S. Millerf11e6652007-03-24 20:36:25 -0700642 goto out;
643
644 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100645 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200646 match_do_rr = true;
647 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100648 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700649 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700650 }
651
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200652 if (strict & RT6_LOOKUP_F_REACHABLE)
653 rt6_probe(rt);
654
Jiri Benc7e980562013-12-11 13:48:20 +0100655 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200656 if (m > *mpri) {
657 *do_rr = match_do_rr;
658 *mpri = m;
659 match = rt;
660 }
David S. Millerf11e6652007-03-24 20:36:25 -0700661out:
662 return match;
663}
664
David Ahern8d1c8022018-04-17 17:33:26 -0700665static struct fib6_info *find_rr_leaf(struct fib6_node *fn,
666 struct fib6_info *leaf,
667 struct fib6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200668 u32 metric, int oif, int strict,
669 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700670{
David Ahern8d1c8022018-04-17 17:33:26 -0700671 struct fib6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800672 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
David S. Millerf11e6652007-03-24 20:36:25 -0700674 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700675 cont = NULL;
David Miller071fb372017-11-28 15:40:15 -0500676 for (rt = rr_head; rt; rt = rcu_dereference(rt->rt6_next)) {
David Ahern93c2fb22018-04-18 15:38:59 -0700677 if (rt->fib6_metric != metric) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700678 cont = rt;
679 break;
680 }
681
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200682 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700683 }
684
Wei Wang66f5d6c2017-10-06 12:06:10 -0700685 for (rt = leaf; rt && rt != rr_head;
David Miller071fb372017-11-28 15:40:15 -0500686 rt = rcu_dereference(rt->rt6_next)) {
David Ahern93c2fb22018-04-18 15:38:59 -0700687 if (rt->fib6_metric != metric) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700688 cont = rt;
689 break;
690 }
691
692 match = find_match(rt, oif, strict, &mpri, match, do_rr);
693 }
694
695 if (match || !cont)
696 return match;
697
David Miller071fb372017-11-28 15:40:15 -0500698 for (rt = cont; rt; rt = rcu_dereference(rt->rt6_next))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200699 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800700
David S. Millerf11e6652007-03-24 20:36:25 -0700701 return match;
702}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800703
David Ahern8d1c8022018-04-17 17:33:26 -0700704static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
Wei Wang8d1040e2017-10-06 12:06:08 -0700705 int oif, int strict)
David S. Millerf11e6652007-03-24 20:36:25 -0700706{
David Ahern8d1c8022018-04-17 17:33:26 -0700707 struct fib6_info *leaf = rcu_dereference(fn->leaf);
708 struct fib6_info *match, *rt0;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200709 bool do_rr = false;
Wei Wang17ecf592017-10-06 12:06:09 -0700710 int key_plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
David Ahern421842e2018-04-17 17:33:18 -0700712 if (!leaf || leaf == net->ipv6.fib6_null_entry)
713 return net->ipv6.fib6_null_entry;
Wei Wang8d1040e2017-10-06 12:06:08 -0700714
Wei Wang66f5d6c2017-10-06 12:06:10 -0700715 rt0 = rcu_dereference(fn->rr_ptr);
David S. Millerf11e6652007-03-24 20:36:25 -0700716 if (!rt0)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700717 rt0 = leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Wei Wang17ecf592017-10-06 12:06:09 -0700719 /* Double check to make sure fn is not an intermediate node
720 * and fn->leaf does not points to its child's leaf
721 * (This might happen if all routes under fn are deleted from
722 * the tree and fib6_repair_tree() is called on the node.)
723 */
David Ahern93c2fb22018-04-18 15:38:59 -0700724 key_plen = rt0->fib6_dst.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700725#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700726 if (rt0->fib6_src.plen)
727 key_plen = rt0->fib6_src.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700728#endif
729 if (fn->fn_bit != key_plen)
David Ahern421842e2018-04-17 17:33:18 -0700730 return net->ipv6.fib6_null_entry;
Wei Wang17ecf592017-10-06 12:06:09 -0700731
David Ahern93c2fb22018-04-18 15:38:59 -0700732 match = find_rr_leaf(fn, leaf, rt0, rt0->fib6_metric, oif, strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200733 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200735 if (do_rr) {
David Ahern8d1c8022018-04-17 17:33:26 -0700736 struct fib6_info *next = rcu_dereference(rt0->rt6_next);
David S. Millerf11e6652007-03-24 20:36:25 -0700737
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800738 /* no entries matched; do round-robin */
David Ahern93c2fb22018-04-18 15:38:59 -0700739 if (!next || next->fib6_metric != rt0->fib6_metric)
Wei Wang8d1040e2017-10-06 12:06:08 -0700740 next = leaf;
David S. Millerf11e6652007-03-24 20:36:25 -0700741
Wei Wang66f5d6c2017-10-06 12:06:10 -0700742 if (next != rt0) {
David Ahern93c2fb22018-04-18 15:38:59 -0700743 spin_lock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700744 /* make sure next is not being deleted from the tree */
David Ahern93c2fb22018-04-18 15:38:59 -0700745 if (next->fib6_node)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700746 rcu_assign_pointer(fn->rr_ptr, next);
David Ahern93c2fb22018-04-18 15:38:59 -0700747 spin_unlock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
750
David Ahern421842e2018-04-17 17:33:18 -0700751 return match ? match : net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
David Ahern8d1c8022018-04-17 17:33:26 -0700754static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt)
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700755{
David Ahern93c2fb22018-04-18 15:38:59 -0700756 return (rt->fib6_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700757}
758
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800759#ifdef CONFIG_IPV6_ROUTE_INFO
760int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000761 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800762{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900763 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800764 struct route_info *rinfo = (struct route_info *) opt;
765 struct in6_addr prefix_buf, *prefix;
766 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900767 unsigned long lifetime;
David Ahern8d1c8022018-04-17 17:33:26 -0700768 struct fib6_info *rt;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800769
770 if (len < sizeof(struct route_info)) {
771 return -EINVAL;
772 }
773
774 /* Sanity check for prefix_len and length */
775 if (rinfo->length > 3) {
776 return -EINVAL;
777 } else if (rinfo->prefix_len > 128) {
778 return -EINVAL;
779 } else if (rinfo->prefix_len > 64) {
780 if (rinfo->length < 2) {
781 return -EINVAL;
782 }
783 } else if (rinfo->prefix_len > 0) {
784 if (rinfo->length < 1) {
785 return -EINVAL;
786 }
787 }
788
789 pref = rinfo->route_pref;
790 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000791 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800792
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900793 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800794
795 if (rinfo->length == 3)
796 prefix = (struct in6_addr *)rinfo->prefix;
797 else {
798 /* this function is safe */
799 ipv6_addr_prefix(&prefix_buf,
800 (struct in6_addr *)rinfo->prefix,
801 rinfo->prefix_len);
802 prefix = &prefix_buf;
803 }
804
Duan Jiongf104a562013-11-08 09:56:53 +0800805 if (rinfo->prefix_len == 0)
David Ahernafb1d4b52018-04-17 17:33:11 -0700806 rt = rt6_get_dflt_router(net, gwaddr, dev);
Duan Jiongf104a562013-11-08 09:56:53 +0800807 else
808 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700809 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800810
811 if (rt && !lifetime) {
David Ahernafb1d4b52018-04-17 17:33:11 -0700812 ip6_del_rt(net, rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800813 rt = NULL;
814 }
815
816 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700817 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
818 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800819 else if (rt)
David Ahern93c2fb22018-04-18 15:38:59 -0700820 rt->fib6_flags = RTF_ROUTEINFO |
821 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800822
823 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000824 if (!addrconf_finite_timeout(lifetime))
David Ahern14895682018-04-17 17:33:17 -0700825 fib6_clean_expires(rt);
Gao feng1716a962012-04-06 00:13:10 +0000826 else
David Ahern14895682018-04-17 17:33:17 -0700827 fib6_set_expires(rt, jiffies + HZ * lifetime);
Gao feng1716a962012-04-06 00:13:10 +0000828
David Ahern93531c62018-04-17 17:33:25 -0700829 fib6_info_release(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800830 }
831 return 0;
832}
833#endif
834
David Ahernae90d862018-04-17 17:33:12 -0700835/*
836 * Misc support functions
837 */
838
839/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -0700840static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt)
David Ahernae90d862018-04-17 17:33:12 -0700841{
David Ahern5e670d82018-04-17 17:33:14 -0700842 struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernae90d862018-04-17 17:33:12 -0700843
David Ahern93c2fb22018-04-18 15:38:59 -0700844 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
David Ahernae90d862018-04-17 17:33:12 -0700845 /* for copies of local routes, dst->dev needs to be the
846 * device if it is a master device, the master device if
847 * device is enslaved, and the loopback as the default
848 */
849 if (netif_is_l3_slave(dev) &&
David Ahern93c2fb22018-04-18 15:38:59 -0700850 !rt6_need_strict(&rt->fib6_dst.addr))
David Ahernae90d862018-04-17 17:33:12 -0700851 dev = l3mdev_master_dev_rcu(dev);
852 else if (!netif_is_l3_master(dev))
853 dev = dev_net(dev)->loopback_dev;
854 /* last case is netif_is_l3_master(dev) is true in which
855 * case we want dev returned to be dev
856 */
857 }
858
859 return dev;
860}
861
David Ahern6edb3c92018-04-17 17:33:15 -0700862static const int fib6_prop[RTN_MAX + 1] = {
863 [RTN_UNSPEC] = 0,
864 [RTN_UNICAST] = 0,
865 [RTN_LOCAL] = 0,
866 [RTN_BROADCAST] = 0,
867 [RTN_ANYCAST] = 0,
868 [RTN_MULTICAST] = 0,
869 [RTN_BLACKHOLE] = -EINVAL,
870 [RTN_UNREACHABLE] = -EHOSTUNREACH,
871 [RTN_PROHIBIT] = -EACCES,
872 [RTN_THROW] = -EAGAIN,
873 [RTN_NAT] = -EINVAL,
874 [RTN_XRESOLVE] = -EINVAL,
875};
876
877static int ip6_rt_type_to_error(u8 fib6_type)
878{
879 return fib6_prop[fib6_type];
880}
881
David Ahern8d1c8022018-04-17 17:33:26 -0700882static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
David Ahern3b6761d2018-04-17 17:33:20 -0700883{
884 unsigned short flags = 0;
885
886 if (rt->dst_nocount)
887 flags |= DST_NOCOUNT;
888 if (rt->dst_nopolicy)
889 flags |= DST_NOPOLICY;
890 if (rt->dst_host)
891 flags |= DST_HOST;
892
893 return flags;
894}
895
David Ahern8d1c8022018-04-17 17:33:26 -0700896static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700897{
898 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type);
899
900 switch (ort->fib6_type) {
901 case RTN_BLACKHOLE:
902 rt->dst.output = dst_discard_out;
903 rt->dst.input = dst_discard;
904 break;
905 case RTN_PROHIBIT:
906 rt->dst.output = ip6_pkt_prohibit_out;
907 rt->dst.input = ip6_pkt_prohibit;
908 break;
909 case RTN_THROW:
910 case RTN_UNREACHABLE:
911 default:
912 rt->dst.output = ip6_pkt_discard_out;
913 rt->dst.input = ip6_pkt_discard;
914 break;
915 }
916}
917
David Ahern8d1c8022018-04-17 17:33:26 -0700918static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700919{
David Ahern3b6761d2018-04-17 17:33:20 -0700920 rt->dst.flags |= fib6_info_dst_flags(ort);
921
David Ahern93c2fb22018-04-18 15:38:59 -0700922 if (ort->fib6_flags & RTF_REJECT) {
David Ahern6edb3c92018-04-17 17:33:15 -0700923 ip6_rt_init_dst_reject(rt, ort);
924 return;
925 }
926
927 rt->dst.error = 0;
928 rt->dst.output = ip6_output;
929
930 if (ort->fib6_type == RTN_LOCAL) {
David Ahern6edb3c92018-04-17 17:33:15 -0700931 rt->dst.input = ip6_input;
David Ahern93c2fb22018-04-18 15:38:59 -0700932 } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700933 rt->dst.input = ip6_mc_input;
934 } else {
935 rt->dst.input = ip6_forward;
936 }
937
938 if (ort->fib6_nh.nh_lwtstate) {
939 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
940 lwtunnel_set_redirect(&rt->dst);
941 }
942
943 rt->dst.lastuse = jiffies;
944}
945
David Ahern8d1c8022018-04-17 17:33:26 -0700946static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
David Ahernae90d862018-04-17 17:33:12 -0700947{
David Ahernae90d862018-04-17 17:33:12 -0700948 rt->rt6i_flags &= ~RTF_EXPIRES;
David Ahern93531c62018-04-17 17:33:25 -0700949 fib6_info_hold(from);
950 rt->from = from;
David Ahernd4ead6b2018-04-17 17:33:16 -0700951 dst_init_metrics(&rt->dst, from->fib6_metrics->metrics, true);
952 if (from->fib6_metrics != &dst_default_metrics) {
953 rt->dst._metrics |= DST_METRICS_REFCOUNTED;
954 refcount_inc(&from->fib6_metrics->refcnt);
955 }
David Ahernae90d862018-04-17 17:33:12 -0700956}
957
David Ahern8d1c8022018-04-17 17:33:26 -0700958static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
David Ahernae90d862018-04-17 17:33:12 -0700959{
David Ahern6edb3c92018-04-17 17:33:15 -0700960 ip6_rt_init_dst(rt, ort);
961
David Ahern93c2fb22018-04-18 15:38:59 -0700962 rt->rt6i_dst = ort->fib6_dst;
963 rt->rt6i_idev = ort->fib6_idev;
David Ahernae90d862018-04-17 17:33:12 -0700964 if (rt->rt6i_idev)
965 in6_dev_hold(rt->rt6i_idev);
David Ahern5e670d82018-04-17 17:33:14 -0700966 rt->rt6i_gateway = ort->fib6_nh.nh_gw;
David Ahern93c2fb22018-04-18 15:38:59 -0700967 rt->rt6i_flags = ort->fib6_flags;
David Ahernae90d862018-04-17 17:33:12 -0700968 rt6_set_from(rt, ort);
David Ahernae90d862018-04-17 17:33:12 -0700969#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700970 rt->rt6i_src = ort->fib6_src;
David Ahernae90d862018-04-17 17:33:12 -0700971#endif
David Ahern93c2fb22018-04-18 15:38:59 -0700972 rt->rt6i_prefsrc = ort->fib6_prefsrc;
David Ahern5e670d82018-04-17 17:33:14 -0700973 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
David Ahernae90d862018-04-17 17:33:12 -0700974}
975
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700976static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
977 struct in6_addr *saddr)
978{
Wei Wang66f5d6c2017-10-06 12:06:10 -0700979 struct fib6_node *pn, *sn;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700980 while (1) {
981 if (fn->fn_flags & RTN_TL_ROOT)
982 return NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -0700983 pn = rcu_dereference(fn->parent);
984 sn = FIB6_SUBTREE(pn);
985 if (sn && sn != fn)
986 fn = fib6_lookup(sn, NULL, saddr);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700987 else
988 fn = pn;
989 if (fn->fn_flags & RTN_RTINFO)
990 return fn;
991 }
992}
Thomas Grafc71099a2006-08-04 23:20:06 -0700993
Wei Wangd3843fe2017-10-06 12:06:06 -0700994static bool ip6_hold_safe(struct net *net, struct rt6_info **prt,
995 bool null_fallback)
996{
997 struct rt6_info *rt = *prt;
998
999 if (dst_hold_safe(&rt->dst))
1000 return true;
1001 if (null_fallback) {
1002 rt = net->ipv6.ip6_null_entry;
1003 dst_hold(&rt->dst);
1004 } else {
1005 rt = NULL;
1006 }
1007 *prt = rt;
1008 return false;
1009}
1010
David Aherndec9b0e2018-04-17 17:33:19 -07001011/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -07001012static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt)
David Aherndec9b0e2018-04-17 17:33:19 -07001013{
David Ahern3b6761d2018-04-17 17:33:20 -07001014 unsigned short flags = fib6_info_dst_flags(rt);
David Aherndec9b0e2018-04-17 17:33:19 -07001015 struct net_device *dev = rt->fib6_nh.nh_dev;
1016 struct rt6_info *nrt;
1017
David Ahern93531c62018-04-17 17:33:25 -07001018 nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Aherndec9b0e2018-04-17 17:33:19 -07001019 if (nrt)
1020 ip6_rt_copy_init(nrt, rt);
1021
1022 return nrt;
1023}
1024
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001025static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1026 struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001027 struct flowi6 *fl6,
1028 const struct sk_buff *skb,
1029 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
David Ahern8d1c8022018-04-17 17:33:26 -07001031 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 struct fib6_node *fn;
David Ahern23fb93a2018-04-17 17:33:23 -07001033 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
David Ahernb6cdbc82018-03-29 17:44:57 -07001035 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1036 flags &= ~RT6_LOOKUP_F_IFACE;
1037
Wei Wang66f5d6c2017-10-06 12:06:10 -07001038 rcu_read_lock();
David S. Miller4c9483b2011-03-12 16:22:43 -05001039 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -07001040restart:
David Ahern23fb93a2018-04-17 17:33:23 -07001041 f6i = rcu_dereference(fn->leaf);
1042 if (!f6i) {
1043 f6i = net->ipv6.fib6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001044 } else {
David Ahern23fb93a2018-04-17 17:33:23 -07001045 f6i = rt6_device_match(net, f6i, &fl6->saddr,
Wei Wang66f5d6c2017-10-06 12:06:10 -07001046 fl6->flowi6_oif, flags);
David Ahern93c2fb22018-04-18 15:38:59 -07001047 if (f6i->fib6_nsiblings && fl6->flowi6_oif == 0)
David Ahern23fb93a2018-04-17 17:33:23 -07001048 f6i = rt6_multipath_select(net, f6i, fl6,
1049 fl6->flowi6_oif, skb, flags);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001050 }
David Ahern23fb93a2018-04-17 17:33:23 -07001051 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001052 fn = fib6_backtrack(fn, &fl6->saddr);
1053 if (fn)
1054 goto restart;
1055 }
David Ahern23fb93a2018-04-17 17:33:23 -07001056
Wei Wang2b760fc2017-10-06 12:06:03 -07001057 /* Search through exception table */
David Ahern23fb93a2018-04-17 17:33:23 -07001058 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1059 if (rt) {
David Aherndec9b0e2018-04-17 17:33:19 -07001060 if (ip6_hold_safe(net, &rt, true))
1061 dst_use_noref(&rt->dst, jiffies);
David Ahern23fb93a2018-04-17 17:33:23 -07001062 } else if (f6i == net->ipv6.fib6_null_entry) {
David Aherndec9b0e2018-04-17 17:33:19 -07001063 rt = net->ipv6.ip6_null_entry;
1064 dst_hold(&rt->dst);
David Ahern23fb93a2018-04-17 17:33:23 -07001065 } else {
1066 rt = ip6_create_rt_rcu(f6i);
1067 if (!rt) {
1068 rt = net->ipv6.ip6_null_entry;
1069 dst_hold(&rt->dst);
1070 }
David Aherndec9b0e2018-04-17 17:33:19 -07001071 }
Wei Wangd3843fe2017-10-06 12:06:06 -07001072
Wei Wang66f5d6c2017-10-06 12:06:10 -07001073 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -08001074
Paolo Abenib65f1642017-10-19 09:31:43 +02001075 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahernb8115802015-11-19 12:24:22 -08001076
Thomas Grafc71099a2006-08-04 23:20:06 -07001077 return rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001078}
1079
Ian Morris67ba4152014-08-24 21:53:10 +01001080struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08001081 const struct sk_buff *skb, int flags)
Florian Westphalea6e5742011-09-05 16:05:44 +02001082{
David Ahernb75cc8f2018-03-02 08:32:17 -08001083 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
Florian Westphalea6e5742011-09-05 16:05:44 +02001084}
1085EXPORT_SYMBOL_GPL(ip6_route_lookup);
1086
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +09001087struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
David Ahernb75cc8f2018-03-02 08:32:17 -08001088 const struct in6_addr *saddr, int oif,
1089 const struct sk_buff *skb, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -07001090{
David S. Miller4c9483b2011-03-12 16:22:43 -05001091 struct flowi6 fl6 = {
1092 .flowi6_oif = oif,
1093 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001094 };
1095 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001096 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07001097
Thomas Grafadaa70b2006-10-13 15:01:03 -07001098 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -05001099 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -07001100 flags |= RT6_LOOKUP_F_HAS_SADDR;
1101 }
1102
David Ahernb75cc8f2018-03-02 08:32:17 -08001103 dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -07001104 if (dst->error == 0)
1105 return (struct rt6_info *) dst;
1106
1107 dst_release(dst);
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 return NULL;
1110}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001111EXPORT_SYMBOL(rt6_lookup);
1112
Thomas Grafc71099a2006-08-04 23:20:06 -07001113/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -07001114 * It takes new route entry, the addition fails by any reason the
1115 * route is released.
1116 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 */
1118
David Ahern8d1c8022018-04-17 17:33:26 -07001119static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001120 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
1122 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001123 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
David Ahern93c2fb22018-04-18 15:38:59 -07001125 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001126 spin_lock_bh(&table->tb6_lock);
David Ahernd4ead6b2018-04-17 17:33:16 -07001127 err = fib6_add(&table->tb6_root, rt, info, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001128 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 return err;
1131}
1132
David Ahern8d1c8022018-04-17 17:33:26 -07001133int ip6_ins_rt(struct net *net, struct fib6_info *rt)
Thomas Graf40e22e82006-08-22 00:00:45 -07001134{
David Ahernafb1d4b52018-04-17 17:33:11 -07001135 struct nl_info info = { .nl_net = net, };
Florian Westphale715b6d2015-01-05 23:57:44 +01001136
David Ahernd4ead6b2018-04-17 17:33:16 -07001137 return __ip6_ins_rt(rt, &info, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001138}
1139
David Ahern8d1c8022018-04-17 17:33:26 -07001140static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001141 const struct in6_addr *daddr,
1142 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
David Ahern4832c302017-08-17 12:17:20 -07001144 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 struct rt6_info *rt;
1146
1147 /*
1148 * Clone the route.
1149 */
1150
David Ahern4832c302017-08-17 12:17:20 -07001151 rcu_read_lock();
1152 dev = ip6_rt_get_dev_rcu(ort);
David Ahern93531c62018-04-17 17:33:25 -07001153 rt = ip6_dst_alloc(dev_net(dev), dev, 0);
David Ahern4832c302017-08-17 12:17:20 -07001154 rcu_read_unlock();
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001155 if (!rt)
1156 return NULL;
1157
1158 ip6_rt_copy_init(rt, ort);
1159 rt->rt6i_flags |= RTF_CACHE;
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001160 rt->dst.flags |= DST_HOST;
1161 rt->rt6i_dst.addr = *daddr;
1162 rt->rt6i_dst.plen = 128;
1163
1164 if (!rt6_is_gw_or_nonexthop(ort)) {
David Ahern93c2fb22018-04-18 15:38:59 -07001165 if (ort->fib6_dst.plen != 128 &&
1166 ipv6_addr_equal(&ort->fib6_dst.addr, daddr))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001167 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001169 if (rt->rt6i_src.plen && saddr) {
1170 rt->rt6i_src.addr = *saddr;
1171 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001172 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001173#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001176 return rt;
1177}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
David Ahern8d1c8022018-04-17 17:33:26 -07001179static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001180{
David Ahern3b6761d2018-04-17 17:33:20 -07001181 unsigned short flags = fib6_info_dst_flags(rt);
David Ahern4832c302017-08-17 12:17:20 -07001182 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001183 struct rt6_info *pcpu_rt;
1184
David Ahern4832c302017-08-17 12:17:20 -07001185 rcu_read_lock();
1186 dev = ip6_rt_get_dev_rcu(rt);
David Ahern93531c62018-04-17 17:33:25 -07001187 pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Ahern4832c302017-08-17 12:17:20 -07001188 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001189 if (!pcpu_rt)
1190 return NULL;
1191 ip6_rt_copy_init(pcpu_rt, rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001192 pcpu_rt->rt6i_flags |= RTF_PCPU;
1193 return pcpu_rt;
1194}
1195
Wei Wang66f5d6c2017-10-06 12:06:10 -07001196/* It should be called with rcu_read_lock() acquired */
David Ahern8d1c8022018-04-17 17:33:26 -07001197static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001198{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001199 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001200
1201 p = this_cpu_ptr(rt->rt6i_pcpu);
1202 pcpu_rt = *p;
1203
David Ahernd4ead6b2018-04-17 17:33:16 -07001204 if (pcpu_rt)
1205 ip6_hold_safe(NULL, &pcpu_rt, false);
Wei Wangd3843fe2017-10-06 12:06:06 -07001206
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001207 return pcpu_rt;
1208}
1209
David Ahernafb1d4b52018-04-17 17:33:11 -07001210static struct rt6_info *rt6_make_pcpu_route(struct net *net,
David Ahern8d1c8022018-04-17 17:33:26 -07001211 struct fib6_info *rt)
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001212{
1213 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001214
1215 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1216 if (!pcpu_rt) {
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001217 dst_hold(&net->ipv6.ip6_null_entry->dst);
1218 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001219 }
1220
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001221 dst_hold(&pcpu_rt->dst);
Wei Wanga94b9362017-10-06 12:06:04 -07001222 p = this_cpu_ptr(rt->rt6i_pcpu);
1223 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001224 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001225
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001226 return pcpu_rt;
1227}
1228
Wei Wang35732d02017-10-06 12:05:57 -07001229/* exception hash table implementation
1230 */
1231static DEFINE_SPINLOCK(rt6_exception_lock);
1232
1233/* Remove rt6_ex from hash table and free the memory
1234 * Caller must hold rt6_exception_lock
1235 */
1236static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1237 struct rt6_exception *rt6_ex)
1238{
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001239 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001240
Wei Wang35732d02017-10-06 12:05:57 -07001241 if (!bucket || !rt6_ex)
1242 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001243
1244 net = dev_net(rt6_ex->rt6i->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001245 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001246 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001247 kfree_rcu(rt6_ex, rcu);
1248 WARN_ON_ONCE(!bucket->depth);
1249 bucket->depth--;
Wei Wang81eb8442017-10-06 12:06:11 -07001250 net->ipv6.rt6_stats->fib_rt_cache--;
Wei Wang35732d02017-10-06 12:05:57 -07001251}
1252
1253/* Remove oldest rt6_ex in bucket and free the memory
1254 * Caller must hold rt6_exception_lock
1255 */
1256static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1257{
1258 struct rt6_exception *rt6_ex, *oldest = NULL;
1259
1260 if (!bucket)
1261 return;
1262
1263 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1264 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1265 oldest = rt6_ex;
1266 }
1267 rt6_remove_exception(bucket, oldest);
1268}
1269
1270static u32 rt6_exception_hash(const struct in6_addr *dst,
1271 const struct in6_addr *src)
1272{
1273 static u32 seed __read_mostly;
1274 u32 val;
1275
1276 net_get_random_once(&seed, sizeof(seed));
1277 val = jhash(dst, sizeof(*dst), seed);
1278
1279#ifdef CONFIG_IPV6_SUBTREES
1280 if (src)
1281 val = jhash(src, sizeof(*src), val);
1282#endif
1283 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1284}
1285
1286/* Helper function to find the cached rt in the hash table
1287 * and update bucket pointer to point to the bucket for this
1288 * (daddr, saddr) pair
1289 * Caller must hold rt6_exception_lock
1290 */
1291static struct rt6_exception *
1292__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1293 const struct in6_addr *daddr,
1294 const struct in6_addr *saddr)
1295{
1296 struct rt6_exception *rt6_ex;
1297 u32 hval;
1298
1299 if (!(*bucket) || !daddr)
1300 return NULL;
1301
1302 hval = rt6_exception_hash(daddr, saddr);
1303 *bucket += hval;
1304
1305 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1306 struct rt6_info *rt6 = rt6_ex->rt6i;
1307 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1308
1309#ifdef CONFIG_IPV6_SUBTREES
1310 if (matched && saddr)
1311 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1312#endif
1313 if (matched)
1314 return rt6_ex;
1315 }
1316 return NULL;
1317}
1318
1319/* Helper function to find the cached rt in the hash table
1320 * and update bucket pointer to point to the bucket for this
1321 * (daddr, saddr) pair
1322 * Caller must hold rcu_read_lock()
1323 */
1324static struct rt6_exception *
1325__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1326 const struct in6_addr *daddr,
1327 const struct in6_addr *saddr)
1328{
1329 struct rt6_exception *rt6_ex;
1330 u32 hval;
1331
1332 WARN_ON_ONCE(!rcu_read_lock_held());
1333
1334 if (!(*bucket) || !daddr)
1335 return NULL;
1336
1337 hval = rt6_exception_hash(daddr, saddr);
1338 *bucket += hval;
1339
1340 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1341 struct rt6_info *rt6 = rt6_ex->rt6i;
1342 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1343
1344#ifdef CONFIG_IPV6_SUBTREES
1345 if (matched && saddr)
1346 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1347#endif
1348 if (matched)
1349 return rt6_ex;
1350 }
1351 return NULL;
1352}
1353
David Ahern8d1c8022018-04-17 17:33:26 -07001354static unsigned int fib6_mtu(const struct fib6_info *rt)
David Ahernd4ead6b2018-04-17 17:33:16 -07001355{
1356 unsigned int mtu;
1357
David Ahern93c2fb22018-04-18 15:38:59 -07001358 mtu = rt->fib6_pmtu ? : rt->fib6_idev->cnf.mtu6;
David Ahernd4ead6b2018-04-17 17:33:16 -07001359 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1360
1361 return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu);
1362}
1363
Wei Wang35732d02017-10-06 12:05:57 -07001364static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern8d1c8022018-04-17 17:33:26 -07001365 struct fib6_info *ort)
Wei Wang35732d02017-10-06 12:05:57 -07001366{
David Ahern5e670d82018-04-17 17:33:14 -07001367 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001368 struct rt6_exception_bucket *bucket;
1369 struct in6_addr *src_key = NULL;
1370 struct rt6_exception *rt6_ex;
1371 int err = 0;
1372
Wei Wang35732d02017-10-06 12:05:57 -07001373 spin_lock_bh(&rt6_exception_lock);
1374
1375 if (ort->exception_bucket_flushed) {
1376 err = -EINVAL;
1377 goto out;
1378 }
1379
1380 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1381 lockdep_is_held(&rt6_exception_lock));
1382 if (!bucket) {
1383 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1384 GFP_ATOMIC);
1385 if (!bucket) {
1386 err = -ENOMEM;
1387 goto out;
1388 }
1389 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1390 }
1391
1392#ifdef CONFIG_IPV6_SUBTREES
1393 /* rt6i_src.plen != 0 indicates ort is in subtree
1394 * and exception table is indexed by a hash of
1395 * both rt6i_dst and rt6i_src.
1396 * Otherwise, the exception table is indexed by
1397 * a hash of only rt6i_dst.
1398 */
David Ahern93c2fb22018-04-18 15:38:59 -07001399 if (ort->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001400 src_key = &nrt->rt6i_src.addr;
1401#endif
Wei Wang60006a42017-10-06 12:05:58 -07001402
1403 /* Update rt6i_prefsrc as it could be changed
1404 * in rt6_remove_prefsrc()
1405 */
David Ahern93c2fb22018-04-18 15:38:59 -07001406 nrt->rt6i_prefsrc = ort->fib6_prefsrc;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001407 /* rt6_mtu_change() might lower mtu on ort.
1408 * Only insert this exception route if its mtu
1409 * is less than ort's mtu value.
1410 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001411 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(ort)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001412 err = -EINVAL;
1413 goto out;
1414 }
Wei Wang60006a42017-10-06 12:05:58 -07001415
Wei Wang35732d02017-10-06 12:05:57 -07001416 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1417 src_key);
1418 if (rt6_ex)
1419 rt6_remove_exception(bucket, rt6_ex);
1420
1421 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1422 if (!rt6_ex) {
1423 err = -ENOMEM;
1424 goto out;
1425 }
1426 rt6_ex->rt6i = nrt;
1427 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001428 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1429 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001430 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001431
1432 if (bucket->depth > FIB6_MAX_DEPTH)
1433 rt6_exception_remove_oldest(bucket);
1434
1435out:
1436 spin_unlock_bh(&rt6_exception_lock);
1437
1438 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001439 if (!err) {
David Ahern93c2fb22018-04-18 15:38:59 -07001440 spin_lock_bh(&ort->fib6_table->tb6_lock);
David Ahern7aef6852018-04-17 17:33:10 -07001441 fib6_update_sernum(net, ort);
David Ahern93c2fb22018-04-18 15:38:59 -07001442 spin_unlock_bh(&ort->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001443 fib6_force_start_gc(net);
1444 }
Wei Wang35732d02017-10-06 12:05:57 -07001445
1446 return err;
1447}
1448
David Ahern8d1c8022018-04-17 17:33:26 -07001449void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001450{
1451 struct rt6_exception_bucket *bucket;
1452 struct rt6_exception *rt6_ex;
1453 struct hlist_node *tmp;
1454 int i;
1455
1456 spin_lock_bh(&rt6_exception_lock);
1457 /* Prevent rt6_insert_exception() to recreate the bucket list */
1458 rt->exception_bucket_flushed = 1;
1459
1460 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1461 lockdep_is_held(&rt6_exception_lock));
1462 if (!bucket)
1463 goto out;
1464
1465 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1466 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1467 rt6_remove_exception(bucket, rt6_ex);
1468 WARN_ON_ONCE(bucket->depth);
1469 bucket++;
1470 }
1471
1472out:
1473 spin_unlock_bh(&rt6_exception_lock);
1474}
1475
1476/* Find cached rt in the hash table inside passed in rt
1477 * Caller has to hold rcu_read_lock()
1478 */
David Ahern8d1c8022018-04-17 17:33:26 -07001479static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -07001480 struct in6_addr *daddr,
1481 struct in6_addr *saddr)
1482{
1483 struct rt6_exception_bucket *bucket;
1484 struct in6_addr *src_key = NULL;
1485 struct rt6_exception *rt6_ex;
1486 struct rt6_info *res = NULL;
1487
1488 bucket = rcu_dereference(rt->rt6i_exception_bucket);
1489
1490#ifdef CONFIG_IPV6_SUBTREES
1491 /* rt6i_src.plen != 0 indicates rt is in subtree
1492 * and exception table is indexed by a hash of
1493 * both rt6i_dst and rt6i_src.
1494 * Otherwise, the exception table is indexed by
1495 * a hash of only rt6i_dst.
1496 */
David Ahern93c2fb22018-04-18 15:38:59 -07001497 if (rt->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001498 src_key = saddr;
1499#endif
1500 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1501
1502 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1503 res = rt6_ex->rt6i;
1504
1505 return res;
1506}
1507
1508/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001509static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001510{
Wei Wang35732d02017-10-06 12:05:57 -07001511 struct rt6_exception_bucket *bucket;
David Ahern8d1c8022018-04-17 17:33:26 -07001512 struct fib6_info *from = rt->from;
Wei Wang35732d02017-10-06 12:05:57 -07001513 struct in6_addr *src_key = NULL;
1514 struct rt6_exception *rt6_ex;
1515 int err;
1516
1517 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001518 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001519 return -EINVAL;
1520
1521 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1522 return -ENOENT;
1523
1524 spin_lock_bh(&rt6_exception_lock);
1525 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1526 lockdep_is_held(&rt6_exception_lock));
1527#ifdef CONFIG_IPV6_SUBTREES
1528 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1529 * and exception table is indexed by a hash of
1530 * both rt6i_dst and rt6i_src.
1531 * Otherwise, the exception table is indexed by
1532 * a hash of only rt6i_dst.
1533 */
David Ahern93c2fb22018-04-18 15:38:59 -07001534 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001535 src_key = &rt->rt6i_src.addr;
1536#endif
1537 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1538 &rt->rt6i_dst.addr,
1539 src_key);
1540 if (rt6_ex) {
1541 rt6_remove_exception(bucket, rt6_ex);
1542 err = 0;
1543 } else {
1544 err = -ENOENT;
1545 }
1546
1547 spin_unlock_bh(&rt6_exception_lock);
1548 return err;
1549}
1550
1551/* Find rt6_ex which contains the passed in rt cache and
1552 * refresh its stamp
1553 */
1554static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1555{
Wei Wang35732d02017-10-06 12:05:57 -07001556 struct rt6_exception_bucket *bucket;
David Ahern8d1c8022018-04-17 17:33:26 -07001557 struct fib6_info *from = rt->from;
Wei Wang35732d02017-10-06 12:05:57 -07001558 struct in6_addr *src_key = NULL;
1559 struct rt6_exception *rt6_ex;
1560
1561 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001562 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001563 return;
1564
1565 rcu_read_lock();
1566 bucket = rcu_dereference(from->rt6i_exception_bucket);
1567
1568#ifdef CONFIG_IPV6_SUBTREES
1569 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1570 * and exception table is indexed by a hash of
1571 * both rt6i_dst and rt6i_src.
1572 * Otherwise, the exception table is indexed by
1573 * a hash of only rt6i_dst.
1574 */
David Ahern93c2fb22018-04-18 15:38:59 -07001575 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001576 src_key = &rt->rt6i_src.addr;
1577#endif
1578 rt6_ex = __rt6_find_exception_rcu(&bucket,
1579 &rt->rt6i_dst.addr,
1580 src_key);
1581 if (rt6_ex)
1582 rt6_ex->stamp = jiffies;
1583
1584 rcu_read_unlock();
1585}
1586
David Ahern8d1c8022018-04-17 17:33:26 -07001587static void rt6_exceptions_remove_prefsrc(struct fib6_info *rt)
Wei Wang60006a42017-10-06 12:05:58 -07001588{
1589 struct rt6_exception_bucket *bucket;
1590 struct rt6_exception *rt6_ex;
1591 int i;
1592
1593 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1594 lockdep_is_held(&rt6_exception_lock));
1595
1596 if (bucket) {
1597 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1598 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1599 rt6_ex->rt6i->rt6i_prefsrc.plen = 0;
1600 }
1601 bucket++;
1602 }
1603 }
1604}
1605
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001606static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1607 struct rt6_info *rt, int mtu)
1608{
1609 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1610 * lowest MTU in the path: always allow updating the route PMTU to
1611 * reflect PMTU decreases.
1612 *
1613 * If the new MTU is higher, and the route PMTU is equal to the local
1614 * MTU, this means the old MTU is the lowest in the path, so allow
1615 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1616 * handle this.
1617 */
1618
1619 if (dst_mtu(&rt->dst) >= mtu)
1620 return true;
1621
1622 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1623 return true;
1624
1625 return false;
1626}
1627
1628static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001629 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001630{
1631 struct rt6_exception_bucket *bucket;
1632 struct rt6_exception *rt6_ex;
1633 int i;
1634
1635 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1636 lockdep_is_held(&rt6_exception_lock));
1637
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001638 if (!bucket)
1639 return;
1640
1641 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1642 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1643 struct rt6_info *entry = rt6_ex->rt6i;
1644
1645 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001646 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001647 * been updated.
1648 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001649 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001650 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001651 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001652 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001653 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001654 }
1655}
1656
Wei Wangb16cb452017-10-06 12:06:00 -07001657#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1658
David Ahern8d1c8022018-04-17 17:33:26 -07001659static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001660 struct in6_addr *gateway)
1661{
1662 struct rt6_exception_bucket *bucket;
1663 struct rt6_exception *rt6_ex;
1664 struct hlist_node *tmp;
1665 int i;
1666
1667 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1668 return;
1669
1670 spin_lock_bh(&rt6_exception_lock);
1671 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1672 lockdep_is_held(&rt6_exception_lock));
1673
1674 if (bucket) {
1675 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1676 hlist_for_each_entry_safe(rt6_ex, tmp,
1677 &bucket->chain, hlist) {
1678 struct rt6_info *entry = rt6_ex->rt6i;
1679
1680 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1681 RTF_CACHE_GATEWAY &&
1682 ipv6_addr_equal(gateway,
1683 &entry->rt6i_gateway)) {
1684 rt6_remove_exception(bucket, rt6_ex);
1685 }
1686 }
1687 bucket++;
1688 }
1689 }
1690
1691 spin_unlock_bh(&rt6_exception_lock);
1692}
1693
Wei Wangc757faa2017-10-06 12:06:01 -07001694static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1695 struct rt6_exception *rt6_ex,
1696 struct fib6_gc_args *gc_args,
1697 unsigned long now)
1698{
1699 struct rt6_info *rt = rt6_ex->rt6i;
1700
Paolo Abeni1859bac2017-10-19 16:07:11 +02001701 /* we are pruning and obsoleting aged-out and non gateway exceptions
1702 * even if others have still references to them, so that on next
1703 * dst_check() such references can be dropped.
1704 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1705 * expired, independently from their aging, as per RFC 8201 section 4
1706 */
Wei Wang31afeb42018-01-26 11:40:17 -08001707 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1708 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1709 RT6_TRACE("aging clone %p\n", rt);
1710 rt6_remove_exception(bucket, rt6_ex);
1711 return;
1712 }
1713 } else if (time_after(jiffies, rt->dst.expires)) {
1714 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001715 rt6_remove_exception(bucket, rt6_ex);
1716 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001717 }
1718
1719 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001720 struct neighbour *neigh;
1721 __u8 neigh_flags = 0;
1722
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001723 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1724 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001725 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001726
Wei Wangc757faa2017-10-06 12:06:01 -07001727 if (!(neigh_flags & NTF_ROUTER)) {
1728 RT6_TRACE("purging route %p via non-router but gateway\n",
1729 rt);
1730 rt6_remove_exception(bucket, rt6_ex);
1731 return;
1732 }
1733 }
Wei Wang31afeb42018-01-26 11:40:17 -08001734
Wei Wangc757faa2017-10-06 12:06:01 -07001735 gc_args->more++;
1736}
1737
David Ahern8d1c8022018-04-17 17:33:26 -07001738void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001739 struct fib6_gc_args *gc_args,
1740 unsigned long now)
1741{
1742 struct rt6_exception_bucket *bucket;
1743 struct rt6_exception *rt6_ex;
1744 struct hlist_node *tmp;
1745 int i;
1746
1747 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1748 return;
1749
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001750 rcu_read_lock_bh();
1751 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001752 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1753 lockdep_is_held(&rt6_exception_lock));
1754
1755 if (bucket) {
1756 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1757 hlist_for_each_entry_safe(rt6_ex, tmp,
1758 &bucket->chain, hlist) {
1759 rt6_age_examine_exception(bucket, rt6_ex,
1760 gc_args, now);
1761 }
1762 bucket++;
1763 }
1764 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001765 spin_unlock(&rt6_exception_lock);
1766 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001767}
1768
David Ahern9ff74382016-06-13 13:44:19 -07001769struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001770 int oif, struct flowi6 *fl6,
1771 const struct sk_buff *skb, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001773 struct fib6_node *fn, *saved_fn;
David Ahern8d1c8022018-04-17 17:33:26 -07001774 struct fib6_info *f6i;
David Ahern23fb93a2018-04-17 17:33:23 -07001775 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001776 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001778 strict |= flags & RT6_LOOKUP_F_IFACE;
David Ahernd5d32e42016-10-24 12:27:23 -07001779 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001780 if (net->ipv6.devconf_all->forwarding == 0)
1781 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Wei Wang66f5d6c2017-10-06 12:06:10 -07001783 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
David S. Miller4c9483b2011-03-12 16:22:43 -05001785 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001786 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
David Ahernca254492015-10-12 11:47:10 -07001788 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1789 oif = 0;
1790
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001791redo_rt6_select:
David Ahern23fb93a2018-04-17 17:33:23 -07001792 f6i = rt6_select(net, fn, oif, strict);
David Ahern93c2fb22018-04-18 15:38:59 -07001793 if (f6i->fib6_nsiblings)
David Ahern23fb93a2018-04-17 17:33:23 -07001794 f6i = rt6_multipath_select(net, f6i, fl6, oif, skb, strict);
1795 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001796 fn = fib6_backtrack(fn, &fl6->saddr);
1797 if (fn)
1798 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001799 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1800 /* also consider unreachable route */
1801 strict &= ~RT6_LOOKUP_F_REACHABLE;
1802 fn = saved_fn;
1803 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001804 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001805 }
1806
David Ahern23fb93a2018-04-17 17:33:23 -07001807 if (f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001808 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001809 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001810 dst_hold(&rt->dst);
Paolo Abenib65f1642017-10-19 09:31:43 +02001811 trace_fib6_table_lookup(net, rt, table, fl6);
Wei Wangd3843fe2017-10-06 12:06:06 -07001812 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001813 }
1814
1815 /*Search through exception table */
1816 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1817 if (rt) {
David Ahernd4ead6b2018-04-17 17:33:16 -07001818 if (ip6_hold_safe(net, &rt, true))
Wei Wangd3843fe2017-10-06 12:06:06 -07001819 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001820
Wei Wang66f5d6c2017-10-06 12:06:10 -07001821 rcu_read_unlock();
Paolo Abenib65f1642017-10-19 09:31:43 +02001822 trace_fib6_table_lookup(net, rt, table, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001823 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001824 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahern93c2fb22018-04-18 15:38:59 -07001825 !(f6i->fib6_flags & RTF_GATEWAY))) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001826 /* Create a RTF_CACHE clone which will not be
1827 * owned by the fib6 tree. It is for the special case where
1828 * the daddr in the skb during the neighbor look-up is different
1829 * from the fl6->daddr used to look-up route here.
1830 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001831
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001832 struct rt6_info *uncached_rt;
1833
David Ahern93531c62018-04-17 17:33:25 -07001834 fib6_info_hold(f6i);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001835 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001836
David Ahern23fb93a2018-04-17 17:33:23 -07001837 uncached_rt = ip6_rt_cache_alloc(f6i, &fl6->daddr, NULL);
David Ahern93531c62018-04-17 17:33:25 -07001838 fib6_info_release(f6i);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001839
Wei Wang1cfb71e2017-06-17 10:42:33 -07001840 if (uncached_rt) {
1841 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1842 * No need for another dst_hold()
1843 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001844 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001845 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001846 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001847 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001848 dst_hold(&uncached_rt->dst);
1849 }
David Ahernb8115802015-11-19 12:24:22 -08001850
Paolo Abenib65f1642017-10-19 09:31:43 +02001851 trace_fib6_table_lookup(net, uncached_rt, table, fl6);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001852 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001853
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001854 } else {
1855 /* Get a percpu copy */
1856
1857 struct rt6_info *pcpu_rt;
1858
Eric Dumazet951f7882017-10-08 21:07:18 -07001859 local_bh_disable();
David Ahern23fb93a2018-04-17 17:33:23 -07001860 pcpu_rt = rt6_get_pcpu_route(f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001861
David Ahern93531c62018-04-17 17:33:25 -07001862 if (!pcpu_rt)
1863 pcpu_rt = rt6_make_pcpu_route(net, f6i);
1864
Eric Dumazet951f7882017-10-08 21:07:18 -07001865 local_bh_enable();
1866 rcu_read_unlock();
Paolo Abenib65f1642017-10-19 09:31:43 +02001867 trace_fib6_table_lookup(net, pcpu_rt, table, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001868 return pcpu_rt;
1869 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001870}
David Ahern9ff74382016-06-13 13:44:19 -07001871EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001872
David Ahernb75cc8f2018-03-02 08:32:17 -08001873static struct rt6_info *ip6_pol_route_input(struct net *net,
1874 struct fib6_table *table,
1875 struct flowi6 *fl6,
1876 const struct sk_buff *skb,
1877 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001878{
David Ahernb75cc8f2018-03-02 08:32:17 -08001879 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001880}
1881
Mahesh Bandeward409b842016-09-16 12:59:08 -07001882struct dst_entry *ip6_route_input_lookup(struct net *net,
1883 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001884 struct flowi6 *fl6,
1885 const struct sk_buff *skb,
1886 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001887{
1888 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1889 flags |= RT6_LOOKUP_F_IFACE;
1890
David Ahernb75cc8f2018-03-02 08:32:17 -08001891 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001892}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001893EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001894
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001895static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001896 struct flow_keys *keys,
1897 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001898{
1899 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1900 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001901 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001902 const struct ipv6hdr *inner_iph;
1903 const struct icmp6hdr *icmph;
1904 struct ipv6hdr _inner_iph;
1905
1906 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1907 goto out;
1908
1909 icmph = icmp6_hdr(skb);
1910 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1911 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1912 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1913 icmph->icmp6_type != ICMPV6_PARAMPROB)
1914 goto out;
1915
1916 inner_iph = skb_header_pointer(skb,
1917 skb_transport_offset(skb) + sizeof(*icmph),
1918 sizeof(_inner_iph), &_inner_iph);
1919 if (!inner_iph)
1920 goto out;
1921
1922 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001923 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001924out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001925 if (_flkeys) {
1926 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1927 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1928 keys->tags.flow_label = _flkeys->tags.flow_label;
1929 keys->basic.ip_proto = _flkeys->basic.ip_proto;
1930 } else {
1931 keys->addrs.v6addrs.src = key_iph->saddr;
1932 keys->addrs.v6addrs.dst = key_iph->daddr;
1933 keys->tags.flow_label = ip6_flowinfo(key_iph);
1934 keys->basic.ip_proto = key_iph->nexthdr;
1935 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001936}
1937
1938/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08001939u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
1940 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001941{
1942 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08001943 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001944
David S. Millerbbfa0472018-03-12 11:09:33 -04001945 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08001946 case 0:
1947 memset(&hash_keys, 0, sizeof(hash_keys));
1948 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1949 if (skb) {
1950 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
1951 } else {
1952 hash_keys.addrs.v6addrs.src = fl6->saddr;
1953 hash_keys.addrs.v6addrs.dst = fl6->daddr;
1954 hash_keys.tags.flow_label = (__force u32)fl6->flowlabel;
1955 hash_keys.basic.ip_proto = fl6->flowi6_proto;
1956 }
1957 break;
1958 case 1:
1959 if (skb) {
1960 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
1961 struct flow_keys keys;
1962
1963 /* short-circuit if we already have L4 hash present */
1964 if (skb->l4_hash)
1965 return skb_get_hash_raw(skb) >> 1;
1966
1967 memset(&hash_keys, 0, sizeof(hash_keys));
1968
1969 if (!flkeys) {
1970 skb_flow_dissect_flow_keys(skb, &keys, flag);
1971 flkeys = &keys;
1972 }
1973 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1974 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
1975 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
1976 hash_keys.ports.src = flkeys->ports.src;
1977 hash_keys.ports.dst = flkeys->ports.dst;
1978 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
1979 } else {
1980 memset(&hash_keys, 0, sizeof(hash_keys));
1981 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1982 hash_keys.addrs.v6addrs.src = fl6->saddr;
1983 hash_keys.addrs.v6addrs.dst = fl6->daddr;
1984 hash_keys.ports.src = fl6->fl6_sport;
1985 hash_keys.ports.dst = fl6->fl6_dport;
1986 hash_keys.basic.ip_proto = fl6->flowi6_proto;
1987 }
1988 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001989 }
David Ahern9a2a5372018-03-02 08:32:15 -08001990 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001991
David Ahern9a2a5372018-03-02 08:32:15 -08001992 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001993}
1994
Thomas Grafc71099a2006-08-04 23:20:06 -07001995void ip6_route_input(struct sk_buff *skb)
1996{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001997 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001998 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001999 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002000 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002001 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002002 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002003 .daddr = iph->daddr,
2004 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002005 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002006 .flowi6_mark = skb->mark,
2007 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002008 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002009 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002010
Jiri Benc904af042015-08-20 13:56:31 +02002011 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002012 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002013 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002014
2015 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2016 flkeys = &_flkeys;
2017
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002018 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002019 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002020 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002021 skb_dst_set(skb,
2022 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002023}
2024
David Ahernb75cc8f2018-03-02 08:32:17 -08002025static struct rt6_info *ip6_pol_route_output(struct net *net,
2026 struct fib6_table *table,
2027 struct flowi6 *fl6,
2028 const struct sk_buff *skb,
2029 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002030{
David Ahernb75cc8f2018-03-02 08:32:17 -08002031 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002032}
2033
Paolo Abeni6f21c962016-01-29 12:30:19 +01002034struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2035 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002036{
David Ahernd46a9d62015-10-21 08:42:22 -07002037 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002038
David Ahern4c1feac2016-09-10 12:09:56 -07002039 if (rt6_need_strict(&fl6->daddr)) {
2040 struct dst_entry *dst;
2041
2042 dst = l3mdev_link_scope_lookup(net, fl6);
2043 if (dst)
2044 return dst;
2045 }
David Ahernca254492015-10-12 11:47:10 -07002046
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002047 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002048
David Ahernd46a9d62015-10-21 08:42:22 -07002049 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002050 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002051 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002052 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002053
David Ahernd46a9d62015-10-21 08:42:22 -07002054 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002055 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002056 else if (sk)
2057 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002058
David Ahernb75cc8f2018-03-02 08:32:17 -08002059 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002061EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
David S. Miller2774c132011-03-01 14:59:04 -08002063struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002064{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002065 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002066 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002067 struct dst_entry *new = NULL;
2068
Wei Wang1dbe32522017-06-17 10:42:26 -07002069 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002070 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002071 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002072 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002073 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002074
Changli Gaod8d1f302010-06-10 23:31:35 -07002075 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002076 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002077 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002078 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002079
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002080 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002081
Wei Wang1dbe32522017-06-17 10:42:26 -07002082 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002083 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002084 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002085
2086 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2087#ifdef CONFIG_IPV6_SUBTREES
2088 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2089#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002090 }
2091
David S. Miller69ead7a2011-03-01 14:45:33 -08002092 dst_release(dst_orig);
2093 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002094}
David S. Miller14e50e52007-05-24 18:17:54 -07002095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096/*
2097 * Destination cache support functions
2098 */
2099
David Ahern8d1c8022018-04-17 17:33:26 -07002100static bool fib6_check(struct fib6_info *f6i, u32 cookie)
David Ahern93531c62018-04-17 17:33:25 -07002101{
2102 u32 rt_cookie = 0;
2103
2104 if ((f6i && !rt6_get_cookie_safe(f6i, &rt_cookie)) ||
2105 rt_cookie != cookie)
2106 return false;
2107
2108 if (fib6_check_expired(f6i))
2109 return false;
2110
2111 return true;
2112}
2113
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002114static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
2115{
Steffen Klassert36143642017-08-25 09:05:42 +02002116 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002117
David Ahern93531c62018-04-17 17:33:25 -07002118 if ((rt->from && !rt6_get_cookie_safe(rt->from, &rt_cookie)) ||
2119 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002120 return NULL;
2121
2122 if (rt6_check_expired(rt))
2123 return NULL;
2124
2125 return &rt->dst;
2126}
2127
2128static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
2129{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002130 if (!__rt6_check_expired(rt) &&
2131 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Ahern93531c62018-04-17 17:33:25 -07002132 fib6_check(rt->from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002133 return &rt->dst;
2134 else
2135 return NULL;
2136}
2137
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2139{
2140 struct rt6_info *rt;
2141
2142 rt = (struct rt6_info *) dst;
2143
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002144 /* All IPV6 dsts are created with ->obsolete set to the value
2145 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2146 * into this function always.
2147 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002148
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08002149 if (rt->rt6i_flags & RTF_PCPU ||
David Miller3a2232e2017-11-28 15:40:40 -05002150 (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002151 return rt6_dst_from_check(rt, cookie);
2152 else
2153 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154}
2155
2156static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2157{
2158 struct rt6_info *rt = (struct rt6_info *) dst;
2159
2160 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002161 if (rt->rt6i_flags & RTF_CACHE) {
2162 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002163 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002164 dst = NULL;
2165 }
2166 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002168 dst = NULL;
2169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002171 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172}
2173
2174static void ip6_link_failure(struct sk_buff *skb)
2175{
2176 struct rt6_info *rt;
2177
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002178 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Eric Dumazetadf30902009-06-02 05:19:30 +00002180 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002182 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07002183 if (dst_hold_safe(&rt->dst))
David Ahern93531c62018-04-17 17:33:25 -07002184 rt6_remove_exception_rt(rt);
2185 } else if (rt->from) {
Wei Wangc5cff852017-08-21 09:47:10 -07002186 struct fib6_node *fn;
2187
2188 rcu_read_lock();
David Ahern93c2fb22018-04-18 15:38:59 -07002189 fn = rcu_dereference(rt->from->fib6_node);
Wei Wangc5cff852017-08-21 09:47:10 -07002190 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2191 fn->fn_sernum = -1;
2192 rcu_read_unlock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 }
2195}
2196
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002197static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2198{
2199 struct net *net = dev_net(rt->dst.dev);
2200
David Ahernd4ead6b2018-04-17 17:33:16 -07002201 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002202 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002203 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2204}
2205
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002206static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2207{
2208 return !(rt->rt6i_flags & RTF_CACHE) &&
David Ahern77634cc2018-04-17 17:33:27 -07002209 (rt->rt6i_flags & RTF_PCPU || rt->from);
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002210}
2211
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002212static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2213 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002215 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002216 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002218 if (rt6->rt6i_flags & RTF_LOCAL)
2219 return;
2220
Xin Long19bda362016-10-28 18:18:01 +08002221 if (dst_metric_locked(dst, RTAX_MTU))
2222 return;
2223
Julian Anastasov0dec8792017-02-06 23:14:16 +02002224 if (iph) {
2225 daddr = &iph->daddr;
2226 saddr = &iph->saddr;
2227 } else if (sk) {
2228 daddr = &sk->sk_v6_daddr;
2229 saddr = &inet6_sk(sk)->saddr;
2230 } else {
2231 daddr = NULL;
2232 saddr = NULL;
2233 }
2234 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002235 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2236 if (mtu >= dst_mtu(dst))
2237 return;
David S. Miller81aded22012-06-15 14:54:11 -07002238
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002239 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002240 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002241 /* update rt6_ex->stamp for cache */
2242 if (rt6->rt6i_flags & RTF_CACHE)
2243 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002244 } else if (daddr) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002245 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002246
David Ahernd4ead6b2018-04-17 17:33:16 -07002247 nrt6 = ip6_rt_cache_alloc(rt6->from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002248 if (nrt6) {
2249 rt6_do_update_pmtu(nrt6, mtu);
David Ahernd4ead6b2018-04-17 17:33:16 -07002250 if (rt6_insert_exception(nrt6, rt6->from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002251 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254}
2255
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002256static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2257 struct sk_buff *skb, u32 mtu)
2258{
2259 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2260}
2261
David S. Miller42ae66c2012-06-15 20:01:57 -07002262void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002263 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002264{
2265 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2266 struct dst_entry *dst;
2267 struct flowi6 fl6;
2268
2269 memset(&fl6, 0, sizeof(fl6));
2270 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07002271 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07002272 fl6.daddr = iph->daddr;
2273 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002274 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002275 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07002276
2277 dst = ip6_route_output(net, NULL, &fl6);
2278 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002279 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002280 dst_release(dst);
2281}
2282EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2283
2284void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2285{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002286 struct dst_entry *dst;
2287
David S. Miller81aded22012-06-15 14:54:11 -07002288 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002289 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002290
2291 dst = __sk_dst_get(sk);
2292 if (!dst || !dst->obsolete ||
2293 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2294 return;
2295
2296 bh_lock_sock(sk);
2297 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2298 ip6_datagram_dst_update(sk, false);
2299 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002300}
2301EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2302
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002303void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2304 const struct flowi6 *fl6)
2305{
2306#ifdef CONFIG_IPV6_SUBTREES
2307 struct ipv6_pinfo *np = inet6_sk(sk);
2308#endif
2309
2310 ip6_dst_store(sk, dst,
2311 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2312 &sk->sk_v6_daddr : NULL,
2313#ifdef CONFIG_IPV6_SUBTREES
2314 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2315 &np->saddr :
2316#endif
2317 NULL);
2318}
2319
Duan Jiongb55b76b2013-09-04 19:44:21 +08002320/* Handle redirects */
2321struct ip6rd_flowi {
2322 struct flowi6 fl6;
2323 struct in6_addr gateway;
2324};
2325
2326static struct rt6_info *__ip6_route_redirect(struct net *net,
2327 struct fib6_table *table,
2328 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002329 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002330 int flags)
2331{
2332 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern23fb93a2018-04-17 17:33:23 -07002333 struct rt6_info *ret = NULL, *rt_cache;
David Ahern8d1c8022018-04-17 17:33:26 -07002334 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002335 struct fib6_node *fn;
2336
2337 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002338 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002339 *
2340 * RFC 4861 specifies that redirects should only be
2341 * accepted if they come from the nexthop to the target.
2342 * Due to the way the routes are chosen, this notion
2343 * is a bit fuzzy and one might need to check all possible
2344 * routes.
2345 */
2346
Wei Wang66f5d6c2017-10-06 12:06:10 -07002347 rcu_read_lock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002348 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
2349restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002350 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07002351 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +02002352 continue;
David Ahern14895682018-04-17 17:33:17 -07002353 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002354 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002355 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002356 break;
David Ahern93c2fb22018-04-18 15:38:59 -07002357 if (!(rt->fib6_flags & RTF_GATEWAY))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002358 continue;
David Ahern5e670d82018-04-17 17:33:14 -07002359 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002360 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002361 /* rt_cache's gateway might be different from its 'parent'
2362 * in the case of an ip redirect.
2363 * So we keep searching in the exception table if the gateway
2364 * is different.
2365 */
David Ahern5e670d82018-04-17 17:33:14 -07002366 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002367 rt_cache = rt6_find_cached_rt(rt,
2368 &fl6->daddr,
2369 &fl6->saddr);
2370 if (rt_cache &&
2371 ipv6_addr_equal(&rdfl->gateway,
2372 &rt_cache->rt6i_gateway)) {
David Ahern23fb93a2018-04-17 17:33:23 -07002373 ret = rt_cache;
Wei Wang2b760fc2017-10-06 12:06:03 -07002374 break;
2375 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002376 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002377 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002378 break;
2379 }
2380
2381 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002382 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002383 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002384 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002385 goto out;
2386 }
2387
David Ahern421842e2018-04-17 17:33:18 -07002388 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002389 fn = fib6_backtrack(fn, &fl6->saddr);
2390 if (fn)
2391 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002392 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002393
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002394out:
David Ahern23fb93a2018-04-17 17:33:23 -07002395 if (ret)
2396 dst_hold(&ret->dst);
2397 else
2398 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002399
Wei Wang66f5d6c2017-10-06 12:06:10 -07002400 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002401
David Ahern23fb93a2018-04-17 17:33:23 -07002402 trace_fib6_table_lookup(net, ret, table, fl6);
2403 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002404};
2405
2406static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002407 const struct flowi6 *fl6,
2408 const struct sk_buff *skb,
2409 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002410{
2411 int flags = RT6_LOOKUP_F_HAS_SADDR;
2412 struct ip6rd_flowi rdfl;
2413
2414 rdfl.fl6 = *fl6;
2415 rdfl.gateway = *gateway;
2416
David Ahernb75cc8f2018-03-02 08:32:17 -08002417 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002418 flags, __ip6_route_redirect);
2419}
2420
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002421void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2422 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002423{
2424 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2425 struct dst_entry *dst;
2426 struct flowi6 fl6;
2427
2428 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002429 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002430 fl6.flowi6_oif = oif;
2431 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002432 fl6.daddr = iph->daddr;
2433 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002434 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002435 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002436
David Ahernb75cc8f2018-03-02 08:32:17 -08002437 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002438 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002439 dst_release(dst);
2440}
2441EXPORT_SYMBOL_GPL(ip6_redirect);
2442
Duan Jiongc92a59e2013-08-22 12:07:35 +08002443void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
2444 u32 mark)
2445{
2446 const struct ipv6hdr *iph = ipv6_hdr(skb);
2447 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2448 struct dst_entry *dst;
2449 struct flowi6 fl6;
2450
2451 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002452 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002453 fl6.flowi6_oif = oif;
2454 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002455 fl6.daddr = msg->dest;
2456 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002457 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002458
David Ahernb75cc8f2018-03-02 08:32:17 -08002459 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002460 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002461 dst_release(dst);
2462}
2463
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002464void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2465{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002466 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2467 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002468}
2469EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2470
David S. Miller0dbaee32010-12-13 12:52:14 -08002471static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472{
David S. Miller0dbaee32010-12-13 12:52:14 -08002473 struct net_device *dev = dst->dev;
2474 unsigned int mtu = dst_mtu(dst);
2475 struct net *net = dev_net(dev);
2476
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2478
Daniel Lezcano55786892008-03-04 13:47:47 -08002479 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2480 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002483 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2484 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2485 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 * rely only on pmtu discovery"
2487 */
2488 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2489 mtu = IPV6_MAXPLEN;
2490 return mtu;
2491}
2492
Steffen Klassertebb762f2011-11-23 02:12:51 +00002493static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002494{
David S. Millerd33e4552010-12-14 13:01:14 -08002495 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002496 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002497
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002498 mtu = dst_metric_raw(dst, RTAX_MTU);
2499 if (mtu)
2500 goto out;
2501
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002502 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002503
2504 rcu_read_lock();
2505 idev = __in6_dev_get(dst->dev);
2506 if (idev)
2507 mtu = idev->cnf.mtu6;
2508 rcu_read_unlock();
2509
Eric Dumazet30f78d82014-04-10 21:23:36 -07002510out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002511 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2512
2513 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002514}
2515
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002516struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002517 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518{
David S. Miller87a11572011-12-06 17:04:13 -05002519 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 struct rt6_info *rt;
2521 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002522 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
David S. Miller38308472011-12-03 18:02:47 -05002524 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002525 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
Martin KaFai Lauad706862015-08-14 11:05:52 -07002527 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002528 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002530 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 goto out;
2532 }
2533
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002534 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002535 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002536 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002537 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002538 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002539 rt->rt6i_dst.plen = 128;
2540 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002541 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Ido Schimmel4c981e22018-01-07 12:45:04 +02002543 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002544 * do proper release of the net_device
2545 */
2546 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002547 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
David S. Miller87a11572011-12-06 17:04:13 -05002549 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2550
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551out:
David S. Miller87a11572011-12-06 17:04:13 -05002552 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553}
2554
Daniel Lezcano569d3642008-01-18 03:56:57 -08002555static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002557 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002558 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2559 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2560 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2561 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2562 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002563 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
Eric Dumazetfc66f952010-10-08 06:37:34 +00002565 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002566 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002567 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 goto out;
2569
Benjamin Thery6891a342008-03-04 13:49:47 -08002570 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002571 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002572 entries = dst_entries_get_slow(ops);
2573 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002574 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002576 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002577 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578}
2579
David Ahern8d1c8022018-04-17 17:33:26 -07002580static int ip6_convert_metrics(struct net *net, struct fib6_info *rt,
David Ahernd4ead6b2018-04-17 17:33:16 -07002581 struct fib6_config *cfg)
Florian Westphale715b6d2015-01-05 23:57:44 +01002582{
David Ahernd4ead6b2018-04-17 17:33:16 -07002583 int err = 0;
Florian Westphale715b6d2015-01-05 23:57:44 +01002584
David Ahernd4ead6b2018-04-17 17:33:16 -07002585 if (cfg->fc_mx) {
2586 rt->fib6_metrics = kzalloc(sizeof(*rt->fib6_metrics),
2587 GFP_KERNEL);
2588 if (unlikely(!rt->fib6_metrics))
2589 return -ENOMEM;
Florian Westphale715b6d2015-01-05 23:57:44 +01002590
David Ahernd4ead6b2018-04-17 17:33:16 -07002591 refcount_set(&rt->fib6_metrics->refcnt, 1);
Florian Westphale715b6d2015-01-05 23:57:44 +01002592
David Ahernd4ead6b2018-04-17 17:33:16 -07002593 err = ip_metrics_convert(net, cfg->fc_mx, cfg->fc_mx_len,
2594 rt->fib6_metrics->metrics);
Florian Westphale715b6d2015-01-05 23:57:44 +01002595 }
2596
David Ahernd4ead6b2018-04-17 17:33:16 -07002597 return err;
Florian Westphale715b6d2015-01-05 23:57:44 +01002598}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599
David Ahern8c145862016-04-24 21:26:04 -07002600static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2601 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002602 const struct in6_addr *gw_addr,
2603 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002604{
2605 struct flowi6 fl6 = {
2606 .flowi6_oif = cfg->fc_ifindex,
2607 .daddr = *gw_addr,
2608 .saddr = cfg->fc_prefsrc,
2609 };
2610 struct fib6_table *table;
2611 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002612
David Ahernf4797b32018-01-25 16:55:08 -08002613 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002614 if (!table)
2615 return NULL;
2616
2617 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2618 flags |= RT6_LOOKUP_F_HAS_SADDR;
2619
David Ahernf4797b32018-01-25 16:55:08 -08002620 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002621 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002622
2623 /* if table lookup failed, fall back to full lookup */
2624 if (rt == net->ipv6.ip6_null_entry) {
2625 ip6_rt_put(rt);
2626 rt = NULL;
2627 }
2628
2629 return rt;
2630}
2631
David Ahernfc1e64e2018-01-25 16:55:09 -08002632static int ip6_route_check_nh_onlink(struct net *net,
2633 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002634 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002635 struct netlink_ext_ack *extack)
2636{
David Ahern44750f82018-02-06 13:17:06 -08002637 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002638 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2639 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
2640 struct rt6_info *grt;
2641 int err;
2642
2643 err = 0;
2644 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2645 if (grt) {
David Ahern58e354c2018-02-06 12:14:12 -08002646 if (!grt->dst.error &&
2647 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002648 NL_SET_ERR_MSG(extack,
2649 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002650 err = -EINVAL;
2651 }
2652
2653 ip6_rt_put(grt);
2654 }
2655
2656 return err;
2657}
2658
David Ahern1edce992018-01-25 16:55:07 -08002659static int ip6_route_check_nh(struct net *net,
2660 struct fib6_config *cfg,
2661 struct net_device **_dev,
2662 struct inet6_dev **idev)
2663{
2664 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2665 struct net_device *dev = _dev ? *_dev : NULL;
2666 struct rt6_info *grt = NULL;
2667 int err = -EHOSTUNREACH;
2668
2669 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002670 int flags = RT6_LOOKUP_F_IFACE;
2671
2672 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2673 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002674 if (grt) {
2675 if (grt->rt6i_flags & RTF_GATEWAY ||
2676 (dev && dev != grt->dst.dev)) {
2677 ip6_rt_put(grt);
2678 grt = NULL;
2679 }
2680 }
2681 }
2682
2683 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002684 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002685
2686 if (!grt)
2687 goto out;
2688
2689 if (dev) {
2690 if (dev != grt->dst.dev) {
2691 ip6_rt_put(grt);
2692 goto out;
2693 }
2694 } else {
2695 *_dev = dev = grt->dst.dev;
2696 *idev = grt->rt6i_idev;
2697 dev_hold(dev);
2698 in6_dev_hold(grt->rt6i_idev);
2699 }
2700
2701 if (!(grt->rt6i_flags & RTF_GATEWAY))
2702 err = 0;
2703
2704 ip6_rt_put(grt);
2705
2706out:
2707 return err;
2708}
2709
David Ahern9fbb7042018-03-13 08:29:36 -07002710static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2711 struct net_device **_dev, struct inet6_dev **idev,
2712 struct netlink_ext_ack *extack)
2713{
2714 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2715 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002716 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002717 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002718 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002719 int err = -EINVAL;
2720
2721 /* if gw_addr is local we will fail to detect this in case
2722 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2723 * will return already-added prefix route via interface that
2724 * prefix route was assigned to, which might be non-loopback.
2725 */
David Ahern232378e2018-03-13 08:29:37 -07002726 if (dev &&
2727 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2728 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002729 goto out;
2730 }
2731
2732 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2733 /* IPv6 strictly inhibits using not link-local
2734 * addresses as nexthop address.
2735 * Otherwise, router will not able to send redirects.
2736 * It is very good, but in some (rare!) circumstances
2737 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2738 * some exceptions. --ANK
2739 * We allow IPv4-mapped nexthops to support RFC4798-type
2740 * addressing
2741 */
2742 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2743 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2744 goto out;
2745 }
2746
2747 if (cfg->fc_flags & RTNH_F_ONLINK)
2748 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2749 else
2750 err = ip6_route_check_nh(net, cfg, _dev, idev);
2751
2752 if (err)
2753 goto out;
2754 }
2755
2756 /* reload in case device was changed */
2757 dev = *_dev;
2758
2759 err = -EINVAL;
2760 if (!dev) {
2761 NL_SET_ERR_MSG(extack, "Egress device not specified");
2762 goto out;
2763 } else if (dev->flags & IFF_LOOPBACK) {
2764 NL_SET_ERR_MSG(extack,
2765 "Egress device can not be loopback device for this route");
2766 goto out;
2767 }
David Ahern232378e2018-03-13 08:29:37 -07002768
2769 /* if we did not check gw_addr above, do so now that the
2770 * egress device has been resolved.
2771 */
2772 if (need_addr_check &&
2773 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2774 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2775 goto out;
2776 }
2777
David Ahern9fbb7042018-03-13 08:29:36 -07002778 err = 0;
2779out:
2780 return err;
2781}
2782
David Ahern8d1c8022018-04-17 17:33:26 -07002783static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07002784 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06002785 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786{
Daniel Lezcano55786892008-03-04 13:47:47 -08002787 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07002788 struct fib6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 struct net_device *dev = NULL;
2790 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002791 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002793 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
David Ahern557c44b2017-04-19 14:19:43 -07002795 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002796 if (cfg->fc_flags & RTF_PCPU) {
2797 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002798 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002799 }
David Ahern557c44b2017-04-19 14:19:43 -07002800
Wei Wang2ea23522017-10-27 17:30:12 -07002801 /* RTF_CACHE is an internal flag; can not be set by userspace */
2802 if (cfg->fc_flags & RTF_CACHE) {
2803 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2804 goto out;
2805 }
2806
David Aherne8478e82018-04-17 17:33:13 -07002807 if (cfg->fc_type > RTN_MAX) {
2808 NL_SET_ERR_MSG(extack, "Invalid route type");
2809 goto out;
2810 }
2811
David Ahernd5d531c2017-05-21 10:12:05 -06002812 if (cfg->fc_dst_len > 128) {
2813 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002814 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002815 }
2816 if (cfg->fc_src_len > 128) {
2817 NL_SET_ERR_MSG(extack, "Invalid source address length");
2818 goto out;
2819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002821 if (cfg->fc_src_len) {
2822 NL_SET_ERR_MSG(extack,
2823 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002824 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002827 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002829 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 if (!dev)
2831 goto out;
2832 idev = in6_dev_get(dev);
2833 if (!idev)
2834 goto out;
2835 }
2836
Thomas Graf86872cb2006-08-22 00:01:08 -07002837 if (cfg->fc_metric == 0)
2838 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
David Ahernfc1e64e2018-01-25 16:55:09 -08002840 if (cfg->fc_flags & RTNH_F_ONLINK) {
2841 if (!dev) {
2842 NL_SET_ERR_MSG(extack,
2843 "Nexthop device required for onlink");
2844 err = -ENODEV;
2845 goto out;
2846 }
2847
2848 if (!(dev->flags & IFF_UP)) {
2849 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2850 err = -ENETDOWN;
2851 goto out;
2852 }
2853 }
2854
Matti Vaittinend71314b2011-11-14 00:14:49 +00002855 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002856 if (cfg->fc_nlinfo.nlh &&
2857 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00002858 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002859 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00002860 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00002861 table = fib6_new_table(net, cfg->fc_table);
2862 }
2863 } else {
2864 table = fib6_new_table(net, cfg->fc_table);
2865 }
David S. Miller38308472011-12-03 18:02:47 -05002866
2867 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002868 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07002869
David Ahern93531c62018-04-17 17:33:25 -07002870 err = -ENOMEM;
2871 rt = fib6_info_alloc(gfp_flags);
2872 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 goto out;
David Ahern93531c62018-04-17 17:33:25 -07002874
2875 if (cfg->fc_flags & RTF_ADDRCONF)
2876 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
David Ahernd4ead6b2018-04-17 17:33:16 -07002878 err = ip6_convert_metrics(net, rt, cfg);
2879 if (err < 0)
2880 goto out;
2881
Gao feng1716a962012-04-06 00:13:10 +00002882 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07002883 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00002884 clock_t_to_jiffies(cfg->fc_expires));
2885 else
David Ahern14895682018-04-17 17:33:17 -07002886 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
Thomas Graf86872cb2006-08-22 00:01:08 -07002888 if (cfg->fc_protocol == RTPROT_UNSPEC)
2889 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07002890 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07002891
2892 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002894 if (cfg->fc_encap) {
2895 struct lwtunnel_state *lwtstate;
2896
David Ahern30357d72017-01-30 12:07:37 -08002897 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07002898 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06002899 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002900 if (err)
2901 goto out;
David Ahern5e670d82018-04-17 17:33:14 -07002902 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002903 }
2904
David Ahern93c2fb22018-04-18 15:38:59 -07002905 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
2906 rt->fib6_dst.plen = cfg->fc_dst_len;
2907 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07002908 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01002909
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07002911 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
2912 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913#endif
2914
David Ahern93c2fb22018-04-18 15:38:59 -07002915 rt->fib6_metric = cfg->fc_metric;
David Ahern5e670d82018-04-17 17:33:14 -07002916 rt->fib6_nh.nh_weight = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
David Aherne8478e82018-04-17 17:33:13 -07002918 rt->fib6_type = cfg->fc_type;
2919
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 /* We cannot add true routes via loopback here,
2921 they would result in kernel looping; promote them to reject routes
2922 */
Thomas Graf86872cb2006-08-22 00:01:08 -07002923 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05002924 (dev && (dev->flags & IFF_LOOPBACK) &&
2925 !(addr_type & IPV6_ADDR_LOOPBACK) &&
2926 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08002928 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 if (dev) {
2930 dev_put(dev);
2931 in6_dev_put(idev);
2932 }
Daniel Lezcano55786892008-03-04 13:47:47 -08002933 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 dev_hold(dev);
2935 idev = in6_dev_get(dev);
2936 if (!idev) {
2937 err = -ENODEV;
2938 goto out;
2939 }
2940 }
David Ahern93c2fb22018-04-18 15:38:59 -07002941 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 goto install_route;
2943 }
2944
Thomas Graf86872cb2006-08-22 00:01:08 -07002945 if (cfg->fc_flags & RTF_GATEWAY) {
David Ahern9fbb7042018-03-13 08:29:36 -07002946 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
2947 if (err)
Florian Westphal48ed7b22015-05-21 00:25:41 +02002948 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
David Ahern93531c62018-04-17 17:33:25 -07002950 rt->fib6_nh.nh_gw = cfg->fc_gateway;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 }
2952
2953 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002954 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 goto out;
2956
Lorenzo Bianconi428604f2018-03-29 11:02:24 +02002957 if (idev->cnf.disable_ipv6) {
2958 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
2959 err = -EACCES;
2960 goto out;
2961 }
2962
David Ahern955ec4c2018-01-24 19:45:29 -08002963 if (!(dev->flags & IFF_UP)) {
2964 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2965 err = -ENETDOWN;
2966 goto out;
2967 }
2968
Daniel Walterc3968a82011-04-13 21:10:57 +00002969 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2970 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06002971 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00002972 err = -EINVAL;
2973 goto out;
2974 }
David Ahern93c2fb22018-04-18 15:38:59 -07002975 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
2976 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00002977 } else
David Ahern93c2fb22018-04-18 15:38:59 -07002978 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00002979
David Ahern93c2fb22018-04-18 15:38:59 -07002980 rt->fib6_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
2982install_route:
David Ahern93c2fb22018-04-18 15:38:59 -07002983 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
Ido Schimmel5609b802018-01-07 12:45:06 +02002984 !netif_carrier_ok(dev))
David Ahern5e670d82018-04-17 17:33:14 -07002985 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
2986 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
David Ahern93531c62018-04-17 17:33:25 -07002987 rt->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07002988 rt->fib6_idev = idev;
2989 rt->fib6_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002990
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002991 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002992
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002993 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994out:
2995 if (dev)
2996 dev_put(dev);
2997 if (idev)
2998 in6_dev_put(idev);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002999
David Ahern93531c62018-04-17 17:33:25 -07003000 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003001 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003002}
3003
David Ahernacb54e32018-04-17 17:33:22 -07003004int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
3005 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003006{
David Ahern8d1c8022018-04-17 17:33:26 -07003007 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003008 int err;
3009
David Ahernacb54e32018-04-17 17:33:22 -07003010 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003011 if (IS_ERR(rt))
3012 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003013
David Ahernd4ead6b2018-04-17 17:33:16 -07003014 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003015 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003016
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 return err;
3018}
3019
David Ahern8d1c8022018-04-17 17:33:26 -07003020static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021{
David Ahernafb1d4b52018-04-17 17:33:11 -07003022 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003023 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003024 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
David Ahern421842e2018-04-17 17:33:18 -07003026 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003027 err = -ENOENT;
3028 goto out;
3029 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003030
David Ahern93c2fb22018-04-18 15:38:59 -07003031 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003032 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003033 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003034 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035
Gao feng6825a262012-09-19 19:25:34 +00003036out:
David Ahern93531c62018-04-17 17:33:25 -07003037 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return err;
3039}
3040
David Ahern8d1c8022018-04-17 17:33:26 -07003041int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003042{
David Ahernafb1d4b52018-04-17 17:33:11 -07003043 struct nl_info info = { .nl_net = net };
3044
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003045 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003046}
3047
David Ahern8d1c8022018-04-17 17:33:26 -07003048static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003049{
3050 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003051 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003052 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003053 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003054 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003055
David Ahern421842e2018-04-17 17:33:18 -07003056 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003057 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003058 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003059 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003060
David Ahern93c2fb22018-04-18 15:38:59 -07003061 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003062 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003063
David Ahern16a16cd2017-02-02 12:37:11 -08003064 /* prefer to send a single notification with all hops */
3065 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3066 if (skb) {
3067 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3068
David Ahernd4ead6b2018-04-17 17:33:16 -07003069 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003070 NULL, NULL, 0, RTM_DELROUTE,
3071 info->portid, seq, 0) < 0) {
3072 kfree_skb(skb);
3073 skb = NULL;
3074 } else
3075 info->skip_notify = 1;
3076 }
3077
David Ahern0ae81332017-02-02 12:37:08 -08003078 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003079 &rt->fib6_siblings,
3080 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003081 err = fib6_del(sibling, info);
3082 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003083 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003084 }
3085 }
3086
3087 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003088out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003089 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003090out_put:
David Ahern93531c62018-04-17 17:33:25 -07003091 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003092
3093 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003094 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003095 info->nlh, gfp_any());
3096 }
David Ahern0ae81332017-02-02 12:37:08 -08003097 return err;
3098}
3099
David Ahern23fb93a2018-04-17 17:33:23 -07003100static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3101{
3102 int rc = -ESRCH;
3103
3104 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3105 goto out;
3106
3107 if (cfg->fc_flags & RTF_GATEWAY &&
3108 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3109 goto out;
3110 if (dst_hold_safe(&rt->dst))
3111 rc = rt6_remove_exception_rt(rt);
3112out:
3113 return rc;
3114}
3115
David Ahern333c4302017-05-21 10:12:04 -06003116static int ip6_route_del(struct fib6_config *cfg,
3117 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118{
David Ahern8d1c8022018-04-17 17:33:26 -07003119 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003120 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003121 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 int err = -ESRCH;
3124
Daniel Lezcano55786892008-03-04 13:47:47 -08003125 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003126 if (!table) {
3127 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003128 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130
Wei Wang66f5d6c2017-10-06 12:06:10 -07003131 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003132
3133 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003134 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003135 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003136 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003137
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003139 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003140 if (cfg->fc_flags & RTF_CACHE) {
David Ahern23fb93a2018-04-17 17:33:23 -07003141 int rc;
3142
Wei Wang2b760fc2017-10-06 12:06:03 -07003143 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
3144 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003145 if (rt_cache) {
3146 rc = ip6_del_cached_rt(rt_cache, cfg);
3147 if (rc != -ESRCH)
3148 return rc;
3149 }
3150 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003151 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003152 if (cfg->fc_ifindex &&
David Ahern5e670d82018-04-17 17:33:14 -07003153 (!rt->fib6_nh.nh_dev ||
3154 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003156 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahern5e670d82018-04-17 17:33:14 -07003157 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003159 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003161 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003162 continue;
David Ahern93531c62018-04-17 17:33:25 -07003163 fib6_info_hold(rt);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003164 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
David Ahern0ae81332017-02-02 12:37:08 -08003166 /* if gateway was specified only delete the one hop */
3167 if (cfg->fc_flags & RTF_GATEWAY)
3168 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3169
3170 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 }
3172 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003173 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
3175 return err;
3176}
3177
David S. Miller6700c272012-07-17 03:29:28 -07003178static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003179{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003180 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003181 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003182 struct ndisc_options ndopts;
3183 struct inet6_dev *in6_dev;
3184 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003185 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003186 int optlen, on_link;
3187 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003188
Simon Horman29a3cad2013-05-28 20:34:26 +00003189 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003190 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003191
3192 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003193 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003194 return;
3195 }
3196
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003197 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003198
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003199 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003200 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003201 return;
3202 }
3203
David S. Miller6e157b62012-07-12 00:05:02 -07003204 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003205 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003206 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003207 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003208 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003209 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003210 return;
3211 }
3212
3213 in6_dev = __in6_dev_get(skb->dev);
3214 if (!in6_dev)
3215 return;
3216 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3217 return;
3218
3219 /* RFC2461 8.1:
3220 * The IP source address of the Redirect MUST be the same as the current
3221 * first-hop router for the specified ICMP Destination Address.
3222 */
3223
Alexander Aringf997c552016-06-15 21:20:23 +02003224 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003225 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3226 return;
3227 }
David S. Miller6e157b62012-07-12 00:05:02 -07003228
3229 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003230 if (ndopts.nd_opts_tgt_lladdr) {
3231 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3232 skb->dev);
3233 if (!lladdr) {
3234 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3235 return;
3236 }
3237 }
3238
David S. Miller6e157b62012-07-12 00:05:02 -07003239 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003240 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003241 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3242 return;
3243 }
3244
3245 /* Redirect received -> path was valid.
3246 * Look, redirects are sent only in response to data packets,
3247 * so that this nexthop apparently is reachable. --ANK
3248 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003249 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003250
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003251 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003252 if (!neigh)
3253 return;
3254
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 /*
3256 * We have finally decided to accept it.
3257 */
3258
Alexander Aringf997c552016-06-15 21:20:23 +02003259 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3261 NEIGH_UPDATE_F_OVERRIDE|
3262 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003263 NEIGH_UPDATE_F_ISROUTER)),
3264 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
David Ahern23fb93a2018-04-17 17:33:23 -07003266 nrt = ip6_rt_cache_alloc(rt->from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003267 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 goto out;
3269
3270 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3271 if (on_link)
3272 nrt->rt6i_flags &= ~RTF_GATEWAY;
3273
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003274 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275
Wei Wang2b760fc2017-10-06 12:06:03 -07003276 /* No need to remove rt from the exception table if rt is
3277 * a cached route because rt6_insert_exception() will
3278 * takes care of it
3279 */
David Ahernd4ead6b2018-04-17 17:33:16 -07003280 if (rt6_insert_exception(nrt, rt->from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003281 dst_release_immediate(&nrt->dst);
3282 goto out;
3283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
Changli Gaod8d1f302010-06-10 23:31:35 -07003285 netevent.old = &rt->dst;
3286 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003287 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003288 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003289 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3290
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291out:
David S. Millere8599ff2012-07-11 23:43:53 -07003292 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003293}
3294
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003295#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003296static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003297 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003298 const struct in6_addr *gwaddr,
3299 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003300{
David Ahern830218c2016-10-24 10:52:35 -07003301 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3302 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003303 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003304 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003305 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003306
David Ahern830218c2016-10-24 10:52:35 -07003307 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003308 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003309 return NULL;
3310
Wei Wang66f5d6c2017-10-06 12:06:10 -07003311 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003312 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003313 if (!fn)
3314 goto out;
3315
Wei Wang66f5d6c2017-10-06 12:06:10 -07003316 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07003317 if (rt->fib6_nh.nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003318 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003319 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003320 continue;
David Ahern5e670d82018-04-17 17:33:14 -07003321 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003322 continue;
David Ahern8d1c8022018-04-17 17:33:26 -07003323 fib6_info_hold(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003324 break;
3325 }
3326out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003327 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003328 return rt;
3329}
3330
David Ahern8d1c8022018-04-17 17:33:26 -07003331static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003332 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003333 const struct in6_addr *gwaddr,
3334 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003335 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003336{
Thomas Graf86872cb2006-08-22 00:01:08 -07003337 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003338 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003339 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003340 .fc_dst_len = prefixlen,
3341 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3342 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003343 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003344 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003345 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003346 .fc_nlinfo.nlh = NULL,
3347 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003348 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003349
David Ahern830218c2016-10-24 10:52:35 -07003350 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003351 cfg.fc_dst = *prefix;
3352 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003353
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003354 /* We should treat it as a default route if prefix length is 0. */
3355 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003356 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003357
David Ahernacb54e32018-04-17 17:33:22 -07003358 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003359
David Ahern830218c2016-10-24 10:52:35 -07003360 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003361}
3362#endif
3363
David Ahern8d1c8022018-04-17 17:33:26 -07003364struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003365 const struct in6_addr *addr,
3366 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003367{
David Ahern830218c2016-10-24 10:52:35 -07003368 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003369 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003370 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
David Ahernafb1d4b52018-04-17 17:33:11 -07003372 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003373 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003374 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375
Wei Wang66f5d6c2017-10-06 12:06:10 -07003376 rcu_read_lock();
3377 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern5e670d82018-04-17 17:33:14 -07003378 if (dev == rt->fib6_nh.nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003379 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahern5e670d82018-04-17 17:33:14 -07003380 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 break;
3382 }
3383 if (rt)
David Ahern8d1c8022018-04-17 17:33:26 -07003384 fib6_info_hold(rt);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003385 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return rt;
3387}
3388
David Ahern8d1c8022018-04-17 17:33:26 -07003389struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003390 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003391 struct net_device *dev,
3392 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393{
Thomas Graf86872cb2006-08-22 00:01:08 -07003394 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003395 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003396 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003397 .fc_ifindex = dev->ifindex,
3398 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3399 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003400 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003401 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003402 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003403 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003404 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003405 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003407 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
David Ahernacb54e32018-04-17 17:33:22 -07003409 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003410 struct fib6_table *table;
3411
3412 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3413 if (table)
3414 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416
David Ahernafb1d4b52018-04-17 17:33:11 -07003417 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418}
3419
David Ahernafb1d4b52018-04-17 17:33:11 -07003420static void __rt6_purge_dflt_routers(struct net *net,
3421 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422{
David Ahern8d1c8022018-04-17 17:33:26 -07003423 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
3425restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003426 rcu_read_lock();
3427 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern93c2fb22018-04-18 15:38:59 -07003428 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
3429 (!rt->fib6_idev || rt->fib6_idev->cnf.accept_ra != 2)) {
David Ahern93531c62018-04-17 17:33:25 -07003430 fib6_info_hold(rt);
3431 rcu_read_unlock();
3432 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 goto restart;
3434 }
3435 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003436 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003437
3438 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3439}
3440
3441void rt6_purge_dflt_routers(struct net *net)
3442{
3443 struct fib6_table *table;
3444 struct hlist_head *head;
3445 unsigned int h;
3446
3447 rcu_read_lock();
3448
3449 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3450 head = &net->ipv6.fib_table_hash[h];
3451 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3452 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003453 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003454 }
3455 }
3456
3457 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458}
3459
Daniel Lezcano55786892008-03-04 13:47:47 -08003460static void rtmsg_to_fib6_config(struct net *net,
3461 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003462 struct fib6_config *cfg)
3463{
3464 memset(cfg, 0, sizeof(*cfg));
3465
David Ahernca254492015-10-12 11:47:10 -07003466 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3467 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07003468 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
3469 cfg->fc_metric = rtmsg->rtmsg_metric;
3470 cfg->fc_expires = rtmsg->rtmsg_info;
3471 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
3472 cfg->fc_src_len = rtmsg->rtmsg_src_len;
3473 cfg->fc_flags = rtmsg->rtmsg_flags;
David Aherne8478e82018-04-17 17:33:13 -07003474 cfg->fc_type = rtmsg->rtmsg_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07003475
Daniel Lezcano55786892008-03-04 13:47:47 -08003476 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08003477
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003478 cfg->fc_dst = rtmsg->rtmsg_dst;
3479 cfg->fc_src = rtmsg->rtmsg_src;
3480 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07003481}
3482
Daniel Lezcano55786892008-03-04 13:47:47 -08003483int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484{
Thomas Graf86872cb2006-08-22 00:01:08 -07003485 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 struct in6_rtmsg rtmsg;
3487 int err;
3488
Ian Morris67ba4152014-08-24 21:53:10 +01003489 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 case SIOCADDRT: /* Add a route */
3491 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003492 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 return -EPERM;
3494 err = copy_from_user(&rtmsg, arg,
3495 sizeof(struct in6_rtmsg));
3496 if (err)
3497 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003498
Daniel Lezcano55786892008-03-04 13:47:47 -08003499 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003500
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 rtnl_lock();
3502 switch (cmd) {
3503 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003504 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 break;
3506 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003507 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 break;
3509 default:
3510 err = -EINVAL;
3511 }
3512 rtnl_unlock();
3513
3514 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
3517 return -EINVAL;
3518}
3519
3520/*
3521 * Drop the packet on the floor
3522 */
3523
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003524static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003526 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003527 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003528 switch (ipstats_mib_noroutes) {
3529 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003530 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003531 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003532 IP6_INC_STATS(dev_net(dst->dev),
3533 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003534 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003535 break;
3536 }
3537 /* FALLTHROUGH */
3538 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003539 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3540 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003541 break;
3542 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003543 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 kfree_skb(skb);
3545 return 0;
3546}
3547
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003548static int ip6_pkt_discard(struct sk_buff *skb)
3549{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003550 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003551}
3552
Eric W. Biedermanede20592015-10-07 16:48:47 -05003553static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554{
Eric Dumazetadf30902009-06-02 05:19:30 +00003555 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003556 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557}
3558
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003559static int ip6_pkt_prohibit(struct sk_buff *skb)
3560{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003561 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003562}
3563
Eric W. Biedermanede20592015-10-07 16:48:47 -05003564static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003565{
Eric Dumazetadf30902009-06-02 05:19:30 +00003566 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003567 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003568}
3569
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570/*
3571 * Allocate a dst for local (unicast / anycast) address.
3572 */
3573
David Ahern360a9882018-04-18 15:39:00 -07003574struct fib6_info *addrconf_f6i_alloc(struct net *net,
3575 struct inet6_dev *idev,
3576 const struct in6_addr *addr,
3577 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578{
David Ahernca254492015-10-12 11:47:10 -07003579 u32 tb_id;
David Ahern4832c302017-08-17 12:17:20 -07003580 struct net_device *dev = idev->dev;
David Ahern360a9882018-04-18 15:39:00 -07003581 struct fib6_info *f6i;
David Ahern5f02ce242016-09-10 12:09:54 -07003582
David Ahern360a9882018-04-18 15:39:00 -07003583 f6i = fib6_info_alloc(gfp_flags);
3584 if (!f6i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 return ERR_PTR(-ENOMEM);
3586
David Ahern360a9882018-04-18 15:39:00 -07003587 f6i->dst_nocount = true;
David Ahern3b6761d2018-04-17 17:33:20 -07003588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 in6_dev_hold(idev);
David Ahern360a9882018-04-18 15:39:00 -07003590 f6i->fib6_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
David Ahern360a9882018-04-18 15:39:00 -07003592 f6i->dst_host = true;
3593 f6i->fib6_protocol = RTPROT_KERNEL;
3594 f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
David Aherne8478e82018-04-17 17:33:13 -07003595 if (anycast) {
David Ahern360a9882018-04-18 15:39:00 -07003596 f6i->fib6_type = RTN_ANYCAST;
3597 f6i->fib6_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003598 } else {
David Ahern360a9882018-04-18 15:39:00 -07003599 f6i->fib6_type = RTN_LOCAL;
3600 f6i->fib6_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
David Ahern360a9882018-04-18 15:39:00 -07003603 f6i->fib6_nh.nh_gw = *addr;
David Ahern93531c62018-04-17 17:33:25 -07003604 dev_hold(dev);
David Ahern360a9882018-04-18 15:39:00 -07003605 f6i->fib6_nh.nh_dev = dev;
3606 f6i->fib6_dst.addr = *addr;
3607 f6i->fib6_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003608 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
David Ahern360a9882018-04-18 15:39:00 -07003609 f6i->fib6_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610
David Ahern360a9882018-04-18 15:39:00 -07003611 return f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612}
3613
Daniel Walterc3968a82011-04-13 21:10:57 +00003614/* remove deleted ip from prefsrc entries */
3615struct arg_dev_net_ip {
3616 struct net_device *dev;
3617 struct net *net;
3618 struct in6_addr *addr;
3619};
3620
David Ahern8d1c8022018-04-17 17:33:26 -07003621static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003622{
3623 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3624 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3625 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3626
David Ahern5e670d82018-04-17 17:33:14 -07003627 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003628 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003629 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003630 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003631 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003632 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003633 /* need to update cache as well */
3634 rt6_exceptions_remove_prefsrc(rt);
3635 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003636 }
3637 return 0;
3638}
3639
3640void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3641{
3642 struct net *net = dev_net(ifp->idev->dev);
3643 struct arg_dev_net_ip adni = {
3644 .dev = ifp->idev->dev,
3645 .net = net,
3646 .addr = &ifp->addr,
3647 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003648 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003649}
3650
Duan Jiongbe7a0102014-05-15 15:56:14 +08003651#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003652
3653/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003654static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003655{
3656 struct in6_addr *gateway = (struct in6_addr *)arg;
3657
David Ahern93c2fb22018-04-18 15:38:59 -07003658 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahern5e670d82018-04-17 17:33:14 -07003659 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003660 return -1;
3661 }
Wei Wangb16cb452017-10-06 12:06:00 -07003662
3663 /* Further clean up cached routes in exception table.
3664 * This is needed because cached route may have a different
3665 * gateway than its 'parent' in the case of an ip redirect.
3666 */
3667 rt6_exceptions_clean_tohost(rt, gateway);
3668
Duan Jiongbe7a0102014-05-15 15:56:14 +08003669 return 0;
3670}
3671
3672void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3673{
3674 fib6_clean_all(net, fib6_clean_tohost, gateway);
3675}
3676
Ido Schimmel2127d952018-01-07 12:45:03 +02003677struct arg_netdev_event {
3678 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003679 union {
3680 unsigned int nh_flags;
3681 unsigned long event;
3682 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003683};
3684
David Ahern8d1c8022018-04-17 17:33:26 -07003685static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003686{
David Ahern8d1c8022018-04-17 17:33:26 -07003687 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003688 struct fib6_node *fn;
3689
David Ahern93c2fb22018-04-18 15:38:59 -07003690 fn = rcu_dereference_protected(rt->fib6_node,
3691 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003692 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003693 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003694 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003695 if (iter->fib6_metric == rt->fib6_metric &&
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003696 rt6_qualify_for_ecmp(iter))
3697 return iter;
3698 iter = rcu_dereference_protected(iter->rt6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003699 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003700 }
3701
3702 return NULL;
3703}
3704
David Ahern8d1c8022018-04-17 17:33:26 -07003705static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003706{
David Ahern5e670d82018-04-17 17:33:14 -07003707 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
3708 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Ahern93c2fb22018-04-18 15:38:59 -07003709 rt->fib6_idev->cnf.ignore_routes_with_linkdown))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003710 return true;
3711
3712 return false;
3713}
3714
David Ahern8d1c8022018-04-17 17:33:26 -07003715static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003716{
David Ahern8d1c8022018-04-17 17:33:26 -07003717 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003718 int total = 0;
3719
3720 if (!rt6_is_dead(rt))
David Ahern5e670d82018-04-17 17:33:14 -07003721 total += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003722
David Ahern93c2fb22018-04-18 15:38:59 -07003723 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003724 if (!rt6_is_dead(iter))
David Ahern5e670d82018-04-17 17:33:14 -07003725 total += iter->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003726 }
3727
3728 return total;
3729}
3730
David Ahern8d1c8022018-04-17 17:33:26 -07003731static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003732{
3733 int upper_bound = -1;
3734
3735 if (!rt6_is_dead(rt)) {
David Ahern5e670d82018-04-17 17:33:14 -07003736 *weight += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003737 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3738 total) - 1;
3739 }
David Ahern5e670d82018-04-17 17:33:14 -07003740 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003741}
3742
David Ahern8d1c8022018-04-17 17:33:26 -07003743static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003744{
David Ahern8d1c8022018-04-17 17:33:26 -07003745 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003746 int weight = 0;
3747
3748 rt6_upper_bound_set(rt, &weight, total);
3749
David Ahern93c2fb22018-04-18 15:38:59 -07003750 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003751 rt6_upper_bound_set(iter, &weight, total);
3752}
3753
David Ahern8d1c8022018-04-17 17:33:26 -07003754void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003755{
David Ahern8d1c8022018-04-17 17:33:26 -07003756 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003757 int total;
3758
3759 /* In case the entire multipath route was marked for flushing,
3760 * then there is no need to rebalance upon the removal of every
3761 * sibling route.
3762 */
David Ahern93c2fb22018-04-18 15:38:59 -07003763 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003764 return;
3765
3766 /* During lookup routes are evaluated in order, so we need to
3767 * make sure upper bounds are assigned from the first sibling
3768 * onwards.
3769 */
3770 first = rt6_multipath_first_sibling(rt);
3771 if (WARN_ON_ONCE(!first))
3772 return;
3773
3774 total = rt6_multipath_total_weight(first);
3775 rt6_multipath_upper_bound_set(first, total);
3776}
3777
David Ahern8d1c8022018-04-17 17:33:26 -07003778static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003779{
3780 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003781 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003782
David Ahern421842e2018-04-17 17:33:18 -07003783 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
David Ahern5e670d82018-04-17 17:33:14 -07003784 rt->fib6_nh.nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003785 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003786 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003787 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003788
3789 return 0;
3790}
3791
3792void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3793{
3794 struct arg_netdev_event arg = {
3795 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003796 {
3797 .nh_flags = nh_flags,
3798 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003799 };
3800
3801 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3802 arg.nh_flags |= RTNH_F_LINKDOWN;
3803
3804 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3805}
3806
David Ahern8d1c8022018-04-17 17:33:26 -07003807static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003808 const struct net_device *dev)
3809{
David Ahern8d1c8022018-04-17 17:33:26 -07003810 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003811
David Ahern5e670d82018-04-17 17:33:14 -07003812 if (rt->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003813 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07003814 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003815 if (iter->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003816 return true;
3817
3818 return false;
3819}
3820
David Ahern8d1c8022018-04-17 17:33:26 -07003821static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003822{
David Ahern8d1c8022018-04-17 17:33:26 -07003823 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003824
3825 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07003826 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003827 iter->should_flush = 1;
3828}
3829
David Ahern8d1c8022018-04-17 17:33:26 -07003830static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003831 const struct net_device *down_dev)
3832{
David Ahern8d1c8022018-04-17 17:33:26 -07003833 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003834 unsigned int dead = 0;
3835
David Ahern5e670d82018-04-17 17:33:14 -07003836 if (rt->fib6_nh.nh_dev == down_dev ||
3837 rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003838 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07003839 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003840 if (iter->fib6_nh.nh_dev == down_dev ||
3841 iter->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003842 dead++;
3843
3844 return dead;
3845}
3846
David Ahern8d1c8022018-04-17 17:33:26 -07003847static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003848 const struct net_device *dev,
3849 unsigned int nh_flags)
3850{
David Ahern8d1c8022018-04-17 17:33:26 -07003851 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003852
David Ahern5e670d82018-04-17 17:33:14 -07003853 if (rt->fib6_nh.nh_dev == dev)
3854 rt->fib6_nh.nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07003855 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003856 if (iter->fib6_nh.nh_dev == dev)
3857 iter->fib6_nh.nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003858}
3859
David Aherna1a22c12017-01-18 07:40:36 -08003860/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07003861static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862{
Ido Schimmel4c981e22018-01-07 12:45:04 +02003863 const struct arg_netdev_event *arg = p_arg;
3864 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07003865 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003866
David Ahern421842e2018-04-17 17:33:18 -07003867 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003868 return 0;
3869
3870 switch (arg->event) {
3871 case NETDEV_UNREGISTER:
David Ahern5e670d82018-04-17 17:33:14 -07003872 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003873 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02003874 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003875 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07003876 if (!rt->fib6_nsiblings)
David Ahern5e670d82018-04-17 17:33:14 -07003877 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003878 if (rt6_multipath_uses_dev(rt, dev)) {
3879 unsigned int count;
3880
3881 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07003882 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02003883 rt6_multipath_flush(rt);
3884 return -1;
3885 }
3886 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
3887 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07003888 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003889 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003890 }
3891 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003892 case NETDEV_CHANGE:
David Ahern5e670d82018-04-17 17:33:14 -07003893 if (rt->fib6_nh.nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07003894 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003895 break;
David Ahern5e670d82018-04-17 17:33:14 -07003896 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003897 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003898 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02003899 }
David S. Millerc159d302011-12-26 15:24:36 -05003900
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 return 0;
3902}
3903
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003904void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905{
Ido Schimmel4c981e22018-01-07 12:45:04 +02003906 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003907 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003908 {
3909 .event = event,
3910 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003911 };
3912
Ido Schimmel4c981e22018-01-07 12:45:04 +02003913 fib6_clean_all(dev_net(dev), fib6_ifdown, &arg);
3914}
3915
3916void rt6_disable_ip(struct net_device *dev, unsigned long event)
3917{
3918 rt6_sync_down_dev(dev, event);
3919 rt6_uncached_list_flush_dev(dev_net(dev), dev);
3920 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921}
3922
Eric Dumazet95c96172012-04-15 05:58:06 +00003923struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00003925 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926};
3927
David Ahern8d1c8022018-04-17 17:33:26 -07003928static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929{
3930 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
3931 struct inet6_dev *idev;
3932
3933 /* In IPv6 pmtu discovery is not optional,
3934 so that RTAX_MTU lock cannot disable it.
3935 We still use this lock to block changes
3936 caused by addrconf/ndisc.
3937 */
3938
3939 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05003940 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 return 0;
3942
3943 /* For administrative MTU increase, there is no way to discover
3944 IPv6 PMTU increase, so PMTU increase should be updated here.
3945 Since RFC 1981 doesn't include administrative MTU increase
3946 update PMTU increase is a MUST. (i.e. jumbo frame)
3947 */
David Ahern5e670d82018-04-17 17:33:14 -07003948 if (rt->fib6_nh.nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07003949 !fib6_metric_locked(rt, RTAX_MTU)) {
3950 u32 mtu = rt->fib6_pmtu;
3951
3952 if (mtu >= arg->mtu ||
3953 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
3954 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
3955
Wei Wangf5bbe7e2017-10-06 12:05:59 -07003956 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01003957 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07003958 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07003959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 return 0;
3961}
3962
Eric Dumazet95c96172012-04-15 05:58:06 +00003963void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964{
Thomas Grafc71099a2006-08-04 23:20:06 -07003965 struct rt6_mtu_change_arg arg = {
3966 .dev = dev,
3967 .mtu = mtu,
3968 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969
Li RongQing0c3584d2013-12-27 16:32:38 +08003970 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971}
3972
Patrick McHardyef7c79e2007-06-05 12:38:30 -07003973static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07003974 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07003975 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07003976 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07003977 [RTA_PRIORITY] = { .type = NLA_U32 },
3978 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003979 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003980 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003981 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
3982 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08003983 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09003984 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08003985 [RTA_MARK] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07003986};
3987
3988static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06003989 struct fib6_config *cfg,
3990 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991{
Thomas Graf86872cb2006-08-22 00:01:08 -07003992 struct rtmsg *rtm;
3993 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003994 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07003995 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996
Johannes Bergfceb6432017-04-12 14:34:07 +02003997 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
3998 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07003999 if (err < 0)
4000 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001
Thomas Graf86872cb2006-08-22 00:01:08 -07004002 err = -EINVAL;
4003 rtm = nlmsg_data(nlh);
4004 memset(cfg, 0, sizeof(*cfg));
4005
4006 cfg->fc_table = rtm->rtm_table;
4007 cfg->fc_dst_len = rtm->rtm_dst_len;
4008 cfg->fc_src_len = rtm->rtm_src_len;
4009 cfg->fc_flags = RTF_UP;
4010 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004011 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07004012
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004013 if (rtm->rtm_type == RTN_UNREACHABLE ||
4014 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004015 rtm->rtm_type == RTN_PROHIBIT ||
4016 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004017 cfg->fc_flags |= RTF_REJECT;
4018
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004019 if (rtm->rtm_type == RTN_LOCAL)
4020 cfg->fc_flags |= RTF_LOCAL;
4021
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004022 if (rtm->rtm_flags & RTM_F_CLONED)
4023 cfg->fc_flags |= RTF_CACHE;
4024
David Ahernfc1e64e2018-01-25 16:55:09 -08004025 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4026
Eric W. Biederman15e47302012-09-07 20:12:54 +00004027 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07004028 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004029 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07004030
4031 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004032 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004033 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004035
4036 if (tb[RTA_DST]) {
4037 int plen = (rtm->rtm_dst_len + 7) >> 3;
4038
4039 if (nla_len(tb[RTA_DST]) < plen)
4040 goto errout;
4041
4042 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004044
4045 if (tb[RTA_SRC]) {
4046 int plen = (rtm->rtm_src_len + 7) >> 3;
4047
4048 if (nla_len(tb[RTA_SRC]) < plen)
4049 goto errout;
4050
4051 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004053
Daniel Walterc3968a82011-04-13 21:10:57 +00004054 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004055 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004056
Thomas Graf86872cb2006-08-22 00:01:08 -07004057 if (tb[RTA_OIF])
4058 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4059
4060 if (tb[RTA_PRIORITY])
4061 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4062
4063 if (tb[RTA_METRICS]) {
4064 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4065 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004067
4068 if (tb[RTA_TABLE])
4069 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4070
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004071 if (tb[RTA_MULTIPATH]) {
4072 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4073 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004074
4075 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004076 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004077 if (err < 0)
4078 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004079 }
4080
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004081 if (tb[RTA_PREF]) {
4082 pref = nla_get_u8(tb[RTA_PREF]);
4083 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4084 pref != ICMPV6_ROUTER_PREF_HIGH)
4085 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4086 cfg->fc_flags |= RTF_PREF(pref);
4087 }
4088
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004089 if (tb[RTA_ENCAP])
4090 cfg->fc_encap = tb[RTA_ENCAP];
4091
David Ahern9ed59592017-01-17 14:57:36 -08004092 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004093 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4094
David Ahernc255bd62017-05-27 16:19:27 -06004095 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004096 if (err < 0)
4097 goto errout;
4098 }
4099
Xin Long32bc2012015-12-16 17:50:11 +08004100 if (tb[RTA_EXPIRES]) {
4101 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4102
4103 if (addrconf_finite_timeout(timeout)) {
4104 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4105 cfg->fc_flags |= RTF_EXPIRES;
4106 }
4107 }
4108
Thomas Graf86872cb2006-08-22 00:01:08 -07004109 err = 0;
4110errout:
4111 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112}
4113
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004114struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004115 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004116 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004117 struct list_head next;
4118};
4119
4120static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
4121{
4122 struct rt6_nh *nh;
4123
4124 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08004125 pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6c nexthop %pI6c ifi %d\n",
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004126 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
4127 nh->r_cfg.fc_ifindex);
4128 }
4129}
4130
David Ahernd4ead6b2018-04-17 17:33:16 -07004131static int ip6_route_info_append(struct net *net,
4132 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004133 struct fib6_info *rt,
4134 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004135{
4136 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004137 int err = -EEXIST;
4138
4139 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004140 /* check if fib6_info already exists */
4141 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004142 return err;
4143 }
4144
4145 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4146 if (!nh)
4147 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004148 nh->fib6_info = rt;
David Ahernd4ead6b2018-04-17 17:33:16 -07004149 err = ip6_convert_metrics(net, rt, r_cfg);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004150 if (err) {
4151 kfree(nh);
4152 return err;
4153 }
4154 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4155 list_add_tail(&nh->next, rt6_nh_list);
4156
4157 return 0;
4158}
4159
David Ahern8d1c8022018-04-17 17:33:26 -07004160static void ip6_route_mpath_notify(struct fib6_info *rt,
4161 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004162 struct nl_info *info,
4163 __u16 nlflags)
4164{
4165 /* if this is an APPEND route, then rt points to the first route
4166 * inserted and rt_last points to last route inserted. Userspace
4167 * wants a consistent dump of the route which starts at the first
4168 * nexthop. Since sibling routes are always added at the end of
4169 * the list, find the first sibling of the last route appended
4170 */
David Ahern93c2fb22018-04-18 15:38:59 -07004171 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4172 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004173 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004174 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004175 }
4176
4177 if (rt)
4178 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4179}
4180
David Ahern333c4302017-05-21 10:12:04 -06004181static int ip6_route_multipath_add(struct fib6_config *cfg,
4182 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004183{
David Ahern8d1c8022018-04-17 17:33:26 -07004184 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004185 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004186 struct fib6_config r_cfg;
4187 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004188 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004189 struct rt6_nh *err_nh;
4190 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004191 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004192 int remaining;
4193 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004194 int err = 1;
4195 int nhn = 0;
4196 int replace = (cfg->fc_nlinfo.nlh &&
4197 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4198 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004199
David Ahern3b1137f2017-02-02 12:37:10 -08004200 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4201 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4202 nlflags |= NLM_F_APPEND;
4203
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004204 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004205 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004206
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004207 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004208 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004209 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004210 while (rtnh_ok(rtnh, remaining)) {
4211 memcpy(&r_cfg, cfg, sizeof(*cfg));
4212 if (rtnh->rtnh_ifindex)
4213 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4214
4215 attrlen = rtnh_attrlen(rtnh);
4216 if (attrlen > 0) {
4217 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4218
4219 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4220 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004221 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004222 r_cfg.fc_flags |= RTF_GATEWAY;
4223 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004224 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4225 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4226 if (nla)
4227 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004228 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004229
David Ahern68e2ffd2018-03-20 10:06:59 -07004230 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004231 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004232 if (IS_ERR(rt)) {
4233 err = PTR_ERR(rt);
4234 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004235 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004236 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004237
David Ahern5e670d82018-04-17 17:33:14 -07004238 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004239
David Ahernd4ead6b2018-04-17 17:33:16 -07004240 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4241 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004242 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004243 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004244 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004245 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004246
4247 rtnh = rtnh_next(rtnh, &remaining);
4248 }
4249
David Ahern3b1137f2017-02-02 12:37:10 -08004250 /* for add and replace send one notification with all nexthops.
4251 * Skip the notification in fib6_add_rt2node and send one with
4252 * the full route when done
4253 */
4254 info->skip_notify = 1;
4255
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004256 err_nh = NULL;
4257 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004258 rt_last = nh->fib6_info;
4259 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4260 fib6_info_release(nh->fib6_info);
David Ahern93531c62018-04-17 17:33:25 -07004261
David Ahern3b1137f2017-02-02 12:37:10 -08004262 /* save reference to first route for notification */
4263 if (!rt_notif && !err)
David Ahern8d1c8022018-04-17 17:33:26 -07004264 rt_notif = nh->fib6_info;
David Ahern3b1137f2017-02-02 12:37:10 -08004265
David Ahern8d1c8022018-04-17 17:33:26 -07004266 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4267 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004268 if (err) {
4269 if (replace && nhn)
4270 ip6_print_replace_route_err(&rt6_nh_list);
4271 err_nh = nh;
4272 goto add_errout;
4273 }
4274
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004275 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004276 * these flags after the first nexthop: if there is a collision,
4277 * we have already failed to add the first nexthop:
4278 * fib6_add_rt2node() has rejected it; when replacing, old
4279 * nexthops have been replaced by first new, the rest should
4280 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004281 */
Michal Kubeček27596472015-05-18 20:54:00 +02004282 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4283 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004284 nhn++;
4285 }
4286
David Ahern3b1137f2017-02-02 12:37:10 -08004287 /* success ... tell user about new route */
4288 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004289 goto cleanup;
4290
4291add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004292 /* send notification for routes that were added so that
4293 * the delete notifications sent by ip6_route_del are
4294 * coherent
4295 */
4296 if (rt_notif)
4297 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4298
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004299 /* Delete routes that were already added */
4300 list_for_each_entry(nh, &rt6_nh_list, next) {
4301 if (err_nh == nh)
4302 break;
David Ahern333c4302017-05-21 10:12:04 -06004303 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004304 }
4305
4306cleanup:
4307 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004308 if (nh->fib6_info)
4309 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004310 list_del(&nh->next);
4311 kfree(nh);
4312 }
4313
4314 return err;
4315}
4316
David Ahern333c4302017-05-21 10:12:04 -06004317static int ip6_route_multipath_del(struct fib6_config *cfg,
4318 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004319{
4320 struct fib6_config r_cfg;
4321 struct rtnexthop *rtnh;
4322 int remaining;
4323 int attrlen;
4324 int err = 1, last_err = 0;
4325
4326 remaining = cfg->fc_mp_len;
4327 rtnh = (struct rtnexthop *)cfg->fc_mp;
4328
4329 /* Parse a Multipath Entry */
4330 while (rtnh_ok(rtnh, remaining)) {
4331 memcpy(&r_cfg, cfg, sizeof(*cfg));
4332 if (rtnh->rtnh_ifindex)
4333 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4334
4335 attrlen = rtnh_attrlen(rtnh);
4336 if (attrlen > 0) {
4337 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4338
4339 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4340 if (nla) {
4341 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4342 r_cfg.fc_flags |= RTF_GATEWAY;
4343 }
4344 }
David Ahern333c4302017-05-21 10:12:04 -06004345 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004346 if (err)
4347 last_err = err;
4348
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004349 rtnh = rtnh_next(rtnh, &remaining);
4350 }
4351
4352 return last_err;
4353}
4354
David Ahernc21ef3e2017-04-16 09:48:24 -07004355static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4356 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357{
Thomas Graf86872cb2006-08-22 00:01:08 -07004358 struct fib6_config cfg;
4359 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
David Ahern333c4302017-05-21 10:12:04 -06004361 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004362 if (err < 0)
4363 return err;
4364
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004365 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004366 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004367 else {
4368 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004369 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371}
4372
David Ahernc21ef3e2017-04-16 09:48:24 -07004373static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4374 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375{
Thomas Graf86872cb2006-08-22 00:01:08 -07004376 struct fib6_config cfg;
4377 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
David Ahern333c4302017-05-21 10:12:04 -06004379 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004380 if (err < 0)
4381 return err;
4382
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004383 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004384 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004385 else
David Ahernacb54e32018-04-17 17:33:22 -07004386 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387}
4388
David Ahern8d1c8022018-04-17 17:33:26 -07004389static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004390{
David Ahernbeb1afac52017-02-02 12:37:09 -08004391 int nexthop_len = 0;
4392
David Ahern93c2fb22018-04-18 15:38:59 -07004393 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004394 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4395 + NLA_ALIGN(sizeof(struct rtnexthop))
4396 + nla_total_size(16) /* RTA_GATEWAY */
David Ahern5e670d82018-04-17 17:33:14 -07004397 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
David Ahernbeb1afac52017-02-02 12:37:09 -08004398
David Ahern93c2fb22018-04-18 15:38:59 -07004399 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004400 }
4401
Thomas Graf339bf982006-11-10 14:10:15 -08004402 return NLMSG_ALIGN(sizeof(struct rtmsg))
4403 + nla_total_size(16) /* RTA_SRC */
4404 + nla_total_size(16) /* RTA_DST */
4405 + nla_total_size(16) /* RTA_GATEWAY */
4406 + nla_total_size(16) /* RTA_PREFSRC */
4407 + nla_total_size(4) /* RTA_TABLE */
4408 + nla_total_size(4) /* RTA_IIF */
4409 + nla_total_size(4) /* RTA_OIF */
4410 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004411 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004412 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004413 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004414 + nla_total_size(1) /* RTA_PREF */
David Ahern5e670d82018-04-17 17:33:14 -07004415 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate)
David Ahernbeb1afac52017-02-02 12:37:09 -08004416 + nexthop_len;
4417}
4418
David Ahern8d1c8022018-04-17 17:33:26 -07004419static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004420 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004421{
David Ahern5e670d82018-04-17 17:33:14 -07004422 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004423 *flags |= RTNH_F_DEAD;
4424
David Ahern5e670d82018-04-17 17:33:14 -07004425 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004426 *flags |= RTNH_F_LINKDOWN;
David Ahern93c2fb22018-04-18 15:38:59 -07004427 if (rt->fib6_idev->cnf.ignore_routes_with_linkdown)
David Ahernbeb1afac52017-02-02 12:37:09 -08004428 *flags |= RTNH_F_DEAD;
4429 }
4430
David Ahern93c2fb22018-04-18 15:38:59 -07004431 if (rt->fib6_flags & RTF_GATEWAY) {
David Ahern5e670d82018-04-17 17:33:14 -07004432 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004433 goto nla_put_failure;
4434 }
4435
David Ahern5e670d82018-04-17 17:33:14 -07004436 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK);
4437 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004438 *flags |= RTNH_F_OFFLOAD;
4439
David Ahern5be083c2017-03-06 15:57:31 -08004440 /* not needed for multipath encoding b/c it has a rtnexthop struct */
David Ahern5e670d82018-04-17 17:33:14 -07004441 if (!skip_oif && rt->fib6_nh.nh_dev &&
4442 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex))
David Ahernbeb1afac52017-02-02 12:37:09 -08004443 goto nla_put_failure;
4444
David Ahern5e670d82018-04-17 17:33:14 -07004445 if (rt->fib6_nh.nh_lwtstate &&
4446 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004447 goto nla_put_failure;
4448
4449 return 0;
4450
4451nla_put_failure:
4452 return -EMSGSIZE;
4453}
4454
David Ahern5be083c2017-03-06 15:57:31 -08004455/* add multipath next hop */
David Ahern8d1c8022018-04-17 17:33:26 -07004456static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt)
David Ahernbeb1afac52017-02-02 12:37:09 -08004457{
David Ahern5e670d82018-04-17 17:33:14 -07004458 const struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernbeb1afac52017-02-02 12:37:09 -08004459 struct rtnexthop *rtnh;
4460 unsigned int flags = 0;
4461
4462 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4463 if (!rtnh)
4464 goto nla_put_failure;
4465
David Ahern5e670d82018-04-17 17:33:14 -07004466 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1;
4467 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
David Ahernbeb1afac52017-02-02 12:37:09 -08004468
David Ahern5be083c2017-03-06 15:57:31 -08004469 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004470 goto nla_put_failure;
4471
4472 rtnh->rtnh_flags = flags;
4473
4474 /* length of rtnetlink header + attributes */
4475 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4476
4477 return 0;
4478
4479nla_put_failure:
4480 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004481}
4482
David Ahernd4ead6b2018-04-17 17:33:16 -07004483static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004484 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004485 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004486 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004487 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488{
4489 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004490 struct nlmsghdr *nlh;
David Ahernd4ead6b2018-04-17 17:33:16 -07004491 long expires = 0;
4492 u32 *pmetrics;
Patrick McHardy9e762a42006-08-10 23:09:48 -07004493 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Eric W. Biederman15e47302012-09-07 20:12:54 +00004495 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004496 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004497 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004498
4499 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 rtm->rtm_family = AF_INET6;
David Ahern93c2fb22018-04-18 15:38:59 -07004501 rtm->rtm_dst_len = rt->fib6_dst.plen;
4502 rtm->rtm_src_len = rt->fib6_src.plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004504 if (rt->fib6_table)
4505 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004506 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004507 table = RT6_TABLE_UNSPEC;
4508 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04004509 if (nla_put_u32(skb, RTA_TABLE, table))
4510 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004511
4512 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 rtm->rtm_flags = 0;
4514 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004515 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
David Ahern93c2fb22018-04-18 15:38:59 -07004517 if (rt->fib6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 rtm->rtm_flags |= RTM_F_CLONED;
4519
David Ahernd4ead6b2018-04-17 17:33:16 -07004520 if (dest) {
4521 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004522 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004523 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 } else if (rtm->rtm_dst_len)
David Ahern93c2fb22018-04-18 15:38:59 -07004525 if (nla_put_in6_addr(skb, RTA_DST, &rt->fib6_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004526 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527#ifdef CONFIG_IPV6_SUBTREES
4528 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004529 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004530 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004531 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004532 } else if (rtm->rtm_src_len &&
David Ahern93c2fb22018-04-18 15:38:59 -07004533 nla_put_in6_addr(skb, RTA_SRC, &rt->fib6_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004534 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004536 if (iif) {
4537#ifdef CONFIG_IPV6_MROUTE
David Ahern93c2fb22018-04-18 15:38:59 -07004538 if (ipv6_addr_is_multicast(&rt->fib6_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004539 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004540
David Ahernfd61c6b2017-01-17 15:51:07 -08004541 if (err == 0)
4542 return 0;
4543 if (err < 0)
4544 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004545 } else
4546#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004547 if (nla_put_u32(skb, RTA_IIF, iif))
4548 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004549 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004551 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004552 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004553 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004555
David Ahern93c2fb22018-04-18 15:38:59 -07004556 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004557 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004558 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004559 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004560 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004561 }
4562
David Ahernd4ead6b2018-04-17 17:33:16 -07004563 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4564 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004565 goto nla_put_failure;
4566
David Ahern93c2fb22018-04-18 15:38:59 -07004567 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004568 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004569
David Ahernbeb1afac52017-02-02 12:37:09 -08004570 /* For multipath routes, walk the siblings list and add
4571 * each as a nexthop within RTA_MULTIPATH.
4572 */
David Ahern93c2fb22018-04-18 15:38:59 -07004573 if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004574 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004575 struct nlattr *mp;
4576
4577 mp = nla_nest_start(skb, RTA_MULTIPATH);
4578 if (!mp)
4579 goto nla_put_failure;
4580
4581 if (rt6_add_nexthop(skb, rt) < 0)
4582 goto nla_put_failure;
4583
4584 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004585 &rt->fib6_siblings, fib6_siblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004586 if (rt6_add_nexthop(skb, sibling) < 0)
4587 goto nla_put_failure;
4588 }
4589
4590 nla_nest_end(skb, mp);
4591 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004592 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004593 goto nla_put_failure;
4594 }
4595
David Ahern93c2fb22018-04-18 15:38:59 -07004596 if (rt->fib6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004597 expires = dst ? dst->expires : rt->expires;
4598 expires -= jiffies;
4599 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004600
David Ahernd4ead6b2018-04-17 17:33:16 -07004601 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004602 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603
David Ahern93c2fb22018-04-18 15:38:59 -07004604 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->fib6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004605 goto nla_put_failure;
4606
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004607
Johannes Berg053c0952015-01-16 22:09:00 +01004608 nlmsg_end(skb, nlh);
4609 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004610
4611nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004612 nlmsg_cancel(skb, nlh);
4613 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614}
4615
David Ahern8d1c8022018-04-17 17:33:26 -07004616int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617{
4618 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08004619 struct net *net = arg->net;
4620
David Ahern421842e2018-04-17 17:33:18 -07004621 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004622 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
Thomas Graf2d7202b2006-08-22 00:01:27 -07004624 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
4625 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08004626
4627 /* user wants prefix routes only */
4628 if (rtm->rtm_flags & RTM_F_PREFIX &&
David Ahern93c2fb22018-04-18 15:38:59 -07004629 !(rt->fib6_flags & RTF_PREFIX_RT)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004630 /* success since this is not a prefix route */
4631 return 1;
4632 }
4633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
David Ahernd4ead6b2018-04-17 17:33:16 -07004635 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4636 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
4637 arg->cb->nlh->nlmsg_seq, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638}
4639
David Ahernc21ef3e2017-04-16 09:48:24 -07004640static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4641 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004643 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004644 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004645 int err, iif = 0, oif = 0;
4646 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004648 struct sk_buff *skb;
4649 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05004650 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004651 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004652
Johannes Bergfceb6432017-04-12 14:34:07 +02004653 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07004654 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004655 if (err < 0)
4656 goto errout;
4657
4658 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05004659 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004660 rtm = nlmsg_data(nlh);
4661 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004662 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004663
4664 if (tb[RTA_SRC]) {
4665 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4666 goto errout;
4667
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004668 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004669 }
4670
4671 if (tb[RTA_DST]) {
4672 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4673 goto errout;
4674
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004675 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004676 }
4677
4678 if (tb[RTA_IIF])
4679 iif = nla_get_u32(tb[RTA_IIF]);
4680
4681 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004682 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004683
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004684 if (tb[RTA_MARK])
4685 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4686
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004687 if (tb[RTA_UID])
4688 fl6.flowi6_uid = make_kuid(current_user_ns(),
4689 nla_get_u32(tb[RTA_UID]));
4690 else
4691 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4692
Thomas Grafab364a62006-08-22 00:01:47 -07004693 if (iif) {
4694 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004695 int flags = 0;
4696
Florian Westphal121622d2017-08-15 16:34:42 +02004697 rcu_read_lock();
4698
4699 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004700 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004701 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004702 err = -ENODEV;
4703 goto errout;
4704 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004705
4706 fl6.flowi6_iif = iif;
4707
4708 if (!ipv6_addr_any(&fl6.saddr))
4709 flags |= RT6_LOOKUP_F_HAS_SADDR;
4710
David Ahernb75cc8f2018-03-02 08:32:17 -08004711 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004712
4713 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004714 } else {
4715 fl6.flowi6_oif = oif;
4716
Ido Schimmel58acfd72017-12-20 12:28:25 +02004717 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004718 }
4719
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004720
4721 rt = container_of(dst, struct rt6_info, dst);
4722 if (rt->dst.error) {
4723 err = rt->dst.error;
4724 ip6_rt_put(rt);
4725 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727
WANG Cong9d6acb32017-03-01 20:48:39 -08004728 if (rt == net->ipv6.ip6_null_entry) {
4729 err = rt->dst.error;
4730 ip6_rt_put(rt);
4731 goto errout;
4732 }
4733
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004735 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004736 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07004737 err = -ENOBUFS;
4738 goto errout;
4739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740
Changli Gaod8d1f302010-06-10 23:31:35 -07004741 skb_dst_set(skb, &rt->dst);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004742 if (fibmatch)
David Ahern93531c62018-04-17 17:33:25 -07004743 err = rt6_fill_node(net, skb, rt->from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004744 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
4745 nlh->nlmsg_seq, 0);
4746 else
David Ahern93531c62018-04-17 17:33:25 -07004747 err = rt6_fill_node(net, skb, rt->from, dst,
4748 &fl6.daddr, &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07004749 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
4750 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07004752 kfree_skb(skb);
4753 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 }
4755
Eric W. Biederman15e47302012-09-07 20:12:54 +00004756 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07004757errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759}
4760
David Ahern8d1c8022018-04-17 17:33:26 -07004761void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07004762 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
4764 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08004765 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004766 u32 seq;
4767 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004769 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05004770 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07004771
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004772 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05004773 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07004774 goto errout;
4775
David Ahernd4ead6b2018-04-17 17:33:16 -07004776 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
4777 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08004778 if (err < 0) {
4779 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
4780 WARN_ON(err == -EMSGSIZE);
4781 kfree_skb(skb);
4782 goto errout;
4783 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00004784 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08004785 info->nlh, gfp_any());
4786 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07004787errout:
4788 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08004789 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790}
4791
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004792static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00004793 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004794{
Jiri Pirko351638e2013-05-28 01:30:21 +00004795 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09004796 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004797
WANG Cong242d3a42017-05-08 10:12:13 -07004798 if (!(dev->flags & IFF_LOOPBACK))
4799 return NOTIFY_OK;
4800
4801 if (event == NETDEV_REGISTER) {
David Ahern421842e2018-04-17 17:33:18 -07004802 net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07004803 net->ipv6.fib6_null_entry->fib6_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07004804 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004805 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
4806#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07004807 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004808 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07004809 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004810 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
4811#endif
WANG Cong76da0702017-06-20 11:42:27 -07004812 } else if (event == NETDEV_UNREGISTER &&
4813 dev->reg_state != NETREG_UNREGISTERED) {
4814 /* NETDEV_UNREGISTER could be fired for multiple times by
4815 * netdev_wait_allrefs(). Make sure we only call this once.
4816 */
David Ahern93c2fb22018-04-18 15:38:59 -07004817 in6_dev_put_clear(&net->ipv6.fib6_null_entry->fib6_idev);
Eric Dumazet12d94a82017-08-15 04:09:51 -07004818 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07004819#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07004820 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
4821 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07004822#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004823 }
4824
4825 return NOTIFY_OK;
4826}
4827
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828/*
4829 * /proc
4830 */
4831
4832#ifdef CONFIG_PROC_FS
4833
Alexey Dobriyan33120b32007-11-06 05:27:11 -08004834static const struct file_operations ipv6_route_proc_fops = {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08004835 .open = ipv6_route_open,
4836 .read = seq_read,
4837 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02004838 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08004839};
4840
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841static int rt6_stats_seq_show(struct seq_file *seq, void *v)
4842{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004843 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004845 net->ipv6.rt6_stats->fib_nodes,
4846 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07004847 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004848 net->ipv6.rt6_stats->fib_rt_entries,
4849 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00004850 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004851 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
4853 return 0;
4854}
4855
4856static int rt6_stats_seq_open(struct inode *inode, struct file *file)
4857{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07004858 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004859}
4860
Arjan van de Ven9a321442007-02-12 00:55:35 -08004861static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 .open = rt6_stats_seq_open,
4863 .read = seq_read,
4864 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07004865 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866};
4867#endif /* CONFIG_PROC_FS */
4868
4869#ifdef CONFIG_SYSCTL
4870
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871static
Joe Perchesfe2c6332013-06-11 23:04:25 -07004872int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 void __user *buffer, size_t *lenp, loff_t *ppos)
4874{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004875 struct net *net;
4876 int delay;
4877 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004879
4880 net = (struct net *)ctl->extra1;
4881 delay = net->ipv6.sysctl.flush_delay;
4882 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02004883 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004884 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885}
4886
Joe Perchesfe2c6332013-06-11 23:04:25 -07004887struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004888 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08004890 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07004892 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004893 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 },
4895 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004897 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 .maxlen = sizeof(int),
4899 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004900 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 },
4902 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08004904 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 .maxlen = sizeof(int),
4906 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004907 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 },
4909 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08004911 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 .maxlen = sizeof(int),
4913 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004914 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 },
4916 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08004918 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 .maxlen = sizeof(int),
4920 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004921 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 },
4923 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08004925 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 .maxlen = sizeof(int),
4927 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004928 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 },
4930 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08004932 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 .maxlen = sizeof(int),
4934 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07004935 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 },
4937 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08004939 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 .maxlen = sizeof(int),
4941 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004942 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 },
4944 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08004946 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 .maxlen = sizeof(int),
4948 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07004949 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 },
4951 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08004953 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 .maxlen = sizeof(int),
4955 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004956 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08004958 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959};
4960
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004961struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08004962{
4963 struct ctl_table *table;
4964
4965 table = kmemdup(ipv6_route_table_template,
4966 sizeof(ipv6_route_table_template),
4967 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09004968
4969 if (table) {
4970 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004971 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00004972 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09004973 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
4974 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
4975 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
4976 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
4977 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
4978 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
4979 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08004980 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00004981
4982 /* Don't export sysctls to unprivileged users */
4983 if (net->user_ns != &init_user_ns)
4984 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09004985 }
4986
Daniel Lezcano760f2d02008-01-10 02:53:43 -08004987 return table;
4988}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989#endif
4990
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004991static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004992{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07004993 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004994
Alexey Dobriyan86393e52009-08-29 01:34:49 +00004995 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
4996 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004997
Eric Dumazetfc66f952010-10-08 06:37:34 +00004998 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
4999 goto out_ip6_dst_ops;
5000
David Ahern421842e2018-04-17 17:33:18 -07005001 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5002 sizeof(*net->ipv6.fib6_null_entry),
5003 GFP_KERNEL);
5004 if (!net->ipv6.fib6_null_entry)
5005 goto out_ip6_dst_entries;
5006
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005007 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5008 sizeof(*net->ipv6.ip6_null_entry),
5009 GFP_KERNEL);
5010 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005011 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005012 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005013 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5014 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005015
5016#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005017 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005018 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5019 sizeof(*net->ipv6.ip6_prohibit_entry),
5020 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005021 if (!net->ipv6.ip6_prohibit_entry)
5022 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005023 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005024 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5025 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005026
5027 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5028 sizeof(*net->ipv6.ip6_blk_hole_entry),
5029 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005030 if (!net->ipv6.ip6_blk_hole_entry)
5031 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005032 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005033 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5034 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005035#endif
5036
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005037 net->ipv6.sysctl.flush_delay = 0;
5038 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5039 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5040 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5041 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5042 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5043 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5044 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
5045
Benjamin Thery6891a342008-03-04 13:49:47 -08005046 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5047
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005048 ret = 0;
5049out:
5050 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005051
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005052#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5053out_ip6_prohibit_entry:
5054 kfree(net->ipv6.ip6_prohibit_entry);
5055out_ip6_null_entry:
5056 kfree(net->ipv6.ip6_null_entry);
5057#endif
David Ahern421842e2018-04-17 17:33:18 -07005058out_fib6_null_entry:
5059 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005060out_ip6_dst_entries:
5061 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005062out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005063 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005064}
5065
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005066static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005067{
David Ahern421842e2018-04-17 17:33:18 -07005068 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005069 kfree(net->ipv6.ip6_null_entry);
5070#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5071 kfree(net->ipv6.ip6_prohibit_entry);
5072 kfree(net->ipv6.ip6_blk_hole_entry);
5073#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005074 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005075}
5076
Thomas Grafd1896342012-06-18 12:08:33 +00005077static int __net_init ip6_route_net_init_late(struct net *net)
5078{
5079#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00005080 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
Joe Perchesd6444062018-03-23 15:54:38 -07005081 proc_create("rt6_stats", 0444, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00005082#endif
5083 return 0;
5084}
5085
5086static void __net_exit ip6_route_net_exit_late(struct net *net)
5087{
5088#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005089 remove_proc_entry("ipv6_route", net->proc_net);
5090 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005091#endif
5092}
5093
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005094static struct pernet_operations ip6_route_net_ops = {
5095 .init = ip6_route_net_init,
5096 .exit = ip6_route_net_exit,
5097};
5098
David S. Millerc3426b42012-06-09 16:27:05 -07005099static int __net_init ipv6_inetpeer_init(struct net *net)
5100{
5101 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5102
5103 if (!bp)
5104 return -ENOMEM;
5105 inet_peer_base_init(bp);
5106 net->ipv6.peers = bp;
5107 return 0;
5108}
5109
5110static void __net_exit ipv6_inetpeer_exit(struct net *net)
5111{
5112 struct inet_peer_base *bp = net->ipv6.peers;
5113
5114 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005115 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005116 kfree(bp);
5117}
5118
David S. Miller2b823f72012-06-09 19:00:16 -07005119static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005120 .init = ipv6_inetpeer_init,
5121 .exit = ipv6_inetpeer_exit,
5122};
5123
Thomas Grafd1896342012-06-18 12:08:33 +00005124static struct pernet_operations ip6_route_net_late_ops = {
5125 .init = ip6_route_net_init_late,
5126 .exit = ip6_route_net_exit_late,
5127};
5128
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005129static struct notifier_block ip6_route_dev_notifier = {
5130 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005131 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005132};
5133
WANG Cong2f460932017-05-03 22:07:31 -07005134void __init ip6_route_init_special_entries(void)
5135{
5136 /* Registering of the loopback is done before this portion of code,
5137 * the loopback reference in rt6_info will not be taken, do it
5138 * manually for init_net */
David Ahern421842e2018-04-17 17:33:18 -07005139 init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
David Ahern93c2fb22018-04-18 15:38:59 -07005140 init_net.ipv6.fib6_null_entry->fib6_idev = in6_dev_get(init_net.loopback_dev);
WANG Cong2f460932017-05-03 22:07:31 -07005141 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5142 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5143 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5144 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5145 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5146 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5147 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5148 #endif
5149}
5150
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005151int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005153 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005154 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005155
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005156 ret = -ENOMEM;
5157 ip6_dst_ops_template.kmem_cachep =
5158 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5159 SLAB_HWCACHE_ALIGN, NULL);
5160 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005161 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005162
Eric Dumazetfc66f952010-10-08 06:37:34 +00005163 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005164 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005165 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005166
David S. Millerc3426b42012-06-09 16:27:05 -07005167 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5168 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005169 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005170
David S. Miller7e52b332012-06-15 15:51:55 -07005171 ret = register_pernet_subsys(&ip6_route_net_ops);
5172 if (ret)
5173 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005174
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005175 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5176
David S. Millere8803b62012-06-16 01:12:19 -07005177 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005178 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005179 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005180
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005181 ret = xfrm6_init();
5182 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005183 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005184
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005185 ret = fib6_rules_init();
5186 if (ret)
5187 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005188
Thomas Grafd1896342012-06-18 12:08:33 +00005189 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5190 if (ret)
5191 goto fib6_rules_init;
5192
Florian Westphal16feebc2017-12-02 21:44:08 +01005193 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5194 inet6_rtm_newroute, NULL, 0);
5195 if (ret < 0)
5196 goto out_register_late_subsys;
5197
5198 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5199 inet6_rtm_delroute, NULL, 0);
5200 if (ret < 0)
5201 goto out_register_late_subsys;
5202
5203 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5204 inet6_rtm_getroute, NULL,
5205 RTNL_FLAG_DOIT_UNLOCKED);
5206 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005207 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005208
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005209 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005210 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005211 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005212
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005213 for_each_possible_cpu(cpu) {
5214 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5215
5216 INIT_LIST_HEAD(&ul->head);
5217 spin_lock_init(&ul->lock);
5218 }
5219
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005220out:
5221 return ret;
5222
Thomas Grafd1896342012-06-18 12:08:33 +00005223out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005224 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005225 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005226fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005227 fib6_rules_cleanup();
5228xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005229 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005230out_fib6_init:
5231 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005232out_register_subsys:
5233 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005234out_register_inetpeer:
5235 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005236out_dst_entries:
5237 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005238out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005239 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005240 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241}
5242
5243void ip6_route_cleanup(void)
5244{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005245 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005246 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005247 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005250 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005251 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005252 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005253 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254}