blob: f62d24948aa25427b17bba8b463891a2948ae2b5 [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
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070081static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080083static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000084static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static struct dst_entry *ip6_negative_advice(struct dst_entry *);
86static void ip6_dst_destroy(struct dst_entry *);
87static void ip6_dst_ifdown(struct dst_entry *,
88 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080089static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050092static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053093static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050094static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070096static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
97 struct sk_buff *skb, u32 mtu);
98static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
99 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700100static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200101static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
David Ahern16a16cd2017-02-02 12:37:11 -0800102static size_t rt6_nlmsg_size(struct rt6_info *rt);
103static int rt6_fill_node(struct net *net,
104 struct sk_buff *skb, struct rt6_info *rt,
105 struct in6_addr *dst, struct in6_addr *src,
106 int iif, int type, u32 portid, u32 seq,
107 unsigned int flags);
Wei Wang35732d02017-10-06 12:05:57 -0700108static struct rt6_info *rt6_find_cached_rt(struct rt6_info *rt,
109 struct in6_addr *daddr,
110 struct in6_addr *saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800112#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800113static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000114 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700115 const struct in6_addr *gwaddr,
116 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000117 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800118static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000119 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700120 const struct in6_addr *gwaddr,
121 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800122#endif
123
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700124struct uncached_list {
125 spinlock_t lock;
126 struct list_head head;
127};
128
129static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
130
131static void rt6_uncached_list_add(struct rt6_info *rt)
132{
133 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
134
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700135 rt->rt6i_uncached_list = ul;
136
137 spin_lock_bh(&ul->lock);
138 list_add_tail(&rt->rt6i_uncached, &ul->head);
139 spin_unlock_bh(&ul->lock);
140}
141
142static void rt6_uncached_list_del(struct rt6_info *rt)
143{
144 if (!list_empty(&rt->rt6i_uncached)) {
145 struct uncached_list *ul = rt->rt6i_uncached_list;
Wei Wang81eb8442017-10-06 12:06:11 -0700146 struct net *net = dev_net(rt->dst.dev);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700147
148 spin_lock_bh(&ul->lock);
149 list_del(&rt->rt6i_uncached);
Wei Wang81eb8442017-10-06 12:06:11 -0700150 atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700151 spin_unlock_bh(&ul->lock);
152 }
153}
154
155static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
156{
157 struct net_device *loopback_dev = net->loopback_dev;
158 int cpu;
159
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500160 if (dev == loopback_dev)
161 return;
162
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700163 for_each_possible_cpu(cpu) {
164 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
165 struct rt6_info *rt;
166
167 spin_lock_bh(&ul->lock);
168 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
169 struct inet6_dev *rt_idev = rt->rt6i_idev;
170 struct net_device *rt_dev = rt->dst.dev;
171
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500172 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700173 rt->rt6i_idev = in6_dev_get(loopback_dev);
174 in6_dev_put(rt_idev);
175 }
176
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500177 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700178 rt->dst.dev = loopback_dev;
179 dev_hold(rt->dst.dev);
180 dev_put(rt_dev);
181 }
182 }
183 spin_unlock_bh(&ul->lock);
184 }
185}
186
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700187static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
188{
David Miller3a2232e2017-11-28 15:40:40 -0500189 return dst_metrics_write_ptr(&rt->from->dst);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700190}
191
David S. Miller06582542011-01-27 14:58:42 -0800192static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
193{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700194 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800195
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700196 if (rt->rt6i_flags & RTF_PCPU)
197 return rt6_pcpu_cow_metrics(rt);
198 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700199 return NULL;
200 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800201 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800202}
203
David S. Millerf894cbf2012-07-02 21:52:24 -0700204static inline const void *choose_neigh_daddr(struct rt6_info *rt,
205 struct sk_buff *skb,
206 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500207{
208 struct in6_addr *p = &rt->rt6i_gateway;
209
David S. Millera7563f32012-01-26 16:29:16 -0500210 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500211 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700212 else if (skb)
213 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500214 return daddr;
215}
216
David S. Millerf894cbf2012-07-02 21:52:24 -0700217static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
218 struct sk_buff *skb,
219 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700220{
David S. Miller39232972012-01-26 15:22:32 -0500221 struct rt6_info *rt = (struct rt6_info *) dst;
222 struct neighbour *n;
223
David S. Millerf894cbf2012-07-02 21:52:24 -0700224 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000225 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500226 if (n)
227 return n;
228 return neigh_create(&nd_tbl, daddr, dst->dev);
229}
230
Julian Anastasov63fca652017-02-06 23:14:15 +0200231static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
232{
233 struct net_device *dev = dst->dev;
234 struct rt6_info *rt = (struct rt6_info *)dst;
235
236 daddr = choose_neigh_daddr(rt, NULL, daddr);
237 if (!daddr)
238 return;
239 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
240 return;
241 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
242 return;
243 __ipv6_confirm_neigh(dev, daddr);
244}
245
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800246static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 .gc = ip6_dst_gc,
249 .gc_thresh = 1024,
250 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800251 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000252 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800253 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 .destroy = ip6_dst_destroy,
255 .ifdown = ip6_dst_ifdown,
256 .negative_advice = ip6_negative_advice,
257 .link_failure = ip6_link_failure,
258 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700259 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500260 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700261 .neigh_lookup = ip6_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200262 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263};
264
Steffen Klassertebb762f2011-11-23 02:12:51 +0000265static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800266{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000267 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
268
269 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800270}
271
David S. Miller6700c272012-07-17 03:29:28 -0700272static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
273 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700274{
275}
276
David S. Miller6700c272012-07-17 03:29:28 -0700277static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
278 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700279{
280}
281
David S. Miller14e50e52007-05-24 18:17:54 -0700282static struct dst_ops ip6_dst_blackhole_ops = {
283 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700284 .destroy = ip6_dst_destroy,
285 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000286 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800287 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700288 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700289 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700290 .cow_metrics = dst_cow_metrics_generic,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700291 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700292};
293
David S. Miller62fa8a82011-01-26 20:51:05 -0800294static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800295 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800296};
297
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000298static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700299 .dst = {
300 .__refcnt = ATOMIC_INIT(1),
301 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000302 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700303 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700304 .input = ip6_pkt_discard,
305 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 },
307 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700308 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 .rt6i_metric = ~(u32) 0,
310 .rt6i_ref = ATOMIC_INIT(1),
311};
312
Thomas Graf101367c2006-08-04 03:39:02 -0700313#ifdef CONFIG_IPV6_MULTIPLE_TABLES
314
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000315static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700316 .dst = {
317 .__refcnt = ATOMIC_INIT(1),
318 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000319 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700320 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700321 .input = ip6_pkt_prohibit,
322 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700323 },
324 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700325 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700326 .rt6i_metric = ~(u32) 0,
327 .rt6i_ref = ATOMIC_INIT(1),
328};
329
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000330static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700331 .dst = {
332 .__refcnt = ATOMIC_INIT(1),
333 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000334 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700335 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700336 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500337 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700338 },
339 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700340 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700341 .rt6i_metric = ~(u32) 0,
342 .rt6i_ref = ATOMIC_INIT(1),
343};
344
345#endif
346
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700347static void rt6_info_init(struct rt6_info *rt)
348{
349 struct dst_entry *dst = &rt->dst;
350
351 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
352 INIT_LIST_HEAD(&rt->rt6i_siblings);
353 INIT_LIST_HEAD(&rt->rt6i_uncached);
354}
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700357static struct rt6_info *__ip6_dst_alloc(struct net *net,
358 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700359 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
David S. Miller97bab732012-06-09 22:36:36 -0700361 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700362 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700363
Wei Wang81eb8442017-10-06 12:06:11 -0700364 if (rt) {
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700365 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -0700366 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
367 }
Steffen Klassert81048912012-07-05 23:37:09 +0000368
David S. Millercf911662011-04-28 14:31:47 -0700369 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
David Ahern9ab179d2016-04-07 11:10:06 -0700372struct rt6_info *ip6_dst_alloc(struct net *net,
373 struct net_device *dev,
374 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700375{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700376 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700377
378 if (rt) {
379 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
Eric Dumazetbfd8e5a2017-10-09 06:01:37 -0700380 if (!rt->rt6i_pcpu) {
Wei Wang587fea72017-06-17 10:42:36 -0700381 dst_release_immediate(&rt->dst);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700382 return NULL;
383 }
384 }
385
386 return rt;
387}
David Ahern9ab179d2016-04-07 11:10:06 -0700388EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390static void ip6_dst_destroy(struct dst_entry *dst)
391{
392 struct rt6_info *rt = (struct rt6_info *)dst;
Wei Wang35732d02017-10-06 12:05:57 -0700393 struct rt6_exception_bucket *bucket;
David Miller3a2232e2017-11-28 15:40:40 -0500394 struct rt6_info *from = rt->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700395 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700397 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200398 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700399 rt6_uncached_list_del(rt);
400
401 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500402 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 rt->rt6i_idev = NULL;
404 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900405 }
Wei Wang35732d02017-10-06 12:05:57 -0700406 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, 1);
407 if (bucket) {
408 rt->rt6i_exception_bucket = NULL;
409 kfree(bucket);
410 }
Gao feng1716a962012-04-06 00:13:10 +0000411
David Miller3a2232e2017-11-28 15:40:40 -0500412 rt->from = NULL;
413 dst_release(&from->dst);
David S. Millerb3419362010-11-30 12:27:11 -0800414}
415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
417 int how)
418{
419 struct rt6_info *rt = (struct rt6_info *)dst;
420 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800421 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900422 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Wei Wange5645f52017-08-14 10:44:59 -0700424 if (idev && idev->dev != loopback_dev) {
425 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
426 if (loopback_idev) {
427 rt->rt6i_idev = loopback_idev;
428 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 }
431}
432
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800433static bool __rt6_check_expired(const struct rt6_info *rt)
434{
435 if (rt->rt6i_flags & RTF_EXPIRES)
436 return time_after(jiffies, rt->dst.expires);
437 else
438 return false;
439}
440
Eric Dumazeta50feda2012-05-18 18:57:34 +0000441static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
Gao feng1716a962012-04-06 00:13:10 +0000443 if (rt->rt6i_flags & RTF_EXPIRES) {
444 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000445 return true;
David Miller3a2232e2017-11-28 15:40:40 -0500446 } else if (rt->from) {
Xin Long1e2ea8a2017-08-26 20:10:10 +0800447 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
David Miller3a2232e2017-11-28 15:40:40 -0500448 rt6_check_expired(rt->from);
Gao feng1716a962012-04-06 00:13:10 +0000449 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000450 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451}
452
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000453static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200454 struct flowi6 *fl6, int oif,
455 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000456{
457 struct rt6_info *sibling, *next_sibling;
458 int route_choosen;
459
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200460 /* We might have already computed the hash for ICMPv6 errors. In such
461 * case it will always be non-zero. Otherwise now is the time to do it.
462 */
463 if (!fl6->mp_hash)
464 fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
465
466 route_choosen = fl6->mp_hash % (match->rt6i_nsiblings + 1);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000467 /* Don't change the route, if route_choosen == 0
468 * (siblings does not include ourself)
469 */
470 if (route_choosen)
471 list_for_each_entry_safe(sibling, next_sibling,
472 &match->rt6i_siblings, rt6i_siblings) {
473 route_choosen--;
474 if (route_choosen == 0) {
Ido Schimmelbbfcd772017-11-21 09:50:12 +0200475 struct inet6_dev *idev = sibling->rt6i_idev;
476
Ido Schimmel8067bb82018-01-07 12:45:09 +0200477 if (sibling->rt6i_nh_flags & RTNH_F_DEAD)
478 break;
Ido Schimmel14c52062018-01-07 12:45:07 +0200479 if (sibling->rt6i_nh_flags & RTNH_F_LINKDOWN &&
Ido Schimmelbbfcd772017-11-21 09:50:12 +0200480 idev->cnf.ignore_routes_with_linkdown)
481 break;
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200482 if (rt6_score_route(sibling, oif, strict) < 0)
483 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000484 match = sibling;
485 break;
486 }
487 }
488 return match;
489}
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491/*
Wei Wang66f5d6c2017-10-06 12:06:10 -0700492 * Route lookup. rcu_read_lock() should be held.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 */
494
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800495static inline struct rt6_info *rt6_device_match(struct net *net,
496 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000497 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700499 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct rt6_info *local = NULL;
502 struct rt6_info *sprt;
503
Ido Schimmel8067bb82018-01-07 12:45:09 +0200504 if (!oif && ipv6_addr_any(saddr) && !(rt->rt6i_nh_flags & RTNH_F_DEAD))
505 return rt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900506
David Miller071fb372017-11-28 15:40:15 -0500507 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) {
David S. Millerd1918542011-12-28 20:19:20 -0500508 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900509
Ido Schimmel8067bb82018-01-07 12:45:09 +0200510 if (sprt->rt6i_nh_flags & RTNH_F_DEAD)
511 continue;
512
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900513 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (dev->ifindex == oif)
515 return sprt;
516 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500517 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 sprt->rt6i_idev->dev->ifindex != oif) {
David Ahern17fb0b22015-09-25 15:22:54 -0600519 if (flags & RT6_LOOKUP_F_IFACE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 continue;
David Ahern17fb0b22015-09-25 15:22:54 -0600521 if (local &&
522 local->rt6i_idev->dev->ifindex == oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 continue;
524 }
525 local = sprt;
526 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900527 } else {
528 if (ipv6_chk_addr(net, saddr, dev,
529 flags & RT6_LOOKUP_F_IFACE))
530 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900534 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (local)
536 return local;
537
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700538 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800539 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
Ido Schimmel8067bb82018-01-07 12:45:09 +0200541
542 return rt->rt6i_nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543}
544
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800545#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200546struct __rt6_probe_work {
547 struct work_struct work;
548 struct in6_addr target;
549 struct net_device *dev;
550};
551
552static void rt6_probe_deferred(struct work_struct *w)
553{
554 struct in6_addr mcaddr;
555 struct __rt6_probe_work *work =
556 container_of(w, struct __rt6_probe_work, work);
557
558 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800559 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200560 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100561 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200562}
563
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800564static void rt6_probe(struct rt6_info *rt)
565{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700566 struct __rt6_probe_work *work;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000567 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800568 /*
569 * Okay, this does not seem to be appropriate
570 * for now, however, we need to check if it
571 * is really so; aka Router Reachability Probing.
572 *
573 * Router Reachability Probe MUST be rate-limited
574 * to no more than one per minute.
575 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000576 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000577 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000578 rcu_read_lock_bh();
579 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
580 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700581 if (neigh->nud_state & NUD_VALID)
582 goto out;
583
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700584 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000585 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700586 if (!(neigh->nud_state & NUD_VALID) &&
587 time_after(jiffies,
588 neigh->updated +
589 rt->rt6i_idev->cnf.rtr_probe_interval)) {
590 work = kmalloc(sizeof(*work), GFP_ATOMIC);
591 if (work)
592 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200593 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000594 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700595 } else {
596 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000597 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700598
599 if (work) {
600 INIT_WORK(&work->work, rt6_probe_deferred);
601 work->target = rt->rt6i_gateway;
602 dev_hold(rt->dst.dev);
603 work->dev = rt->dst.dev;
604 schedule_work(&work->work);
605 }
606
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700607out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000608 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800609}
610#else
611static inline void rt6_probe(struct rt6_info *rt)
612{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800613}
614#endif
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800617 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700619static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
David S. Millerd1918542011-12-28 20:19:20 -0500621 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700622 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800623 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700624 if ((dev->flags & IFF_LOOPBACK) &&
625 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
626 return 1;
627 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200630static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000632 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200633 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000634
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700635 if (rt->rt6i_flags & RTF_NONEXTHOP ||
636 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200637 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000638
639 rcu_read_lock_bh();
640 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
641 if (neigh) {
642 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800643 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200644 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800645#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000646 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200647 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100648 else
649 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800650#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000651 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200652 } else {
653 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100654 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000655 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000656 rcu_read_unlock_bh();
657
Paul Marksa5a81f02012-12-03 10:26:54 +0000658 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800659}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800661static int rt6_score_route(struct rt6_info *rt, int oif,
662 int strict)
663{
Paul Marksa5a81f02012-12-03 10:26:54 +0000664 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900665
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700666 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700667 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200668 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800669#ifdef CONFIG_IPV6_ROUTER_PREF
670 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
671#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200672 if (strict & RT6_LOOKUP_F_REACHABLE) {
673 int n = rt6_check_neigh(rt);
674 if (n < 0)
675 return n;
676 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800677 return m;
678}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
David S. Millerf11e6652007-03-24 20:36:25 -0700680static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200681 int *mpri, struct rt6_info *match,
682 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800683{
David S. Millerf11e6652007-03-24 20:36:25 -0700684 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200685 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400686 struct inet6_dev *idev = rt->rt6i_idev;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400687
Ido Schimmel8067bb82018-01-07 12:45:09 +0200688 if (rt->rt6i_nh_flags & RTNH_F_DEAD)
689 goto out;
690
Ido Schimmel14c52062018-01-07 12:45:07 +0200691 if (idev->cnf.ignore_routes_with_linkdown &&
692 rt->rt6i_nh_flags & RTNH_F_LINKDOWN &&
David Ahernd5d32e42016-10-24 12:27:23 -0700693 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400694 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700695
696 if (rt6_check_expired(rt))
697 goto out;
698
699 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100700 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200701 match_do_rr = true;
702 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100703 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700704 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700705 }
706
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200707 if (strict & RT6_LOOKUP_F_REACHABLE)
708 rt6_probe(rt);
709
Jiri Benc7e980562013-12-11 13:48:20 +0100710 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200711 if (m > *mpri) {
712 *do_rr = match_do_rr;
713 *mpri = m;
714 match = rt;
715 }
David S. Millerf11e6652007-03-24 20:36:25 -0700716out:
717 return match;
718}
719
720static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
Wei Wang8d1040e2017-10-06 12:06:08 -0700721 struct rt6_info *leaf,
David S. Millerf11e6652007-03-24 20:36:25 -0700722 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200723 u32 metric, int oif, int strict,
724 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700725{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700726 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800727 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
David S. Millerf11e6652007-03-24 20:36:25 -0700729 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700730 cont = NULL;
David Miller071fb372017-11-28 15:40:15 -0500731 for (rt = rr_head; rt; rt = rcu_dereference(rt->rt6_next)) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700732 if (rt->rt6i_metric != metric) {
733 cont = rt;
734 break;
735 }
736
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200737 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700738 }
739
Wei Wang66f5d6c2017-10-06 12:06:10 -0700740 for (rt = leaf; rt && rt != rr_head;
David Miller071fb372017-11-28 15:40:15 -0500741 rt = rcu_dereference(rt->rt6_next)) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700742 if (rt->rt6i_metric != metric) {
743 cont = rt;
744 break;
745 }
746
747 match = find_match(rt, oif, strict, &mpri, match, do_rr);
748 }
749
750 if (match || !cont)
751 return match;
752
David Miller071fb372017-11-28 15:40:15 -0500753 for (rt = cont; rt; rt = rcu_dereference(rt->rt6_next))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200754 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800755
David S. Millerf11e6652007-03-24 20:36:25 -0700756 return match;
757}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800758
Wei Wang8d1040e2017-10-06 12:06:08 -0700759static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn,
760 int oif, int strict)
David S. Millerf11e6652007-03-24 20:36:25 -0700761{
Wei Wang66f5d6c2017-10-06 12:06:10 -0700762 struct rt6_info *leaf = rcu_dereference(fn->leaf);
David S. Millerf11e6652007-03-24 20:36:25 -0700763 struct rt6_info *match, *rt0;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200764 bool do_rr = false;
Wei Wang17ecf592017-10-06 12:06:09 -0700765 int key_plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Wei Wang87b1af82017-10-23 14:59:35 -0700767 if (!leaf || leaf == net->ipv6.ip6_null_entry)
Wei Wang8d1040e2017-10-06 12:06:08 -0700768 return net->ipv6.ip6_null_entry;
769
Wei Wang66f5d6c2017-10-06 12:06:10 -0700770 rt0 = rcu_dereference(fn->rr_ptr);
David S. Millerf11e6652007-03-24 20:36:25 -0700771 if (!rt0)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700772 rt0 = leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Wei Wang17ecf592017-10-06 12:06:09 -0700774 /* Double check to make sure fn is not an intermediate node
775 * and fn->leaf does not points to its child's leaf
776 * (This might happen if all routes under fn are deleted from
777 * the tree and fib6_repair_tree() is called on the node.)
778 */
779 key_plen = rt0->rt6i_dst.plen;
780#ifdef CONFIG_IPV6_SUBTREES
781 if (rt0->rt6i_src.plen)
782 key_plen = rt0->rt6i_src.plen;
783#endif
784 if (fn->fn_bit != key_plen)
785 return net->ipv6.ip6_null_entry;
786
Wei Wang8d1040e2017-10-06 12:06:08 -0700787 match = find_rr_leaf(fn, leaf, rt0, rt0->rt6i_metric, oif, strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200788 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200790 if (do_rr) {
David Miller071fb372017-11-28 15:40:15 -0500791 struct rt6_info *next = rcu_dereference(rt0->rt6_next);
David S. Millerf11e6652007-03-24 20:36:25 -0700792
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800793 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700794 if (!next || next->rt6i_metric != rt0->rt6i_metric)
Wei Wang8d1040e2017-10-06 12:06:08 -0700795 next = leaf;
David S. Millerf11e6652007-03-24 20:36:25 -0700796
Wei Wang66f5d6c2017-10-06 12:06:10 -0700797 if (next != rt0) {
798 spin_lock_bh(&leaf->rt6i_table->tb6_lock);
799 /* make sure next is not being deleted from the tree */
800 if (next->rt6i_node)
801 rcu_assign_pointer(fn->rr_ptr, next);
802 spin_unlock_bh(&leaf->rt6i_table->tb6_lock);
803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
805
Eric Dumazeta02cec22010-09-22 20:43:57 +0000806 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807}
808
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700809static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
810{
811 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
812}
813
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800814#ifdef CONFIG_IPV6_ROUTE_INFO
815int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000816 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800817{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900818 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800819 struct route_info *rinfo = (struct route_info *) opt;
820 struct in6_addr prefix_buf, *prefix;
821 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900822 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800823 struct rt6_info *rt;
824
825 if (len < sizeof(struct route_info)) {
826 return -EINVAL;
827 }
828
829 /* Sanity check for prefix_len and length */
830 if (rinfo->length > 3) {
831 return -EINVAL;
832 } else if (rinfo->prefix_len > 128) {
833 return -EINVAL;
834 } else if (rinfo->prefix_len > 64) {
835 if (rinfo->length < 2) {
836 return -EINVAL;
837 }
838 } else if (rinfo->prefix_len > 0) {
839 if (rinfo->length < 1) {
840 return -EINVAL;
841 }
842 }
843
844 pref = rinfo->route_pref;
845 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000846 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800847
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900848 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800849
850 if (rinfo->length == 3)
851 prefix = (struct in6_addr *)rinfo->prefix;
852 else {
853 /* this function is safe */
854 ipv6_addr_prefix(&prefix_buf,
855 (struct in6_addr *)rinfo->prefix,
856 rinfo->prefix_len);
857 prefix = &prefix_buf;
858 }
859
Duan Jiongf104a562013-11-08 09:56:53 +0800860 if (rinfo->prefix_len == 0)
861 rt = rt6_get_dflt_router(gwaddr, dev);
862 else
863 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700864 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800865
866 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700867 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800868 rt = NULL;
869 }
870
871 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700872 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
873 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800874 else if (rt)
875 rt->rt6i_flags = RTF_ROUTEINFO |
876 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
877
878 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000879 if (!addrconf_finite_timeout(lifetime))
880 rt6_clean_expires(rt);
881 else
882 rt6_set_expires(rt, jiffies + HZ * lifetime);
883
Amerigo Wang94e187c2012-10-29 00:13:19 +0000884 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800885 }
886 return 0;
887}
888#endif
889
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700890static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
891 struct in6_addr *saddr)
892{
Wei Wang66f5d6c2017-10-06 12:06:10 -0700893 struct fib6_node *pn, *sn;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700894 while (1) {
895 if (fn->fn_flags & RTN_TL_ROOT)
896 return NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -0700897 pn = rcu_dereference(fn->parent);
898 sn = FIB6_SUBTREE(pn);
899 if (sn && sn != fn)
900 fn = fib6_lookup(sn, NULL, saddr);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700901 else
902 fn = pn;
903 if (fn->fn_flags & RTN_RTINFO)
904 return fn;
905 }
906}
Thomas Grafc71099a2006-08-04 23:20:06 -0700907
Wei Wangd3843fe2017-10-06 12:06:06 -0700908static bool ip6_hold_safe(struct net *net, struct rt6_info **prt,
909 bool null_fallback)
910{
911 struct rt6_info *rt = *prt;
912
913 if (dst_hold_safe(&rt->dst))
914 return true;
915 if (null_fallback) {
916 rt = net->ipv6.ip6_null_entry;
917 dst_hold(&rt->dst);
918 } else {
919 rt = NULL;
920 }
921 *prt = rt;
922 return false;
923}
924
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800925static struct rt6_info *ip6_pol_route_lookup(struct net *net,
926 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500927 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Wei Wang2b760fc2017-10-06 12:06:03 -0700929 struct rt6_info *rt, *rt_cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Wei Wang66f5d6c2017-10-06 12:06:10 -0700932 rcu_read_lock();
David S. Miller4c9483b2011-03-12 16:22:43 -0500933 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700934restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -0700935 rt = rcu_dereference(fn->leaf);
936 if (!rt) {
937 rt = net->ipv6.ip6_null_entry;
938 } else {
939 rt = rt6_device_match(net, rt, &fl6->saddr,
940 fl6->flowi6_oif, flags);
941 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
942 rt = rt6_multipath_select(rt, fl6,
943 fl6->flowi6_oif, flags);
944 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700945 if (rt == net->ipv6.ip6_null_entry) {
946 fn = fib6_backtrack(fn, &fl6->saddr);
947 if (fn)
948 goto restart;
949 }
Wei Wang2b760fc2017-10-06 12:06:03 -0700950 /* Search through exception table */
951 rt_cache = rt6_find_cached_rt(rt, &fl6->daddr, &fl6->saddr);
952 if (rt_cache)
953 rt = rt_cache;
954
Wei Wangd3843fe2017-10-06 12:06:06 -0700955 if (ip6_hold_safe(net, &rt, true))
956 dst_use_noref(&rt->dst, jiffies);
957
Wei Wang66f5d6c2017-10-06 12:06:10 -0700958 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -0800959
Paolo Abenib65f1642017-10-19 09:31:43 +0200960 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahernb8115802015-11-19 12:24:22 -0800961
Thomas Grafc71099a2006-08-04 23:20:06 -0700962 return rt;
963
964}
965
Ian Morris67ba4152014-08-24 21:53:10 +0100966struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200967 int flags)
968{
969 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
970}
971EXPORT_SYMBOL_GPL(ip6_route_lookup);
972
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900973struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
974 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700975{
David S. Miller4c9483b2011-03-12 16:22:43 -0500976 struct flowi6 fl6 = {
977 .flowi6_oif = oif,
978 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700979 };
980 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700981 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700982
Thomas Grafadaa70b2006-10-13 15:01:03 -0700983 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500984 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700985 flags |= RT6_LOOKUP_F_HAS_SADDR;
986 }
987
David S. Miller4c9483b2011-03-12 16:22:43 -0500988 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700989 if (dst->error == 0)
990 return (struct rt6_info *) dst;
991
992 dst_release(dst);
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return NULL;
995}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900996EXPORT_SYMBOL(rt6_lookup);
997
Thomas Grafc71099a2006-08-04 23:20:06 -0700998/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -0700999 * It takes new route entry, the addition fails by any reason the
1000 * route is released.
1001 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 */
1003
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001004static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001005 struct mx6_config *mxc,
1006 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{
1008 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001009 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Thomas Grafc71099a2006-08-04 23:20:06 -07001011 table = rt->rt6i_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001012 spin_lock_bh(&table->tb6_lock);
David Ahern333c4302017-05-21 10:12:04 -06001013 err = fib6_add(&table->tb6_root, rt, info, mxc, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001014 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 return err;
1017}
1018
Thomas Graf40e22e82006-08-22 00:00:45 -07001019int ip6_ins_rt(struct rt6_info *rt)
1020{
Florian Westphale715b6d2015-01-05 23:57:44 +01001021 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
1022 struct mx6_config mxc = { .mx = NULL, };
1023
Wei Wang1cfb71e2017-06-17 10:42:33 -07001024 /* Hold dst to account for the reference from the fib6 tree */
1025 dst_hold(&rt->dst);
David Ahern333c4302017-05-21 10:12:04 -06001026 return __ip6_ins_rt(rt, &info, &mxc, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001027}
1028
David Ahern4832c302017-08-17 12:17:20 -07001029/* called with rcu_lock held */
1030static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt)
1031{
1032 struct net_device *dev = rt->dst.dev;
1033
David Ahern98d11292017-11-21 07:08:57 -08001034 if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) {
David Ahern4832c302017-08-17 12:17:20 -07001035 /* for copies of local routes, dst->dev needs to be the
1036 * device if it is a master device, the master device if
1037 * device is enslaved, and the loopback as the default
1038 */
1039 if (netif_is_l3_slave(dev) &&
1040 !rt6_need_strict(&rt->rt6i_dst.addr))
1041 dev = l3mdev_master_dev_rcu(dev);
1042 else if (!netif_is_l3_master(dev))
1043 dev = dev_net(dev)->loopback_dev;
1044 /* last case is netif_is_l3_master(dev) is true in which
1045 * case we want dev returned to be dev
1046 */
1047 }
1048
1049 return dev;
1050}
1051
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001052static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
1053 const struct in6_addr *daddr,
1054 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
David Ahern4832c302017-08-17 12:17:20 -07001056 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 struct rt6_info *rt;
1058
1059 /*
1060 * Clone the route.
1061 */
1062
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001063 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
David Miller3a2232e2017-11-28 15:40:40 -05001064 ort = ort->from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
David Ahern4832c302017-08-17 12:17:20 -07001066 rcu_read_lock();
1067 dev = ip6_rt_get_dev_rcu(ort);
1068 rt = __ip6_dst_alloc(dev_net(dev), dev, 0);
1069 rcu_read_unlock();
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001070 if (!rt)
1071 return NULL;
1072
1073 ip6_rt_copy_init(rt, ort);
1074 rt->rt6i_flags |= RTF_CACHE;
1075 rt->rt6i_metric = 0;
1076 rt->dst.flags |= DST_HOST;
1077 rt->rt6i_dst.addr = *daddr;
1078 rt->rt6i_dst.plen = 128;
1079
1080 if (!rt6_is_gw_or_nonexthop(ort)) {
1081 if (ort->rt6i_dst.plen != 128 &&
1082 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
1083 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001085 if (rt->rt6i_src.plen && saddr) {
1086 rt->rt6i_src.addr = *saddr;
1087 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001088 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001089#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001092 return rt;
1093}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001095static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
1096{
David Ahern4832c302017-08-17 12:17:20 -07001097 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001098 struct rt6_info *pcpu_rt;
1099
David Ahern4832c302017-08-17 12:17:20 -07001100 rcu_read_lock();
1101 dev = ip6_rt_get_dev_rcu(rt);
1102 pcpu_rt = __ip6_dst_alloc(dev_net(dev), dev, rt->dst.flags);
1103 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001104 if (!pcpu_rt)
1105 return NULL;
1106 ip6_rt_copy_init(pcpu_rt, rt);
1107 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
1108 pcpu_rt->rt6i_flags |= RTF_PCPU;
1109 return pcpu_rt;
1110}
1111
Wei Wang66f5d6c2017-10-06 12:06:10 -07001112/* It should be called with rcu_read_lock() acquired */
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001113static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
1114{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001115 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001116
1117 p = this_cpu_ptr(rt->rt6i_pcpu);
1118 pcpu_rt = *p;
1119
Wei Wangd3843fe2017-10-06 12:06:06 -07001120 if (pcpu_rt && ip6_hold_safe(NULL, &pcpu_rt, false))
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001121 rt6_dst_from_metrics_check(pcpu_rt);
Wei Wangd3843fe2017-10-06 12:06:06 -07001122
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001123 return pcpu_rt;
1124}
1125
1126static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
1127{
1128 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001129
1130 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1131 if (!pcpu_rt) {
1132 struct net *net = dev_net(rt->dst.dev);
1133
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001134 dst_hold(&net->ipv6.ip6_null_entry->dst);
1135 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001136 }
1137
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001138 dst_hold(&pcpu_rt->dst);
Wei Wanga94b9362017-10-06 12:06:04 -07001139 p = this_cpu_ptr(rt->rt6i_pcpu);
1140 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001141 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001142
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001143 rt6_dst_from_metrics_check(pcpu_rt);
1144 return pcpu_rt;
1145}
1146
Wei Wang35732d02017-10-06 12:05:57 -07001147/* exception hash table implementation
1148 */
1149static DEFINE_SPINLOCK(rt6_exception_lock);
1150
1151/* Remove rt6_ex from hash table and free the memory
1152 * Caller must hold rt6_exception_lock
1153 */
1154static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1155 struct rt6_exception *rt6_ex)
1156{
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001157 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001158
Wei Wang35732d02017-10-06 12:05:57 -07001159 if (!bucket || !rt6_ex)
1160 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001161
1162 net = dev_net(rt6_ex->rt6i->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001163 rt6_ex->rt6i->rt6i_node = NULL;
1164 hlist_del_rcu(&rt6_ex->hlist);
1165 rt6_release(rt6_ex->rt6i);
1166 kfree_rcu(rt6_ex, rcu);
1167 WARN_ON_ONCE(!bucket->depth);
1168 bucket->depth--;
Wei Wang81eb8442017-10-06 12:06:11 -07001169 net->ipv6.rt6_stats->fib_rt_cache--;
Wei Wang35732d02017-10-06 12:05:57 -07001170}
1171
1172/* Remove oldest rt6_ex in bucket and free the memory
1173 * Caller must hold rt6_exception_lock
1174 */
1175static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1176{
1177 struct rt6_exception *rt6_ex, *oldest = NULL;
1178
1179 if (!bucket)
1180 return;
1181
1182 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1183 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1184 oldest = rt6_ex;
1185 }
1186 rt6_remove_exception(bucket, oldest);
1187}
1188
1189static u32 rt6_exception_hash(const struct in6_addr *dst,
1190 const struct in6_addr *src)
1191{
1192 static u32 seed __read_mostly;
1193 u32 val;
1194
1195 net_get_random_once(&seed, sizeof(seed));
1196 val = jhash(dst, sizeof(*dst), seed);
1197
1198#ifdef CONFIG_IPV6_SUBTREES
1199 if (src)
1200 val = jhash(src, sizeof(*src), val);
1201#endif
1202 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1203}
1204
1205/* Helper function to find the cached rt in the hash table
1206 * and update bucket pointer to point to the bucket for this
1207 * (daddr, saddr) pair
1208 * Caller must hold rt6_exception_lock
1209 */
1210static struct rt6_exception *
1211__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1212 const struct in6_addr *daddr,
1213 const struct in6_addr *saddr)
1214{
1215 struct rt6_exception *rt6_ex;
1216 u32 hval;
1217
1218 if (!(*bucket) || !daddr)
1219 return NULL;
1220
1221 hval = rt6_exception_hash(daddr, saddr);
1222 *bucket += hval;
1223
1224 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1225 struct rt6_info *rt6 = rt6_ex->rt6i;
1226 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1227
1228#ifdef CONFIG_IPV6_SUBTREES
1229 if (matched && saddr)
1230 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1231#endif
1232 if (matched)
1233 return rt6_ex;
1234 }
1235 return NULL;
1236}
1237
1238/* Helper function to find the cached rt in the hash table
1239 * and update bucket pointer to point to the bucket for this
1240 * (daddr, saddr) pair
1241 * Caller must hold rcu_read_lock()
1242 */
1243static struct rt6_exception *
1244__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1245 const struct in6_addr *daddr,
1246 const struct in6_addr *saddr)
1247{
1248 struct rt6_exception *rt6_ex;
1249 u32 hval;
1250
1251 WARN_ON_ONCE(!rcu_read_lock_held());
1252
1253 if (!(*bucket) || !daddr)
1254 return NULL;
1255
1256 hval = rt6_exception_hash(daddr, saddr);
1257 *bucket += hval;
1258
1259 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1260 struct rt6_info *rt6 = rt6_ex->rt6i;
1261 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1262
1263#ifdef CONFIG_IPV6_SUBTREES
1264 if (matched && saddr)
1265 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1266#endif
1267 if (matched)
1268 return rt6_ex;
1269 }
1270 return NULL;
1271}
1272
1273static int rt6_insert_exception(struct rt6_info *nrt,
1274 struct rt6_info *ort)
1275{
Wei Wang81eb8442017-10-06 12:06:11 -07001276 struct net *net = dev_net(ort->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001277 struct rt6_exception_bucket *bucket;
1278 struct in6_addr *src_key = NULL;
1279 struct rt6_exception *rt6_ex;
1280 int err = 0;
1281
1282 /* ort can't be a cache or pcpu route */
1283 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
David Miller3a2232e2017-11-28 15:40:40 -05001284 ort = ort->from;
Wei Wang35732d02017-10-06 12:05:57 -07001285 WARN_ON_ONCE(ort->rt6i_flags & (RTF_CACHE | RTF_PCPU));
1286
1287 spin_lock_bh(&rt6_exception_lock);
1288
1289 if (ort->exception_bucket_flushed) {
1290 err = -EINVAL;
1291 goto out;
1292 }
1293
1294 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1295 lockdep_is_held(&rt6_exception_lock));
1296 if (!bucket) {
1297 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1298 GFP_ATOMIC);
1299 if (!bucket) {
1300 err = -ENOMEM;
1301 goto out;
1302 }
1303 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1304 }
1305
1306#ifdef CONFIG_IPV6_SUBTREES
1307 /* rt6i_src.plen != 0 indicates ort is in subtree
1308 * and exception table is indexed by a hash of
1309 * both rt6i_dst and rt6i_src.
1310 * Otherwise, the exception table is indexed by
1311 * a hash of only rt6i_dst.
1312 */
1313 if (ort->rt6i_src.plen)
1314 src_key = &nrt->rt6i_src.addr;
1315#endif
Wei Wang60006a42017-10-06 12:05:58 -07001316
1317 /* Update rt6i_prefsrc as it could be changed
1318 * in rt6_remove_prefsrc()
1319 */
1320 nrt->rt6i_prefsrc = ort->rt6i_prefsrc;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001321 /* rt6_mtu_change() might lower mtu on ort.
1322 * Only insert this exception route if its mtu
1323 * is less than ort's mtu value.
1324 */
1325 if (nrt->rt6i_pmtu >= dst_mtu(&ort->dst)) {
1326 err = -EINVAL;
1327 goto out;
1328 }
Wei Wang60006a42017-10-06 12:05:58 -07001329
Wei Wang35732d02017-10-06 12:05:57 -07001330 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1331 src_key);
1332 if (rt6_ex)
1333 rt6_remove_exception(bucket, rt6_ex);
1334
1335 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1336 if (!rt6_ex) {
1337 err = -ENOMEM;
1338 goto out;
1339 }
1340 rt6_ex->rt6i = nrt;
1341 rt6_ex->stamp = jiffies;
1342 atomic_inc(&nrt->rt6i_ref);
1343 nrt->rt6i_node = ort->rt6i_node;
1344 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1345 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001346 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001347
1348 if (bucket->depth > FIB6_MAX_DEPTH)
1349 rt6_exception_remove_oldest(bucket);
1350
1351out:
1352 spin_unlock_bh(&rt6_exception_lock);
1353
1354 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001355 if (!err) {
Wei Wang35732d02017-10-06 12:05:57 -07001356 fib6_update_sernum(ort);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001357 fib6_force_start_gc(net);
1358 }
Wei Wang35732d02017-10-06 12:05:57 -07001359
1360 return err;
1361}
1362
1363void rt6_flush_exceptions(struct rt6_info *rt)
1364{
1365 struct rt6_exception_bucket *bucket;
1366 struct rt6_exception *rt6_ex;
1367 struct hlist_node *tmp;
1368 int i;
1369
1370 spin_lock_bh(&rt6_exception_lock);
1371 /* Prevent rt6_insert_exception() to recreate the bucket list */
1372 rt->exception_bucket_flushed = 1;
1373
1374 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1375 lockdep_is_held(&rt6_exception_lock));
1376 if (!bucket)
1377 goto out;
1378
1379 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1380 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1381 rt6_remove_exception(bucket, rt6_ex);
1382 WARN_ON_ONCE(bucket->depth);
1383 bucket++;
1384 }
1385
1386out:
1387 spin_unlock_bh(&rt6_exception_lock);
1388}
1389
1390/* Find cached rt in the hash table inside passed in rt
1391 * Caller has to hold rcu_read_lock()
1392 */
1393static struct rt6_info *rt6_find_cached_rt(struct rt6_info *rt,
1394 struct in6_addr *daddr,
1395 struct in6_addr *saddr)
1396{
1397 struct rt6_exception_bucket *bucket;
1398 struct in6_addr *src_key = NULL;
1399 struct rt6_exception *rt6_ex;
1400 struct rt6_info *res = NULL;
1401
1402 bucket = rcu_dereference(rt->rt6i_exception_bucket);
1403
1404#ifdef CONFIG_IPV6_SUBTREES
1405 /* rt6i_src.plen != 0 indicates rt is in subtree
1406 * and exception table is indexed by a hash of
1407 * both rt6i_dst and rt6i_src.
1408 * Otherwise, the exception table is indexed by
1409 * a hash of only rt6i_dst.
1410 */
1411 if (rt->rt6i_src.plen)
1412 src_key = saddr;
1413#endif
1414 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1415
1416 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1417 res = rt6_ex->rt6i;
1418
1419 return res;
1420}
1421
1422/* Remove the passed in cached rt from the hash table that contains it */
1423int rt6_remove_exception_rt(struct rt6_info *rt)
1424{
Wei Wang35732d02017-10-06 12:05:57 -07001425 struct rt6_exception_bucket *bucket;
David Miller3a2232e2017-11-28 15:40:40 -05001426 struct rt6_info *from = rt->from;
Wei Wang35732d02017-10-06 12:05:57 -07001427 struct in6_addr *src_key = NULL;
1428 struct rt6_exception *rt6_ex;
1429 int err;
1430
1431 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001432 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001433 return -EINVAL;
1434
1435 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1436 return -ENOENT;
1437
1438 spin_lock_bh(&rt6_exception_lock);
1439 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1440 lockdep_is_held(&rt6_exception_lock));
1441#ifdef CONFIG_IPV6_SUBTREES
1442 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1443 * and exception table is indexed by a hash of
1444 * both rt6i_dst and rt6i_src.
1445 * Otherwise, the exception table is indexed by
1446 * a hash of only rt6i_dst.
1447 */
1448 if (from->rt6i_src.plen)
1449 src_key = &rt->rt6i_src.addr;
1450#endif
1451 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1452 &rt->rt6i_dst.addr,
1453 src_key);
1454 if (rt6_ex) {
1455 rt6_remove_exception(bucket, rt6_ex);
1456 err = 0;
1457 } else {
1458 err = -ENOENT;
1459 }
1460
1461 spin_unlock_bh(&rt6_exception_lock);
1462 return err;
1463}
1464
1465/* Find rt6_ex which contains the passed in rt cache and
1466 * refresh its stamp
1467 */
1468static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1469{
Wei Wang35732d02017-10-06 12:05:57 -07001470 struct rt6_exception_bucket *bucket;
David Miller3a2232e2017-11-28 15:40:40 -05001471 struct rt6_info *from = rt->from;
Wei Wang35732d02017-10-06 12:05:57 -07001472 struct in6_addr *src_key = NULL;
1473 struct rt6_exception *rt6_ex;
1474
1475 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001476 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001477 return;
1478
1479 rcu_read_lock();
1480 bucket = rcu_dereference(from->rt6i_exception_bucket);
1481
1482#ifdef CONFIG_IPV6_SUBTREES
1483 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1484 * and exception table is indexed by a hash of
1485 * both rt6i_dst and rt6i_src.
1486 * Otherwise, the exception table is indexed by
1487 * a hash of only rt6i_dst.
1488 */
1489 if (from->rt6i_src.plen)
1490 src_key = &rt->rt6i_src.addr;
1491#endif
1492 rt6_ex = __rt6_find_exception_rcu(&bucket,
1493 &rt->rt6i_dst.addr,
1494 src_key);
1495 if (rt6_ex)
1496 rt6_ex->stamp = jiffies;
1497
1498 rcu_read_unlock();
1499}
1500
Wei Wang60006a42017-10-06 12:05:58 -07001501static void rt6_exceptions_remove_prefsrc(struct rt6_info *rt)
1502{
1503 struct rt6_exception_bucket *bucket;
1504 struct rt6_exception *rt6_ex;
1505 int i;
1506
1507 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1508 lockdep_is_held(&rt6_exception_lock));
1509
1510 if (bucket) {
1511 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1512 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1513 rt6_ex->rt6i->rt6i_prefsrc.plen = 0;
1514 }
1515 bucket++;
1516 }
1517 }
1518}
1519
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001520static void rt6_exceptions_update_pmtu(struct rt6_info *rt, int mtu)
1521{
1522 struct rt6_exception_bucket *bucket;
1523 struct rt6_exception *rt6_ex;
1524 int i;
1525
1526 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1527 lockdep_is_held(&rt6_exception_lock));
1528
1529 if (bucket) {
1530 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1531 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1532 struct rt6_info *entry = rt6_ex->rt6i;
1533 /* For RTF_CACHE with rt6i_pmtu == 0
1534 * (i.e. a redirected route),
1535 * the metrics of its rt->dst.from has already
1536 * been updated.
1537 */
1538 if (entry->rt6i_pmtu && entry->rt6i_pmtu > mtu)
1539 entry->rt6i_pmtu = mtu;
1540 }
1541 bucket++;
1542 }
1543 }
1544}
1545
Wei Wangb16cb452017-10-06 12:06:00 -07001546#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1547
1548static void rt6_exceptions_clean_tohost(struct rt6_info *rt,
1549 struct in6_addr *gateway)
1550{
1551 struct rt6_exception_bucket *bucket;
1552 struct rt6_exception *rt6_ex;
1553 struct hlist_node *tmp;
1554 int i;
1555
1556 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1557 return;
1558
1559 spin_lock_bh(&rt6_exception_lock);
1560 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1561 lockdep_is_held(&rt6_exception_lock));
1562
1563 if (bucket) {
1564 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1565 hlist_for_each_entry_safe(rt6_ex, tmp,
1566 &bucket->chain, hlist) {
1567 struct rt6_info *entry = rt6_ex->rt6i;
1568
1569 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1570 RTF_CACHE_GATEWAY &&
1571 ipv6_addr_equal(gateway,
1572 &entry->rt6i_gateway)) {
1573 rt6_remove_exception(bucket, rt6_ex);
1574 }
1575 }
1576 bucket++;
1577 }
1578 }
1579
1580 spin_unlock_bh(&rt6_exception_lock);
1581}
1582
Wei Wangc757faa2017-10-06 12:06:01 -07001583static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1584 struct rt6_exception *rt6_ex,
1585 struct fib6_gc_args *gc_args,
1586 unsigned long now)
1587{
1588 struct rt6_info *rt = rt6_ex->rt6i;
1589
Paolo Abeni1859bac2017-10-19 16:07:11 +02001590 /* we are pruning and obsoleting aged-out and non gateway exceptions
1591 * even if others have still references to them, so that on next
1592 * dst_check() such references can be dropped.
1593 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1594 * expired, independently from their aging, as per RFC 8201 section 4
1595 */
1596 if (!(rt->rt6i_flags & RTF_EXPIRES) &&
Wei Wangc757faa2017-10-06 12:06:01 -07001597 time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1598 RT6_TRACE("aging clone %p\n", rt);
1599 rt6_remove_exception(bucket, rt6_ex);
1600 return;
1601 } else if (rt->rt6i_flags & RTF_GATEWAY) {
1602 struct neighbour *neigh;
1603 __u8 neigh_flags = 0;
1604
1605 neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway);
1606 if (neigh) {
1607 neigh_flags = neigh->flags;
1608 neigh_release(neigh);
1609 }
1610 if (!(neigh_flags & NTF_ROUTER)) {
1611 RT6_TRACE("purging route %p via non-router but gateway\n",
1612 rt);
1613 rt6_remove_exception(bucket, rt6_ex);
1614 return;
1615 }
Paolo Abeni1859bac2017-10-19 16:07:11 +02001616 } else if (__rt6_check_expired(rt)) {
1617 RT6_TRACE("purging expired route %p\n", rt);
1618 rt6_remove_exception(bucket, rt6_ex);
1619 return;
Wei Wangc757faa2017-10-06 12:06:01 -07001620 }
1621 gc_args->more++;
1622}
1623
1624void rt6_age_exceptions(struct rt6_info *rt,
1625 struct fib6_gc_args *gc_args,
1626 unsigned long now)
1627{
1628 struct rt6_exception_bucket *bucket;
1629 struct rt6_exception *rt6_ex;
1630 struct hlist_node *tmp;
1631 int i;
1632
1633 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1634 return;
1635
1636 spin_lock_bh(&rt6_exception_lock);
1637 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1638 lockdep_is_held(&rt6_exception_lock));
1639
1640 if (bucket) {
1641 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1642 hlist_for_each_entry_safe(rt6_ex, tmp,
1643 &bucket->chain, hlist) {
1644 rt6_age_examine_exception(bucket, rt6_ex,
1645 gc_args, now);
1646 }
1647 bucket++;
1648 }
1649 }
1650 spin_unlock_bh(&rt6_exception_lock);
1651}
1652
David Ahern9ff74382016-06-13 13:44:19 -07001653struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1654 int oif, struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001656 struct fib6_node *fn, *saved_fn;
Wei Wang2b760fc2017-10-06 12:06:03 -07001657 struct rt6_info *rt, *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07001658 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001660 strict |= flags & RT6_LOOKUP_F_IFACE;
David Ahernd5d32e42016-10-24 12:27:23 -07001661 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001662 if (net->ipv6.devconf_all->forwarding == 0)
1663 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Wei Wang66f5d6c2017-10-06 12:06:10 -07001665 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
David S. Miller4c9483b2011-03-12 16:22:43 -05001667 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001668 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
David Ahernca254492015-10-12 11:47:10 -07001670 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1671 oif = 0;
1672
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001673redo_rt6_select:
Wei Wang8d1040e2017-10-06 12:06:08 -07001674 rt = rt6_select(net, fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001675 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001676 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001677 if (rt == net->ipv6.ip6_null_entry) {
1678 fn = fib6_backtrack(fn, &fl6->saddr);
1679 if (fn)
1680 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001681 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1682 /* also consider unreachable route */
1683 strict &= ~RT6_LOOKUP_F_REACHABLE;
1684 fn = saved_fn;
1685 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001686 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001687 }
1688
Wei Wang2b760fc2017-10-06 12:06:03 -07001689 /*Search through exception table */
1690 rt_cache = rt6_find_cached_rt(rt, &fl6->daddr, &fl6->saddr);
1691 if (rt_cache)
1692 rt = rt_cache;
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001693
Wei Wangd3843fe2017-10-06 12:06:06 -07001694 if (rt == net->ipv6.ip6_null_entry) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07001695 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001696 dst_hold(&rt->dst);
Paolo Abenib65f1642017-10-19 09:31:43 +02001697 trace_fib6_table_lookup(net, rt, table, fl6);
Wei Wangd3843fe2017-10-06 12:06:06 -07001698 return rt;
1699 } else if (rt->rt6i_flags & RTF_CACHE) {
1700 if (ip6_hold_safe(net, &rt, true)) {
1701 dst_use_noref(&rt->dst, jiffies);
1702 rt6_dst_from_metrics_check(rt);
1703 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07001704 rcu_read_unlock();
Paolo Abenib65f1642017-10-19 09:31:43 +02001705 trace_fib6_table_lookup(net, rt, table, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001706 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001707 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1708 !(rt->rt6i_flags & RTF_GATEWAY))) {
1709 /* Create a RTF_CACHE clone which will not be
1710 * owned by the fib6 tree. It is for the special case where
1711 * the daddr in the skb during the neighbor look-up is different
1712 * from the fl6->daddr used to look-up route here.
1713 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001714
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001715 struct rt6_info *uncached_rt;
1716
Wei Wangd3843fe2017-10-06 12:06:06 -07001717 if (ip6_hold_safe(net, &rt, true)) {
1718 dst_use_noref(&rt->dst, jiffies);
1719 } else {
Wei Wang66f5d6c2017-10-06 12:06:10 -07001720 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001721 uncached_rt = rt;
1722 goto uncached_rt_out;
1723 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07001724 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001725
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001726 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1727 dst_release(&rt->dst);
1728
Wei Wang1cfb71e2017-06-17 10:42:33 -07001729 if (uncached_rt) {
1730 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1731 * No need for another dst_hold()
1732 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001733 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001734 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001735 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001736 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001737 dst_hold(&uncached_rt->dst);
1738 }
David Ahernb8115802015-11-19 12:24:22 -08001739
Wei Wangd3843fe2017-10-06 12:06:06 -07001740uncached_rt_out:
Paolo Abenib65f1642017-10-19 09:31:43 +02001741 trace_fib6_table_lookup(net, uncached_rt, table, fl6);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001742 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001743
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001744 } else {
1745 /* Get a percpu copy */
1746
1747 struct rt6_info *pcpu_rt;
1748
Wei Wangd3843fe2017-10-06 12:06:06 -07001749 dst_use_noref(&rt->dst, jiffies);
Eric Dumazet951f7882017-10-08 21:07:18 -07001750 local_bh_disable();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001751 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001752
Eric Dumazet951f7882017-10-08 21:07:18 -07001753 if (!pcpu_rt) {
Wei Wanga94b9362017-10-06 12:06:04 -07001754 /* atomic_inc_not_zero() is needed when using rcu */
1755 if (atomic_inc_not_zero(&rt->rt6i_ref)) {
Eric Dumazet951f7882017-10-08 21:07:18 -07001756 /* No dst_hold() on rt is needed because grabbing
Wei Wanga94b9362017-10-06 12:06:04 -07001757 * rt->rt6i_ref makes sure rt can't be released.
1758 */
Wei Wanga94b9362017-10-06 12:06:04 -07001759 pcpu_rt = rt6_make_pcpu_route(rt);
1760 rt6_release(rt);
1761 } else {
1762 /* rt is already removed from tree */
Wei Wanga94b9362017-10-06 12:06:04 -07001763 pcpu_rt = net->ipv6.ip6_null_entry;
1764 dst_hold(&pcpu_rt->dst);
1765 }
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001766 }
Eric Dumazet951f7882017-10-08 21:07:18 -07001767 local_bh_enable();
1768 rcu_read_unlock();
Paolo Abenib65f1642017-10-19 09:31:43 +02001769 trace_fib6_table_lookup(net, pcpu_rt, table, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001770 return pcpu_rt;
1771 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001772}
David Ahern9ff74382016-06-13 13:44:19 -07001773EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001774
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001775static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001776 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001777{
David S. Miller4c9483b2011-03-12 16:22:43 -05001778 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001779}
1780
Mahesh Bandeward409b842016-09-16 12:59:08 -07001781struct dst_entry *ip6_route_input_lookup(struct net *net,
1782 struct net_device *dev,
1783 struct flowi6 *fl6, int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001784{
1785 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1786 flags |= RT6_LOOKUP_F_IFACE;
1787
1788 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1789}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001790EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001791
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001792static void ip6_multipath_l3_keys(const struct sk_buff *skb,
1793 struct flow_keys *keys)
1794{
1795 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1796 const struct ipv6hdr *key_iph = outer_iph;
1797 const struct ipv6hdr *inner_iph;
1798 const struct icmp6hdr *icmph;
1799 struct ipv6hdr _inner_iph;
1800
1801 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1802 goto out;
1803
1804 icmph = icmp6_hdr(skb);
1805 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1806 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1807 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1808 icmph->icmp6_type != ICMPV6_PARAMPROB)
1809 goto out;
1810
1811 inner_iph = skb_header_pointer(skb,
1812 skb_transport_offset(skb) + sizeof(*icmph),
1813 sizeof(_inner_iph), &_inner_iph);
1814 if (!inner_iph)
1815 goto out;
1816
1817 key_iph = inner_iph;
1818out:
1819 memset(keys, 0, sizeof(*keys));
1820 keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1821 keys->addrs.v6addrs.src = key_iph->saddr;
1822 keys->addrs.v6addrs.dst = key_iph->daddr;
1823 keys->tags.flow_label = ip6_flowinfo(key_iph);
1824 keys->basic.ip_proto = key_iph->nexthdr;
1825}
1826
1827/* if skb is set it will be used and fl6 can be NULL */
1828u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb)
1829{
1830 struct flow_keys hash_keys;
1831
1832 if (skb) {
1833 ip6_multipath_l3_keys(skb, &hash_keys);
1834 return flow_hash_from_keys(&hash_keys);
1835 }
1836
1837 return get_hash_from_flowi6(fl6);
1838}
1839
Thomas Grafc71099a2006-08-04 23:20:06 -07001840void ip6_route_input(struct sk_buff *skb)
1841{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001842 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001843 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001844 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001845 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001846 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07001847 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05001848 .daddr = iph->daddr,
1849 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001850 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001851 .flowi6_mark = skb->mark,
1852 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001853 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001854
Jiri Benc904af042015-08-20 13:56:31 +02001855 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001856 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001857 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001858 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
1859 fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
Jiri Benc06e9d042015-08-20 13:56:26 +02001860 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001861 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001862}
1863
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001864static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001865 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001866{
David S. Miller4c9483b2011-03-12 16:22:43 -05001867 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001868}
1869
Paolo Abeni6f21c962016-01-29 12:30:19 +01001870struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
1871 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001872{
David Ahernd46a9d62015-10-21 08:42:22 -07001873 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07001874
David Ahern4c1feac2016-09-10 12:09:56 -07001875 if (rt6_need_strict(&fl6->daddr)) {
1876 struct dst_entry *dst;
1877
1878 dst = l3mdev_link_scope_lookup(net, fl6);
1879 if (dst)
1880 return dst;
1881 }
David Ahernca254492015-10-12 11:47:10 -07001882
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001883 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001884
David Ahernd46a9d62015-10-21 08:42:22 -07001885 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07001886 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07001887 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001888 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001889
David Ahernd46a9d62015-10-21 08:42:22 -07001890 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07001891 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001892 else if (sk)
1893 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001894
David S. Miller4c9483b2011-03-12 16:22:43 -05001895 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896}
Paolo Abeni6f21c962016-01-29 12:30:19 +01001897EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
David S. Miller2774c132011-03-01 14:59:04 -08001899struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001900{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001901 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07001902 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07001903 struct dst_entry *new = NULL;
1904
Wei Wang1dbe32522017-06-17 10:42:26 -07001905 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02001906 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001907 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001908 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001909 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001910
Changli Gaod8d1f302010-06-10 23:31:35 -07001911 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001912 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001913 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001914 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07001915
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001916 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001917
Wei Wang1dbe32522017-06-17 10:42:26 -07001918 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001919 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001920 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07001921 rt->rt6i_metric = 0;
1922
1923 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1924#ifdef CONFIG_IPV6_SUBTREES
1925 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1926#endif
David S. Miller14e50e52007-05-24 18:17:54 -07001927 }
1928
David S. Miller69ead7a2011-03-01 14:45:33 -08001929 dst_release(dst_orig);
1930 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001931}
David S. Miller14e50e52007-05-24 18:17:54 -07001932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933/*
1934 * Destination cache support functions
1935 */
1936
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001937static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1938{
David Miller3a2232e2017-11-28 15:40:40 -05001939 if (rt->from &&
1940 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(&rt->from->dst))
1941 dst_init_metrics(&rt->dst, dst_metrics_ptr(&rt->from->dst), true);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001942}
1943
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001944static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1945{
Steffen Klassert36143642017-08-25 09:05:42 +02001946 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07001947
1948 if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001949 return NULL;
1950
1951 if (rt6_check_expired(rt))
1952 return NULL;
1953
1954 return &rt->dst;
1955}
1956
1957static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1958{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08001959 if (!__rt6_check_expired(rt) &&
1960 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Miller3a2232e2017-11-28 15:40:40 -05001961 rt6_check(rt->from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001962 return &rt->dst;
1963 else
1964 return NULL;
1965}
1966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1968{
1969 struct rt6_info *rt;
1970
1971 rt = (struct rt6_info *) dst;
1972
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001973 /* All IPV6 dsts are created with ->obsolete set to the value
1974 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1975 * into this function always.
1976 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001977
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001978 rt6_dst_from_metrics_check(rt);
1979
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08001980 if (rt->rt6i_flags & RTF_PCPU ||
David Miller3a2232e2017-11-28 15:40:40 -05001981 (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001982 return rt6_dst_from_check(rt, cookie);
1983 else
1984 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985}
1986
1987static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1988{
1989 struct rt6_info *rt = (struct rt6_info *) dst;
1990
1991 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001992 if (rt->rt6i_flags & RTF_CACHE) {
1993 if (rt6_check_expired(rt)) {
1994 ip6_del_rt(rt);
1995 dst = NULL;
1996 }
1997 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001999 dst = NULL;
2000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002002 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003}
2004
2005static void ip6_link_failure(struct sk_buff *skb)
2006{
2007 struct rt6_info *rt;
2008
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002009 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Eric Dumazetadf30902009-06-02 05:19:30 +00002011 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002013 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07002014 if (dst_hold_safe(&rt->dst))
2015 ip6_del_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002016 } else {
2017 struct fib6_node *fn;
2018
2019 rcu_read_lock();
2020 fn = rcu_dereference(rt->rt6i_node);
2021 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2022 fn->fn_sernum = -1;
2023 rcu_read_unlock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026}
2027
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002028static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2029{
2030 struct net *net = dev_net(rt->dst.dev);
2031
2032 rt->rt6i_flags |= RTF_MODIFIED;
2033 rt->rt6i_pmtu = mtu;
2034 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2035}
2036
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002037static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2038{
2039 return !(rt->rt6i_flags & RTF_CACHE) &&
Wei Wang4e587ea2017-08-25 15:03:10 -07002040 (rt->rt6i_flags & RTF_PCPU ||
2041 rcu_access_pointer(rt->rt6i_node));
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002042}
2043
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002044static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2045 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002047 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002048 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002050 if (rt6->rt6i_flags & RTF_LOCAL)
2051 return;
2052
Xin Long19bda362016-10-28 18:18:01 +08002053 if (dst_metric_locked(dst, RTAX_MTU))
2054 return;
2055
Julian Anastasov0dec8792017-02-06 23:14:16 +02002056 if (iph) {
2057 daddr = &iph->daddr;
2058 saddr = &iph->saddr;
2059 } else if (sk) {
2060 daddr = &sk->sk_v6_daddr;
2061 saddr = &inet6_sk(sk)->saddr;
2062 } else {
2063 daddr = NULL;
2064 saddr = NULL;
2065 }
2066 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002067 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2068 if (mtu >= dst_mtu(dst))
2069 return;
David S. Miller81aded22012-06-15 14:54:11 -07002070
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002071 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002072 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002073 /* update rt6_ex->stamp for cache */
2074 if (rt6->rt6i_flags & RTF_CACHE)
2075 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002076 } else if (daddr) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002077 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002078
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002079 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
2080 if (nrt6) {
2081 rt6_do_update_pmtu(nrt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002082 if (rt6_insert_exception(nrt6, rt6))
2083 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 }
2086}
2087
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002088static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2089 struct sk_buff *skb, u32 mtu)
2090{
2091 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2092}
2093
David S. Miller42ae66c2012-06-15 20:01:57 -07002094void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002095 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002096{
2097 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2098 struct dst_entry *dst;
2099 struct flowi6 fl6;
2100
2101 memset(&fl6, 0, sizeof(fl6));
2102 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07002103 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07002104 fl6.daddr = iph->daddr;
2105 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002106 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002107 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07002108
2109 dst = ip6_route_output(net, NULL, &fl6);
2110 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002111 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002112 dst_release(dst);
2113}
2114EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2115
2116void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2117{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002118 struct dst_entry *dst;
2119
David S. Miller81aded22012-06-15 14:54:11 -07002120 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002121 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002122
2123 dst = __sk_dst_get(sk);
2124 if (!dst || !dst->obsolete ||
2125 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2126 return;
2127
2128 bh_lock_sock(sk);
2129 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2130 ip6_datagram_dst_update(sk, false);
2131 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002132}
2133EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2134
Duan Jiongb55b76b2013-09-04 19:44:21 +08002135/* Handle redirects */
2136struct ip6rd_flowi {
2137 struct flowi6 fl6;
2138 struct in6_addr gateway;
2139};
2140
2141static struct rt6_info *__ip6_route_redirect(struct net *net,
2142 struct fib6_table *table,
2143 struct flowi6 *fl6,
2144 int flags)
2145{
2146 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
Wei Wang2b760fc2017-10-06 12:06:03 -07002147 struct rt6_info *rt, *rt_cache;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002148 struct fib6_node *fn;
2149
2150 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002151 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002152 *
2153 * RFC 4861 specifies that redirects should only be
2154 * accepted if they come from the nexthop to the target.
2155 * Due to the way the routes are chosen, this notion
2156 * is a bit fuzzy and one might need to check all possible
2157 * routes.
2158 */
2159
Wei Wang66f5d6c2017-10-06 12:06:10 -07002160 rcu_read_lock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002161 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
2162restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002163 for_each_fib6_node_rt_rcu(fn) {
Ido Schimmel8067bb82018-01-07 12:45:09 +02002164 if (rt->rt6i_nh_flags & RTNH_F_DEAD)
2165 continue;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002166 if (rt6_check_expired(rt))
2167 continue;
2168 if (rt->dst.error)
2169 break;
2170 if (!(rt->rt6i_flags & RTF_GATEWAY))
2171 continue;
2172 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
2173 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002174 /* rt_cache's gateway might be different from its 'parent'
2175 * in the case of an ip redirect.
2176 * So we keep searching in the exception table if the gateway
2177 * is different.
2178 */
2179 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) {
2180 rt_cache = rt6_find_cached_rt(rt,
2181 &fl6->daddr,
2182 &fl6->saddr);
2183 if (rt_cache &&
2184 ipv6_addr_equal(&rdfl->gateway,
2185 &rt_cache->rt6i_gateway)) {
2186 rt = rt_cache;
2187 break;
2188 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002189 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002190 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002191 break;
2192 }
2193
2194 if (!rt)
2195 rt = net->ipv6.ip6_null_entry;
2196 else if (rt->dst.error) {
2197 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002198 goto out;
2199 }
2200
2201 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002202 fn = fib6_backtrack(fn, &fl6->saddr);
2203 if (fn)
2204 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002205 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002206
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002207out:
Wei Wangd3843fe2017-10-06 12:06:06 -07002208 ip6_hold_safe(net, &rt, true);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002209
Wei Wang66f5d6c2017-10-06 12:06:10 -07002210 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002211
Paolo Abenib65f1642017-10-19 09:31:43 +02002212 trace_fib6_table_lookup(net, rt, table, fl6);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002213 return rt;
2214};
2215
2216static struct dst_entry *ip6_route_redirect(struct net *net,
2217 const struct flowi6 *fl6,
2218 const struct in6_addr *gateway)
2219{
2220 int flags = RT6_LOOKUP_F_HAS_SADDR;
2221 struct ip6rd_flowi rdfl;
2222
2223 rdfl.fl6 = *fl6;
2224 rdfl.gateway = *gateway;
2225
2226 return fib6_rule_lookup(net, &rdfl.fl6,
2227 flags, __ip6_route_redirect);
2228}
2229
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002230void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2231 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002232{
2233 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2234 struct dst_entry *dst;
2235 struct flowi6 fl6;
2236
2237 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002238 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002239 fl6.flowi6_oif = oif;
2240 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002241 fl6.daddr = iph->daddr;
2242 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002243 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002244 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002245
Duan Jiongb55b76b2013-09-04 19:44:21 +08002246 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
2247 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002248 dst_release(dst);
2249}
2250EXPORT_SYMBOL_GPL(ip6_redirect);
2251
Duan Jiongc92a59e2013-08-22 12:07:35 +08002252void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
2253 u32 mark)
2254{
2255 const struct ipv6hdr *iph = ipv6_hdr(skb);
2256 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2257 struct dst_entry *dst;
2258 struct flowi6 fl6;
2259
2260 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002261 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002262 fl6.flowi6_oif = oif;
2263 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002264 fl6.daddr = msg->dest;
2265 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002266 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002267
Duan Jiongb55b76b2013-09-04 19:44:21 +08002268 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
2269 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002270 dst_release(dst);
2271}
2272
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002273void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2274{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002275 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2276 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002277}
2278EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2279
David S. Miller0dbaee32010-12-13 12:52:14 -08002280static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281{
David S. Miller0dbaee32010-12-13 12:52:14 -08002282 struct net_device *dev = dst->dev;
2283 unsigned int mtu = dst_mtu(dst);
2284 struct net *net = dev_net(dev);
2285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2287
Daniel Lezcano55786892008-03-04 13:47:47 -08002288 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2289 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002292 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2293 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2294 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 * rely only on pmtu discovery"
2296 */
2297 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2298 mtu = IPV6_MAXPLEN;
2299 return mtu;
2300}
2301
Steffen Klassertebb762f2011-11-23 02:12:51 +00002302static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002303{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002304 const struct rt6_info *rt = (const struct rt6_info *)dst;
2305 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08002306 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002307
2308 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07002309 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002310
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002311 mtu = dst_metric_raw(dst, RTAX_MTU);
2312 if (mtu)
2313 goto out;
2314
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002315 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002316
2317 rcu_read_lock();
2318 idev = __in6_dev_get(dst->dev);
2319 if (idev)
2320 mtu = idev->cnf.mtu6;
2321 rcu_read_unlock();
2322
Eric Dumazet30f78d82014-04-10 21:23:36 -07002323out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002324 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2325
2326 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002327}
2328
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002329struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002330 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331{
David S. Miller87a11572011-12-06 17:04:13 -05002332 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 struct rt6_info *rt;
2334 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002335 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
David S. Miller38308472011-12-03 18:02:47 -05002337 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002338 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
Martin KaFai Lauad706862015-08-14 11:05:52 -07002340 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002341 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002343 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 goto out;
2345 }
2346
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002347 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002348 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002349 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002350 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002351 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002352 rt->rt6i_dst.plen = 128;
2353 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002354 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
Ido Schimmel4c981e22018-01-07 12:45:04 +02002356 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002357 * do proper release of the net_device
2358 */
2359 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002360 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
David S. Miller87a11572011-12-06 17:04:13 -05002362 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364out:
David S. Miller87a11572011-12-06 17:04:13 -05002365 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366}
2367
Daniel Lezcano569d3642008-01-18 03:56:57 -08002368static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002370 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002371 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2372 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2373 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2374 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2375 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002376 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
Eric Dumazetfc66f952010-10-08 06:37:34 +00002378 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002379 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002380 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 goto out;
2382
Benjamin Thery6891a342008-03-04 13:49:47 -08002383 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002384 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002385 entries = dst_entries_get_slow(ops);
2386 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002387 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002389 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002390 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391}
2392
Florian Westphale715b6d2015-01-05 23:57:44 +01002393static int ip6_convert_metrics(struct mx6_config *mxc,
2394 const struct fib6_config *cfg)
2395{
Stephen Hemminger6670e152017-11-14 08:25:49 -08002396 struct net *net = cfg->fc_nlinfo.nl_net;
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02002397 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01002398 struct nlattr *nla;
2399 int remaining;
2400 u32 *mp;
2401
Ian Morris63159f22015-03-29 14:00:04 +01002402 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01002403 return 0;
2404
2405 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
2406 if (unlikely(!mp))
2407 return -ENOMEM;
2408
2409 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
2410 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02002411 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01002412
Daniel Borkmann1bb14802015-08-31 15:58:45 +02002413 if (!type)
2414 continue;
2415 if (unlikely(type > RTAX_MAX))
2416 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01002417
Daniel Borkmann1bb14802015-08-31 15:58:45 +02002418 if (type == RTAX_CC_ALGO) {
2419 char tmp[TCP_CA_NAME_MAX];
2420
2421 nla_strlcpy(tmp, nla, sizeof(tmp));
Stephen Hemminger6670e152017-11-14 08:25:49 -08002422 val = tcp_ca_get_key_by_name(net, tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02002423 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01002424 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02002425 } else {
2426 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01002427 }
Paolo Abeni626abd52016-05-13 18:33:41 +02002428 if (type == RTAX_HOPLIMIT && val > 255)
2429 val = 255;
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02002430 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
2431 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02002432
2433 mp[type - 1] = val;
2434 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01002435 }
2436
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02002437 if (ecn_ca) {
2438 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
2439 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
2440 }
Florian Westphale715b6d2015-01-05 23:57:44 +01002441
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02002442 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01002443 return 0;
2444 err:
2445 kfree(mp);
2446 return -EINVAL;
2447}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
David Ahern8c145862016-04-24 21:26:04 -07002449static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2450 struct fib6_config *cfg,
2451 const struct in6_addr *gw_addr)
2452{
2453 struct flowi6 fl6 = {
2454 .flowi6_oif = cfg->fc_ifindex,
2455 .daddr = *gw_addr,
2456 .saddr = cfg->fc_prefsrc,
2457 };
2458 struct fib6_table *table;
2459 struct rt6_info *rt;
David Ahernd5d32e42016-10-24 12:27:23 -07002460 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahern8c145862016-04-24 21:26:04 -07002461
2462 table = fib6_get_table(net, cfg->fc_table);
2463 if (!table)
2464 return NULL;
2465
2466 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2467 flags |= RT6_LOOKUP_F_HAS_SADDR;
2468
2469 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
2470
2471 /* if table lookup failed, fall back to full lookup */
2472 if (rt == net->ipv6.ip6_null_entry) {
2473 ip6_rt_put(rt);
2474 rt = NULL;
2475 }
2476
2477 return rt;
2478}
2479
David Ahern333c4302017-05-21 10:12:04 -06002480static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2481 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482{
Daniel Lezcano55786892008-03-04 13:47:47 -08002483 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 struct rt6_info *rt = NULL;
2485 struct net_device *dev = NULL;
2486 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002487 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002489 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
David Ahern557c44b2017-04-19 14:19:43 -07002491 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002492 if (cfg->fc_flags & RTF_PCPU) {
2493 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002494 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002495 }
David Ahern557c44b2017-04-19 14:19:43 -07002496
Wei Wang2ea23522017-10-27 17:30:12 -07002497 /* RTF_CACHE is an internal flag; can not be set by userspace */
2498 if (cfg->fc_flags & RTF_CACHE) {
2499 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2500 goto out;
2501 }
2502
David Ahernd5d531c2017-05-21 10:12:05 -06002503 if (cfg->fc_dst_len > 128) {
2504 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002505 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002506 }
2507 if (cfg->fc_src_len > 128) {
2508 NL_SET_ERR_MSG(extack, "Invalid source address length");
2509 goto out;
2510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002512 if (cfg->fc_src_len) {
2513 NL_SET_ERR_MSG(extack,
2514 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002515 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002518 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002520 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (!dev)
2522 goto out;
2523 idev = in6_dev_get(dev);
2524 if (!idev)
2525 goto out;
2526 }
2527
Thomas Graf86872cb2006-08-22 00:01:08 -07002528 if (cfg->fc_metric == 0)
2529 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
Matti Vaittinend71314b2011-11-14 00:14:49 +00002531 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002532 if (cfg->fc_nlinfo.nlh &&
2533 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00002534 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002535 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00002536 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00002537 table = fib6_new_table(net, cfg->fc_table);
2538 }
2539 } else {
2540 table = fib6_new_table(net, cfg->fc_table);
2541 }
David S. Miller38308472011-12-03 18:02:47 -05002542
2543 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002544 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07002545
Martin KaFai Lauad706862015-08-14 11:05:52 -07002546 rt = ip6_dst_alloc(net, NULL,
2547 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
David S. Miller38308472011-12-03 18:02:47 -05002549 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 err = -ENOMEM;
2551 goto out;
2552 }
2553
Gao feng1716a962012-04-06 00:13:10 +00002554 if (cfg->fc_flags & RTF_EXPIRES)
2555 rt6_set_expires(rt, jiffies +
2556 clock_t_to_jiffies(cfg->fc_expires));
2557 else
2558 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
Thomas Graf86872cb2006-08-22 00:01:08 -07002560 if (cfg->fc_protocol == RTPROT_UNSPEC)
2561 cfg->fc_protocol = RTPROT_BOOT;
2562 rt->rt6i_protocol = cfg->fc_protocol;
2563
2564 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
2566 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07002567 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002568 else if (cfg->fc_flags & RTF_LOCAL)
2569 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 else
Changli Gaod8d1f302010-06-10 23:31:35 -07002571 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
Changli Gaod8d1f302010-06-10 23:31:35 -07002573 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002575 if (cfg->fc_encap) {
2576 struct lwtunnel_state *lwtstate;
2577
David Ahern30357d72017-01-30 12:07:37 -08002578 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07002579 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06002580 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002581 if (err)
2582 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02002583 rt->dst.lwtstate = lwtstate_get(lwtstate);
2584 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
2585 rt->dst.lwtstate->orig_output = rt->dst.output;
2586 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07002587 }
Jiri Benc61adedf2015-08-20 13:56:25 +02002588 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
2589 rt->dst.lwtstate->orig_input = rt->dst.input;
2590 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07002591 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002592 }
2593
Thomas Graf86872cb2006-08-22 00:01:08 -07002594 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
2595 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07002596 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01002597 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01002598
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07002600 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
2601 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602#endif
2603
Thomas Graf86872cb2006-08-22 00:01:08 -07002604 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
2606 /* We cannot add true routes via loopback here,
2607 they would result in kernel looping; promote them to reject routes
2608 */
Thomas Graf86872cb2006-08-22 00:01:08 -07002609 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05002610 (dev && (dev->flags & IFF_LOOPBACK) &&
2611 !(addr_type & IPV6_ADDR_LOOPBACK) &&
2612 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08002614 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 if (dev) {
2616 dev_put(dev);
2617 in6_dev_put(idev);
2618 }
Daniel Lezcano55786892008-03-04 13:47:47 -08002619 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 dev_hold(dev);
2621 idev = in6_dev_get(dev);
2622 if (!idev) {
2623 err = -ENODEV;
2624 goto out;
2625 }
2626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002628 switch (cfg->fc_type) {
2629 case RTN_BLACKHOLE:
2630 rt->dst.error = -EINVAL;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002631 rt->dst.output = dst_discard_out;
Kamala R7150aed2013-12-02 19:55:21 +05302632 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002633 break;
2634 case RTN_PROHIBIT:
2635 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05302636 rt->dst.output = ip6_pkt_prohibit_out;
2637 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002638 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002639 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02002640 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002641 default:
Kamala R7150aed2013-12-02 19:55:21 +05302642 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02002643 : (cfg->fc_type == RTN_UNREACHABLE)
2644 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05302645 rt->dst.output = ip6_pkt_discard_out;
2646 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002647 break;
2648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 goto install_route;
2650 }
2651
Thomas Graf86872cb2006-08-22 00:01:08 -07002652 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002653 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 int gwa_type;
2655
Thomas Graf86872cb2006-08-22 00:01:08 -07002656 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02002657 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02002658
2659 /* if gw_addr is local we will fail to detect this in case
2660 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2661 * will return already-added prefix route via interface that
2662 * prefix route was assigned to, which might be non-loopback.
2663 */
2664 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02002665 if (ipv6_chk_addr_and_flags(net, gw_addr,
2666 gwa_type & IPV6_ADDR_LINKLOCAL ?
David Ahernd5d531c2017-05-21 10:12:05 -06002667 dev : NULL, 0, 0)) {
2668 NL_SET_ERR_MSG(extack, "Invalid gateway address");
Florian Westphal48ed7b22015-05-21 00:25:41 +02002669 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002670 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002671 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
David Ahern8c145862016-04-24 21:26:04 -07002674 struct rt6_info *grt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
2676 /* IPv6 strictly inhibits using not link-local
2677 addresses as nexthop address.
2678 Otherwise, router will not able to send redirects.
2679 It is very good, but in some (rare!) circumstances
2680 (SIT, PtP, NBMA NOARP links) it is handy to allow
2681 some exceptions. --ANK
Erik Nordmark96d58222016-12-03 20:57:09 -08002682 We allow IPv4-mapped nexthops to support RFC4798-type
2683 addressing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 */
Erik Nordmark96d58222016-12-03 20:57:09 -08002685 if (!(gwa_type & (IPV6_ADDR_UNICAST |
David Ahernd5d531c2017-05-21 10:12:05 -06002686 IPV6_ADDR_MAPPED))) {
2687 NL_SET_ERR_MSG(extack,
2688 "Invalid gateway address");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
Vincent Bernata435a072016-09-18 17:46:07 +02002692 if (cfg->fc_table) {
David Ahern8c145862016-04-24 21:26:04 -07002693 grt = ip6_nh_lookup_table(net, cfg, gw_addr);
2694
Vincent Bernata435a072016-09-18 17:46:07 +02002695 if (grt) {
2696 if (grt->rt6i_flags & RTF_GATEWAY ||
2697 (dev && dev != grt->dst.dev)) {
2698 ip6_rt_put(grt);
2699 grt = NULL;
2700 }
2701 }
2702 }
2703
David Ahern8c145862016-04-24 21:26:04 -07002704 if (!grt)
2705 grt = rt6_lookup(net, gw_addr, NULL,
2706 cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
2708 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05002709 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 goto out;
2711 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05002712 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002713 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 goto out;
2715 }
2716 } else {
David S. Millerd1918542011-12-28 20:19:20 -05002717 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 idev = grt->rt6i_idev;
2719 dev_hold(dev);
2720 in6_dev_hold(grt->rt6i_idev);
2721 }
David S. Miller38308472011-12-03 18:02:47 -05002722 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00002724 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725
2726 if (err)
2727 goto out;
2728 }
2729 err = -EINVAL;
David Ahernd5d531c2017-05-21 10:12:05 -06002730 if (!dev) {
2731 NL_SET_ERR_MSG(extack, "Egress device not specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002733 } else if (dev->flags & IFF_LOOPBACK) {
2734 NL_SET_ERR_MSG(extack,
2735 "Egress device can not be loopback device for this route");
2736 goto out;
2737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 }
2739
2740 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002741 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 goto out;
2743
Daniel Walterc3968a82011-04-13 21:10:57 +00002744 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2745 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06002746 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00002747 err = -EINVAL;
2748 goto out;
2749 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002750 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00002751 rt->rt6i_prefsrc.plen = 128;
2752 } else
2753 rt->rt6i_prefsrc.plen = 0;
2754
Thomas Graf86872cb2006-08-22 00:01:08 -07002755 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756
2757install_route:
Ido Schimmel5609b802018-01-07 12:45:06 +02002758 if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
2759 !netif_carrier_ok(dev))
2760 rt->rt6i_nh_flags |= RTNH_F_LINKDOWN;
Changli Gaod8d1f302010-06-10 23:31:35 -07002761 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07002763 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002764
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002765 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002766
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002767 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768out:
2769 if (dev)
2770 dev_put(dev);
2771 if (idev)
2772 in6_dev_put(idev);
Wei Wang587fea72017-06-17 10:42:36 -07002773 if (rt)
2774 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002775
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002776 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002777}
2778
David Ahern333c4302017-05-21 10:12:04 -06002779int ip6_route_add(struct fib6_config *cfg,
2780 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002781{
2782 struct mx6_config mxc = { .mx = NULL, };
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002783 struct rt6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002784 int err;
2785
David Ahern333c4302017-05-21 10:12:04 -06002786 rt = ip6_route_info_create(cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002787 if (IS_ERR(rt)) {
2788 err = PTR_ERR(rt);
2789 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002790 goto out;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002791 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002792
2793 err = ip6_convert_metrics(&mxc, cfg);
2794 if (err)
2795 goto out;
2796
David Ahern333c4302017-05-21 10:12:04 -06002797 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002798
2799 kfree(mxc.mx);
2800
2801 return err;
2802out:
Wei Wang587fea72017-06-17 10:42:36 -07002803 if (rt)
2804 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002805
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 return err;
2807}
2808
Thomas Graf86872cb2006-08-22 00:01:08 -07002809static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810{
2811 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002812 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002813 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Wei Wanga4c2fd72017-06-17 10:42:42 -07002815 if (rt == net->ipv6.ip6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00002816 err = -ENOENT;
2817 goto out;
2818 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002819
Thomas Grafc71099a2006-08-04 23:20:06 -07002820 table = rt->rt6i_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07002821 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002822 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07002823 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
Gao feng6825a262012-09-19 19:25:34 +00002825out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002826 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 return err;
2828}
2829
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002830int ip6_del_rt(struct rt6_info *rt)
2831{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002832 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002833 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002834 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002835 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002836}
2837
David Ahern0ae81332017-02-02 12:37:08 -08002838static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
2839{
2840 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08002841 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08002842 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08002843 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08002844 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08002845
WANG Conge3330032017-02-27 16:07:43 -08002846 if (rt == net->ipv6.ip6_null_entry)
2847 goto out_put;
David Ahern0ae81332017-02-02 12:37:08 -08002848 table = rt->rt6i_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07002849 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08002850
2851 if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
2852 struct rt6_info *sibling, *next_sibling;
2853
David Ahern16a16cd2017-02-02 12:37:11 -08002854 /* prefer to send a single notification with all hops */
2855 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
2856 if (skb) {
2857 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
2858
WANG Conge3330032017-02-27 16:07:43 -08002859 if (rt6_fill_node(net, skb, rt,
David Ahern16a16cd2017-02-02 12:37:11 -08002860 NULL, NULL, 0, RTM_DELROUTE,
2861 info->portid, seq, 0) < 0) {
2862 kfree_skb(skb);
2863 skb = NULL;
2864 } else
2865 info->skip_notify = 1;
2866 }
2867
David Ahern0ae81332017-02-02 12:37:08 -08002868 list_for_each_entry_safe(sibling, next_sibling,
2869 &rt->rt6i_siblings,
2870 rt6i_siblings) {
2871 err = fib6_del(sibling, info);
2872 if (err)
WANG Conge3330032017-02-27 16:07:43 -08002873 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08002874 }
2875 }
2876
2877 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08002878out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002879 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08002880out_put:
David Ahern0ae81332017-02-02 12:37:08 -08002881 ip6_rt_put(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08002882
2883 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08002884 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08002885 info->nlh, gfp_any());
2886 }
David Ahern0ae81332017-02-02 12:37:08 -08002887 return err;
2888}
2889
David Ahern333c4302017-05-21 10:12:04 -06002890static int ip6_route_del(struct fib6_config *cfg,
2891 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892{
Wei Wang2b760fc2017-10-06 12:06:03 -07002893 struct rt6_info *rt, *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07002894 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 int err = -ESRCH;
2897
Daniel Lezcano55786892008-03-04 13:47:47 -08002898 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06002899 if (!table) {
2900 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07002901 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06002902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Wei Wang66f5d6c2017-10-06 12:06:10 -07002904 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07002905
2906 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002907 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07002908 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07002909 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002910
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07002912 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002913 if (cfg->fc_flags & RTF_CACHE) {
2914 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
2915 &cfg->fc_src);
2916 if (!rt_cache)
2917 continue;
2918 rt = rt_cache;
2919 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002920 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002921 (!rt->dst.dev ||
2922 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002924 if (cfg->fc_flags & RTF_GATEWAY &&
2925 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002927 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 continue;
Mantas Mc2ed1882016-12-16 10:30:59 +02002929 if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
2930 continue;
Wei Wangd3843fe2017-10-06 12:06:06 -07002931 if (!dst_hold_safe(&rt->dst))
2932 break;
Wei Wang66f5d6c2017-10-06 12:06:10 -07002933 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
David Ahern0ae81332017-02-02 12:37:08 -08002935 /* if gateway was specified only delete the one hop */
2936 if (cfg->fc_flags & RTF_GATEWAY)
2937 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
2938
2939 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 }
2941 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07002942 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
2944 return err;
2945}
2946
David S. Miller6700c272012-07-17 03:29:28 -07002947static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002948{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002949 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002950 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002951 struct ndisc_options ndopts;
2952 struct inet6_dev *in6_dev;
2953 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002954 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002955 int optlen, on_link;
2956 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002957
Simon Horman29a3cad2013-05-28 20:34:26 +00002958 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002959 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002960
2961 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002962 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002963 return;
2964 }
2965
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002966 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002967
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002968 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002969 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002970 return;
2971 }
2972
David S. Miller6e157b62012-07-12 00:05:02 -07002973 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002974 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002975 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002976 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002977 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002978 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002979 return;
2980 }
2981
2982 in6_dev = __in6_dev_get(skb->dev);
2983 if (!in6_dev)
2984 return;
2985 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2986 return;
2987
2988 /* RFC2461 8.1:
2989 * The IP source address of the Redirect MUST be the same as the current
2990 * first-hop router for the specified ICMP Destination Address.
2991 */
2992
Alexander Aringf997c552016-06-15 21:20:23 +02002993 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002994 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2995 return;
2996 }
David S. Miller6e157b62012-07-12 00:05:02 -07002997
2998 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002999 if (ndopts.nd_opts_tgt_lladdr) {
3000 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3001 skb->dev);
3002 if (!lladdr) {
3003 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3004 return;
3005 }
3006 }
3007
David S. Miller6e157b62012-07-12 00:05:02 -07003008 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003009 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003010 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3011 return;
3012 }
3013
3014 /* Redirect received -> path was valid.
3015 * Look, redirects are sent only in response to data packets,
3016 * so that this nexthop apparently is reachable. --ANK
3017 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003018 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003019
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003020 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003021 if (!neigh)
3022 return;
3023
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 /*
3025 * We have finally decided to accept it.
3026 */
3027
Alexander Aringf997c552016-06-15 21:20:23 +02003028 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3030 NEIGH_UPDATE_F_OVERRIDE|
3031 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003032 NEIGH_UPDATE_F_ISROUTER)),
3033 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07003035 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003036 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 goto out;
3038
3039 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3040 if (on_link)
3041 nrt->rt6i_flags &= ~RTF_GATEWAY;
3042
Xin Longb91d5322017-08-03 14:13:46 +08003043 nrt->rt6i_protocol = RTPROT_REDIRECT;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003044 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
Wei Wang2b760fc2017-10-06 12:06:03 -07003046 /* No need to remove rt from the exception table if rt is
3047 * a cached route because rt6_insert_exception() will
3048 * takes care of it
3049 */
3050 if (rt6_insert_exception(nrt, rt)) {
3051 dst_release_immediate(&nrt->dst);
3052 goto out;
3053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054
Changli Gaod8d1f302010-06-10 23:31:35 -07003055 netevent.old = &rt->dst;
3056 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003057 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003058 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003059 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3060
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061out:
David S. Millere8599ff2012-07-11 23:43:53 -07003062 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003063}
3064
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 * Misc support functions
3067 */
3068
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003069static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
3070{
David Miller3a2232e2017-11-28 15:40:40 -05003071 BUG_ON(from->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003072
3073 rt->rt6i_flags &= ~RTF_EXPIRES;
3074 dst_hold(&from->dst);
David Miller3a2232e2017-11-28 15:40:40 -05003075 rt->from = from;
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003076 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
3077}
3078
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07003079static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07003081 rt->dst.input = ort->dst.input;
3082 rt->dst.output = ort->dst.output;
3083 rt->rt6i_dst = ort->rt6i_dst;
3084 rt->dst.error = ort->dst.error;
3085 rt->rt6i_idev = ort->rt6i_idev;
3086 if (rt->rt6i_idev)
3087 in6_dev_hold(rt->rt6i_idev);
3088 rt->dst.lastuse = jiffies;
3089 rt->rt6i_gateway = ort->rt6i_gateway;
3090 rt->rt6i_flags = ort->rt6i_flags;
3091 rt6_set_from(rt, ort);
3092 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07003094 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07003096 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
3097 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02003098 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099}
3100
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003101#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003102static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003103 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003104 const struct in6_addr *gwaddr,
3105 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003106{
David Ahern830218c2016-10-24 10:52:35 -07003107 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3108 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003109 struct fib6_node *fn;
3110 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003111 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003112
David Ahern830218c2016-10-24 10:52:35 -07003113 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003114 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003115 return NULL;
3116
Wei Wang66f5d6c2017-10-06 12:06:10 -07003117 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003118 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003119 if (!fn)
3120 goto out;
3121
Wei Wang66f5d6c2017-10-06 12:06:10 -07003122 for_each_fib6_node_rt_rcu(fn) {
David S. Millerd1918542011-12-28 20:19:20 -05003123 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003124 continue;
3125 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
3126 continue;
3127 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
3128 continue;
Wei Wangd3843fe2017-10-06 12:06:06 -07003129 ip6_hold_safe(NULL, &rt, false);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003130 break;
3131 }
3132out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003133 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003134 return rt;
3135}
3136
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003137static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003138 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003139 const struct in6_addr *gwaddr,
3140 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003141 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003142{
Thomas Graf86872cb2006-08-22 00:01:08 -07003143 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003144 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003145 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003146 .fc_dst_len = prefixlen,
3147 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3148 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003149 .fc_protocol = RTPROT_RA,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003150 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003151 .fc_nlinfo.nlh = NULL,
3152 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003153 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003154
David Ahern830218c2016-10-24 10:52:35 -07003155 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003156 cfg.fc_dst = *prefix;
3157 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003158
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003159 /* We should treat it as a default route if prefix length is 0. */
3160 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003161 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003162
David Ahern333c4302017-05-21 10:12:04 -06003163 ip6_route_add(&cfg, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003164
David Ahern830218c2016-10-24 10:52:35 -07003165 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003166}
3167#endif
3168
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003169struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003170{
David Ahern830218c2016-10-24 10:52:35 -07003171 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003173 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
David Ahern830218c2016-10-24 10:52:35 -07003175 table = fib6_get_table(dev_net(dev), tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003176 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003177 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
Wei Wang66f5d6c2017-10-06 12:06:10 -07003179 rcu_read_lock();
3180 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David S. Millerd1918542011-12-28 20:19:20 -05003181 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08003182 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 ipv6_addr_equal(&rt->rt6i_gateway, addr))
3184 break;
3185 }
3186 if (rt)
Wei Wangd3843fe2017-10-06 12:06:06 -07003187 ip6_hold_safe(NULL, &rt, false);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003188 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 return rt;
3190}
3191
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003192struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003193 struct net_device *dev,
3194 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195{
Thomas Graf86872cb2006-08-22 00:01:08 -07003196 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003197 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003198 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003199 .fc_ifindex = dev->ifindex,
3200 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3201 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003202 .fc_protocol = RTPROT_RA,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003203 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003204 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003205 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07003206 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003208 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
David Ahern333c4302017-05-21 10:12:04 -06003210 if (!ip6_route_add(&cfg, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003211 struct fib6_table *table;
3212
3213 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3214 if (table)
3215 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 return rt6_get_dflt_router(gwaddr, dev);
3219}
3220
David Ahern830218c2016-10-24 10:52:35 -07003221static void __rt6_purge_dflt_routers(struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222{
3223 struct rt6_info *rt;
3224
3225restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003226 rcu_read_lock();
3227 for_each_fib6_node_rt_rcu(&table->tb6_root) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00003228 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
3229 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Wei Wangd3843fe2017-10-06 12:06:06 -07003230 if (dst_hold_safe(&rt->dst)) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003231 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07003232 ip6_del_rt(rt);
3233 } else {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003234 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07003235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 goto restart;
3237 }
3238 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003239 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003240
3241 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3242}
3243
3244void rt6_purge_dflt_routers(struct net *net)
3245{
3246 struct fib6_table *table;
3247 struct hlist_head *head;
3248 unsigned int h;
3249
3250 rcu_read_lock();
3251
3252 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3253 head = &net->ipv6.fib_table_hash[h];
3254 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3255 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
3256 __rt6_purge_dflt_routers(table);
3257 }
3258 }
3259
3260 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261}
3262
Daniel Lezcano55786892008-03-04 13:47:47 -08003263static void rtmsg_to_fib6_config(struct net *net,
3264 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003265 struct fib6_config *cfg)
3266{
3267 memset(cfg, 0, sizeof(*cfg));
3268
David Ahernca254492015-10-12 11:47:10 -07003269 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3270 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07003271 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
3272 cfg->fc_metric = rtmsg->rtmsg_metric;
3273 cfg->fc_expires = rtmsg->rtmsg_info;
3274 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
3275 cfg->fc_src_len = rtmsg->rtmsg_src_len;
3276 cfg->fc_flags = rtmsg->rtmsg_flags;
3277
Daniel Lezcano55786892008-03-04 13:47:47 -08003278 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08003279
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003280 cfg->fc_dst = rtmsg->rtmsg_dst;
3281 cfg->fc_src = rtmsg->rtmsg_src;
3282 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07003283}
3284
Daniel Lezcano55786892008-03-04 13:47:47 -08003285int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286{
Thomas Graf86872cb2006-08-22 00:01:08 -07003287 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 struct in6_rtmsg rtmsg;
3289 int err;
3290
Ian Morris67ba4152014-08-24 21:53:10 +01003291 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 case SIOCADDRT: /* Add a route */
3293 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003294 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 return -EPERM;
3296 err = copy_from_user(&rtmsg, arg,
3297 sizeof(struct in6_rtmsg));
3298 if (err)
3299 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003300
Daniel Lezcano55786892008-03-04 13:47:47 -08003301 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003302
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 rtnl_lock();
3304 switch (cmd) {
3305 case SIOCADDRT:
David Ahern333c4302017-05-21 10:12:04 -06003306 err = ip6_route_add(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 break;
3308 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003309 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 break;
3311 default:
3312 err = -EINVAL;
3313 }
3314 rtnl_unlock();
3315
3316 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
3319 return -EINVAL;
3320}
3321
3322/*
3323 * Drop the packet on the floor
3324 */
3325
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003326static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003328 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003329 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003330 switch (ipstats_mib_noroutes) {
3331 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003332 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003333 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003334 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3335 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003336 break;
3337 }
3338 /* FALLTHROUGH */
3339 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003340 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3341 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003342 break;
3343 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003344 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 kfree_skb(skb);
3346 return 0;
3347}
3348
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003349static int ip6_pkt_discard(struct sk_buff *skb)
3350{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003351 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003352}
3353
Eric W. Biedermanede20592015-10-07 16:48:47 -05003354static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355{
Eric Dumazetadf30902009-06-02 05:19:30 +00003356 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003357 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358}
3359
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003360static int ip6_pkt_prohibit(struct sk_buff *skb)
3361{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003362 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003363}
3364
Eric W. Biedermanede20592015-10-07 16:48:47 -05003365static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003366{
Eric Dumazetadf30902009-06-02 05:19:30 +00003367 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003368 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003369}
3370
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371/*
3372 * Allocate a dst for local (unicast / anycast) address.
3373 */
3374
3375struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
3376 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05003377 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378{
David Ahernca254492015-10-12 11:47:10 -07003379 u32 tb_id;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003380 struct net *net = dev_net(idev->dev);
David Ahern4832c302017-08-17 12:17:20 -07003381 struct net_device *dev = idev->dev;
David Ahern5f02ce242016-09-10 12:09:54 -07003382 struct rt6_info *rt;
3383
David Ahern5f02ce242016-09-10 12:09:54 -07003384 rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01003385 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return ERR_PTR(-ENOMEM);
3387
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 in6_dev_hold(idev);
3389
David S. Miller11d53b42011-06-24 15:23:34 -07003390 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07003391 rt->dst.input = ip6_input;
3392 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
David Ahern94b5e0f2017-02-02 08:52:21 -08003395 rt->rt6i_protocol = RTPROT_KERNEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09003397 if (anycast)
3398 rt->rt6i_flags |= RTF_ANYCAST;
3399 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
Julian Anastasov550bab42013-10-20 15:43:04 +03003402 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003403 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 rt->rt6i_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003405 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
3406 rt->rt6i_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 return rt;
3409}
3410
Daniel Walterc3968a82011-04-13 21:10:57 +00003411/* remove deleted ip from prefsrc entries */
3412struct arg_dev_net_ip {
3413 struct net_device *dev;
3414 struct net *net;
3415 struct in6_addr *addr;
3416};
3417
3418static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
3419{
3420 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3421 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3422 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3423
David S. Millerd1918542011-12-28 20:19:20 -05003424 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00003425 rt != net->ipv6.ip6_null_entry &&
3426 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003427 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003428 /* remove prefsrc entry */
3429 rt->rt6i_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003430 /* need to update cache as well */
3431 rt6_exceptions_remove_prefsrc(rt);
3432 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003433 }
3434 return 0;
3435}
3436
3437void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3438{
3439 struct net *net = dev_net(ifp->idev->dev);
3440 struct arg_dev_net_ip adni = {
3441 .dev = ifp->idev->dev,
3442 .net = net,
3443 .addr = &ifp->addr,
3444 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003445 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003446}
3447
Duan Jiongbe7a0102014-05-15 15:56:14 +08003448#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003449
3450/* Remove routers and update dst entries when gateway turn into host. */
3451static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
3452{
3453 struct in6_addr *gateway = (struct in6_addr *)arg;
3454
Wei Wang2b760fc2017-10-06 12:06:03 -07003455 if (((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
3456 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003457 return -1;
3458 }
Wei Wangb16cb452017-10-06 12:06:00 -07003459
3460 /* Further clean up cached routes in exception table.
3461 * This is needed because cached route may have a different
3462 * gateway than its 'parent' in the case of an ip redirect.
3463 */
3464 rt6_exceptions_clean_tohost(rt, gateway);
3465
Duan Jiongbe7a0102014-05-15 15:56:14 +08003466 return 0;
3467}
3468
3469void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3470{
3471 fib6_clean_all(net, fib6_clean_tohost, gateway);
3472}
3473
Ido Schimmel2127d952018-01-07 12:45:03 +02003474struct arg_netdev_event {
3475 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003476 union {
3477 unsigned int nh_flags;
3478 unsigned long event;
3479 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003480};
3481
3482static int fib6_ifup(struct rt6_info *rt, void *p_arg)
3483{
3484 const struct arg_netdev_event *arg = p_arg;
3485 const struct net *net = dev_net(arg->dev);
3486
3487 if (rt != net->ipv6.ip6_null_entry && rt->dst.dev == arg->dev)
3488 rt->rt6i_nh_flags &= ~arg->nh_flags;
3489
3490 return 0;
3491}
3492
3493void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3494{
3495 struct arg_netdev_event arg = {
3496 .dev = dev,
3497 .nh_flags = nh_flags,
3498 };
3499
3500 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3501 arg.nh_flags |= RTNH_F_LINKDOWN;
3502
3503 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3504}
3505
David Aherna1a22c12017-01-18 07:40:36 -08003506/* called with write lock held for table with rt */
Ido Schimmel4c981e22018-01-07 12:45:04 +02003507static int fib6_ifdown(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508{
Ido Schimmel4c981e22018-01-07 12:45:04 +02003509 const struct arg_netdev_event *arg = p_arg;
3510 const struct net_device *dev = arg->dev;
3511 const struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003512
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003513 if (rt->dst.dev != dev || rt == net->ipv6.ip6_null_entry)
3514 return 0;
3515
3516 switch (arg->event) {
3517 case NETDEV_UNREGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 return -1;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003519 case NETDEV_DOWN:
3520 if (rt->rt6i_nsiblings == 0 ||
3521 !rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3522 return -1;
3523 rt->rt6i_nh_flags |= RTNH_F_DEAD;
3524 /* fall through */
3525 case NETDEV_CHANGE:
3526 if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST))
3527 break;
3528 rt->rt6i_nh_flags |= RTNH_F_LINKDOWN;
3529 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02003530 }
David S. Millerc159d302011-12-26 15:24:36 -05003531
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 return 0;
3533}
3534
Ido Schimmel27c6fa72018-01-07 12:45:05 +02003535void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536{
Ido Schimmel4c981e22018-01-07 12:45:04 +02003537 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003538 .dev = dev,
Ido Schimmel4c981e22018-01-07 12:45:04 +02003539 .event = event,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003540 };
3541
Ido Schimmel4c981e22018-01-07 12:45:04 +02003542 fib6_clean_all(dev_net(dev), fib6_ifdown, &arg);
3543}
3544
3545void rt6_disable_ip(struct net_device *dev, unsigned long event)
3546{
3547 rt6_sync_down_dev(dev, event);
3548 rt6_uncached_list_flush_dev(dev_net(dev), dev);
3549 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550}
3551
Eric Dumazet95c96172012-04-15 05:58:06 +00003552struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00003554 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555};
3556
3557static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
3558{
3559 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
3560 struct inet6_dev *idev;
3561
3562 /* In IPv6 pmtu discovery is not optional,
3563 so that RTAX_MTU lock cannot disable it.
3564 We still use this lock to block changes
3565 caused by addrconf/ndisc.
3566 */
3567
3568 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05003569 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 return 0;
3571
3572 /* For administrative MTU increase, there is no way to discover
3573 IPv6 PMTU increase, so PMTU increase should be updated here.
3574 Since RFC 1981 doesn't include administrative MTU increase
3575 update PMTU increase is a MUST. (i.e. jumbo frame)
3576 */
3577 /*
3578 If new MTU is less than route PMTU, this new MTU will be the
3579 lowest MTU in the path, update the route PMTU to reflect PMTU
3580 decreases; if new MTU is greater than route PMTU, and the
3581 old MTU is the lowest MTU in the path, update the route PMTU
3582 to reflect the increase. In this case if the other nodes' MTU
3583 also have the lowest MTU, TOO BIG MESSAGE will be lead to
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01003584 PMTU discovery.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 */
David S. Millerd1918542011-12-28 20:19:20 -05003586 if (rt->dst.dev == arg->dev &&
Maciej Żenczykowskifb56be82016-11-04 14:51:54 -07003587 dst_metric_raw(&rt->dst, RTAX_MTU) &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003588 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07003589 spin_lock_bh(&rt6_exception_lock);
Wei Wang2b760fc2017-10-06 12:06:03 -07003590 if (dst_mtu(&rt->dst) >= arg->mtu ||
3591 (dst_mtu(&rt->dst) < arg->mtu &&
3592 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003593 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
3594 }
Wei Wangf5bbe7e2017-10-06 12:05:59 -07003595 rt6_exceptions_update_pmtu(rt, arg->mtu);
3596 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07003597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 return 0;
3599}
3600
Eric Dumazet95c96172012-04-15 05:58:06 +00003601void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602{
Thomas Grafc71099a2006-08-04 23:20:06 -07003603 struct rt6_mtu_change_arg arg = {
3604 .dev = dev,
3605 .mtu = mtu,
3606 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
Li RongQing0c3584d2013-12-27 16:32:38 +08003608 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609}
3610
Patrick McHardyef7c79e2007-06-05 12:38:30 -07003611static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07003612 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07003613 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07003614 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07003615 [RTA_PRIORITY] = { .type = NLA_U32 },
3616 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003617 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003618 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003619 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
3620 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08003621 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09003622 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08003623 [RTA_MARK] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07003624};
3625
3626static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06003627 struct fib6_config *cfg,
3628 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629{
Thomas Graf86872cb2006-08-22 00:01:08 -07003630 struct rtmsg *rtm;
3631 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003632 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07003633 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634
Johannes Bergfceb6432017-04-12 14:34:07 +02003635 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
3636 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07003637 if (err < 0)
3638 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
Thomas Graf86872cb2006-08-22 00:01:08 -07003640 err = -EINVAL;
3641 rtm = nlmsg_data(nlh);
3642 memset(cfg, 0, sizeof(*cfg));
3643
3644 cfg->fc_table = rtm->rtm_table;
3645 cfg->fc_dst_len = rtm->rtm_dst_len;
3646 cfg->fc_src_len = rtm->rtm_src_len;
3647 cfg->fc_flags = RTF_UP;
3648 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003649 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07003650
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003651 if (rtm->rtm_type == RTN_UNREACHABLE ||
3652 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003653 rtm->rtm_type == RTN_PROHIBIT ||
3654 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07003655 cfg->fc_flags |= RTF_REJECT;
3656
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003657 if (rtm->rtm_type == RTN_LOCAL)
3658 cfg->fc_flags |= RTF_LOCAL;
3659
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07003660 if (rtm->rtm_flags & RTM_F_CLONED)
3661 cfg->fc_flags |= RTF_CACHE;
3662
Eric W. Biederman15e47302012-09-07 20:12:54 +00003663 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07003664 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003665 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07003666
3667 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003668 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07003669 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003671
3672 if (tb[RTA_DST]) {
3673 int plen = (rtm->rtm_dst_len + 7) >> 3;
3674
3675 if (nla_len(tb[RTA_DST]) < plen)
3676 goto errout;
3677
3678 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003680
3681 if (tb[RTA_SRC]) {
3682 int plen = (rtm->rtm_src_len + 7) >> 3;
3683
3684 if (nla_len(tb[RTA_SRC]) < plen)
3685 goto errout;
3686
3687 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003689
Daniel Walterc3968a82011-04-13 21:10:57 +00003690 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02003691 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00003692
Thomas Graf86872cb2006-08-22 00:01:08 -07003693 if (tb[RTA_OIF])
3694 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
3695
3696 if (tb[RTA_PRIORITY])
3697 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
3698
3699 if (tb[RTA_METRICS]) {
3700 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
3701 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003703
3704 if (tb[RTA_TABLE])
3705 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
3706
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003707 if (tb[RTA_MULTIPATH]) {
3708 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
3709 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08003710
3711 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06003712 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003713 if (err < 0)
3714 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003715 }
3716
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003717 if (tb[RTA_PREF]) {
3718 pref = nla_get_u8(tb[RTA_PREF]);
3719 if (pref != ICMPV6_ROUTER_PREF_LOW &&
3720 pref != ICMPV6_ROUTER_PREF_HIGH)
3721 pref = ICMPV6_ROUTER_PREF_MEDIUM;
3722 cfg->fc_flags |= RTF_PREF(pref);
3723 }
3724
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003725 if (tb[RTA_ENCAP])
3726 cfg->fc_encap = tb[RTA_ENCAP];
3727
David Ahern9ed59592017-01-17 14:57:36 -08003728 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003729 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
3730
David Ahernc255bd62017-05-27 16:19:27 -06003731 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003732 if (err < 0)
3733 goto errout;
3734 }
3735
Xin Long32bc2012015-12-16 17:50:11 +08003736 if (tb[RTA_EXPIRES]) {
3737 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
3738
3739 if (addrconf_finite_timeout(timeout)) {
3740 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
3741 cfg->fc_flags |= RTF_EXPIRES;
3742 }
3743 }
3744
Thomas Graf86872cb2006-08-22 00:01:08 -07003745 err = 0;
3746errout:
3747 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748}
3749
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003750struct rt6_nh {
3751 struct rt6_info *rt6_info;
3752 struct fib6_config r_cfg;
3753 struct mx6_config mxc;
3754 struct list_head next;
3755};
3756
3757static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
3758{
3759 struct rt6_nh *nh;
3760
3761 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08003762 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 -07003763 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
3764 nh->r_cfg.fc_ifindex);
3765 }
3766}
3767
3768static int ip6_route_info_append(struct list_head *rt6_nh_list,
3769 struct rt6_info *rt, struct fib6_config *r_cfg)
3770{
3771 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003772 int err = -EEXIST;
3773
3774 list_for_each_entry(nh, rt6_nh_list, next) {
3775 /* check if rt6_info already exists */
David Ahernf06b7542017-07-05 14:41:46 -06003776 if (rt6_duplicate_nexthop(nh->rt6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003777 return err;
3778 }
3779
3780 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
3781 if (!nh)
3782 return -ENOMEM;
3783 nh->rt6_info = rt;
3784 err = ip6_convert_metrics(&nh->mxc, r_cfg);
3785 if (err) {
3786 kfree(nh);
3787 return err;
3788 }
3789 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
3790 list_add_tail(&nh->next, rt6_nh_list);
3791
3792 return 0;
3793}
3794
David Ahern3b1137f2017-02-02 12:37:10 -08003795static void ip6_route_mpath_notify(struct rt6_info *rt,
3796 struct rt6_info *rt_last,
3797 struct nl_info *info,
3798 __u16 nlflags)
3799{
3800 /* if this is an APPEND route, then rt points to the first route
3801 * inserted and rt_last points to last route inserted. Userspace
3802 * wants a consistent dump of the route which starts at the first
3803 * nexthop. Since sibling routes are always added at the end of
3804 * the list, find the first sibling of the last route appended
3805 */
3806 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
3807 rt = list_first_entry(&rt_last->rt6i_siblings,
3808 struct rt6_info,
3809 rt6i_siblings);
3810 }
3811
3812 if (rt)
3813 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
3814}
3815
David Ahern333c4302017-05-21 10:12:04 -06003816static int ip6_route_multipath_add(struct fib6_config *cfg,
3817 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003818{
David Ahern3b1137f2017-02-02 12:37:10 -08003819 struct rt6_info *rt_notif = NULL, *rt_last = NULL;
3820 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003821 struct fib6_config r_cfg;
3822 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003823 struct rt6_info *rt;
3824 struct rt6_nh *err_nh;
3825 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08003826 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003827 int remaining;
3828 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003829 int err = 1;
3830 int nhn = 0;
3831 int replace = (cfg->fc_nlinfo.nlh &&
3832 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
3833 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003834
David Ahern3b1137f2017-02-02 12:37:10 -08003835 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
3836 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
3837 nlflags |= NLM_F_APPEND;
3838
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02003839 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003840 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003841
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003842 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
3843 * rt6_info structs per nexthop
3844 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003845 while (rtnh_ok(rtnh, remaining)) {
3846 memcpy(&r_cfg, cfg, sizeof(*cfg));
3847 if (rtnh->rtnh_ifindex)
3848 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3849
3850 attrlen = rtnh_attrlen(rtnh);
3851 if (attrlen > 0) {
3852 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3853
3854 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3855 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003856 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003857 r_cfg.fc_flags |= RTF_GATEWAY;
3858 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003859 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
3860 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
3861 if (nla)
3862 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003863 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003864
David Ahern333c4302017-05-21 10:12:04 -06003865 rt = ip6_route_info_create(&r_cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003866 if (IS_ERR(rt)) {
3867 err = PTR_ERR(rt);
3868 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003869 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003870 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003871
3872 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003873 if (err) {
Wei Wang587fea72017-06-17 10:42:36 -07003874 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003875 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003876 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003877
3878 rtnh = rtnh_next(rtnh, &remaining);
3879 }
3880
David Ahern3b1137f2017-02-02 12:37:10 -08003881 /* for add and replace send one notification with all nexthops.
3882 * Skip the notification in fib6_add_rt2node and send one with
3883 * the full route when done
3884 */
3885 info->skip_notify = 1;
3886
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003887 err_nh = NULL;
3888 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern3b1137f2017-02-02 12:37:10 -08003889 rt_last = nh->rt6_info;
David Ahern333c4302017-05-21 10:12:04 -06003890 err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
David Ahern3b1137f2017-02-02 12:37:10 -08003891 /* save reference to first route for notification */
3892 if (!rt_notif && !err)
3893 rt_notif = nh->rt6_info;
3894
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003895 /* nh->rt6_info is used or freed at this point, reset to NULL*/
3896 nh->rt6_info = NULL;
3897 if (err) {
3898 if (replace && nhn)
3899 ip6_print_replace_route_err(&rt6_nh_list);
3900 err_nh = nh;
3901 goto add_errout;
3902 }
3903
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003904 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02003905 * these flags after the first nexthop: if there is a collision,
3906 * we have already failed to add the first nexthop:
3907 * fib6_add_rt2node() has rejected it; when replacing, old
3908 * nexthops have been replaced by first new, the rest should
3909 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003910 */
Michal Kubeček27596472015-05-18 20:54:00 +02003911 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
3912 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003913 nhn++;
3914 }
3915
David Ahern3b1137f2017-02-02 12:37:10 -08003916 /* success ... tell user about new route */
3917 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003918 goto cleanup;
3919
3920add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08003921 /* send notification for routes that were added so that
3922 * the delete notifications sent by ip6_route_del are
3923 * coherent
3924 */
3925 if (rt_notif)
3926 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
3927
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003928 /* Delete routes that were already added */
3929 list_for_each_entry(nh, &rt6_nh_list, next) {
3930 if (err_nh == nh)
3931 break;
David Ahern333c4302017-05-21 10:12:04 -06003932 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003933 }
3934
3935cleanup:
3936 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
Wei Wang587fea72017-06-17 10:42:36 -07003937 if (nh->rt6_info)
3938 dst_release_immediate(&nh->rt6_info->dst);
Wu Fengguang52fe51f2015-09-10 06:57:12 +08003939 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003940 list_del(&nh->next);
3941 kfree(nh);
3942 }
3943
3944 return err;
3945}
3946
David Ahern333c4302017-05-21 10:12:04 -06003947static int ip6_route_multipath_del(struct fib6_config *cfg,
3948 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003949{
3950 struct fib6_config r_cfg;
3951 struct rtnexthop *rtnh;
3952 int remaining;
3953 int attrlen;
3954 int err = 1, last_err = 0;
3955
3956 remaining = cfg->fc_mp_len;
3957 rtnh = (struct rtnexthop *)cfg->fc_mp;
3958
3959 /* Parse a Multipath Entry */
3960 while (rtnh_ok(rtnh, remaining)) {
3961 memcpy(&r_cfg, cfg, sizeof(*cfg));
3962 if (rtnh->rtnh_ifindex)
3963 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3964
3965 attrlen = rtnh_attrlen(rtnh);
3966 if (attrlen > 0) {
3967 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3968
3969 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3970 if (nla) {
3971 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
3972 r_cfg.fc_flags |= RTF_GATEWAY;
3973 }
3974 }
David Ahern333c4302017-05-21 10:12:04 -06003975 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003976 if (err)
3977 last_err = err;
3978
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003979 rtnh = rtnh_next(rtnh, &remaining);
3980 }
3981
3982 return last_err;
3983}
3984
David Ahernc21ef3e2017-04-16 09:48:24 -07003985static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3986 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987{
Thomas Graf86872cb2006-08-22 00:01:08 -07003988 struct fib6_config cfg;
3989 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990
David Ahern333c4302017-05-21 10:12:04 -06003991 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003992 if (err < 0)
3993 return err;
3994
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003995 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003996 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003997 else {
3998 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06003999 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001}
4002
David Ahernc21ef3e2017-04-16 09:48:24 -07004003static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4004 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005{
Thomas Graf86872cb2006-08-22 00:01:08 -07004006 struct fib6_config cfg;
4007 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008
David Ahern333c4302017-05-21 10:12:04 -06004009 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004010 if (err < 0)
4011 return err;
4012
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004013 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004014 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004015 else
David Ahern333c4302017-05-21 10:12:04 -06004016 return ip6_route_add(&cfg, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017}
4018
David Ahernbeb1afac52017-02-02 12:37:09 -08004019static size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004020{
David Ahernbeb1afac52017-02-02 12:37:09 -08004021 int nexthop_len = 0;
4022
4023 if (rt->rt6i_nsiblings) {
4024 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4025 + NLA_ALIGN(sizeof(struct rtnexthop))
4026 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernbeb1afac52017-02-02 12:37:09 -08004027 + lwtunnel_get_encap_size(rt->dst.lwtstate);
4028
4029 nexthop_len *= rt->rt6i_nsiblings;
4030 }
4031
Thomas Graf339bf982006-11-10 14:10:15 -08004032 return NLMSG_ALIGN(sizeof(struct rtmsg))
4033 + nla_total_size(16) /* RTA_SRC */
4034 + nla_total_size(16) /* RTA_DST */
4035 + nla_total_size(16) /* RTA_GATEWAY */
4036 + nla_total_size(16) /* RTA_PREFSRC */
4037 + nla_total_size(4) /* RTA_TABLE */
4038 + nla_total_size(4) /* RTA_IIF */
4039 + nla_total_size(4) /* RTA_OIF */
4040 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004041 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004042 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004043 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004044 + nla_total_size(1) /* RTA_PREF */
David Ahernbeb1afac52017-02-02 12:37:09 -08004045 + lwtunnel_get_encap_size(rt->dst.lwtstate)
4046 + nexthop_len;
4047}
4048
4049static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004050 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004051{
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004052 if (rt->rt6i_nh_flags & RTNH_F_DEAD)
4053 *flags |= RTNH_F_DEAD;
4054
Ido Schimmel44c9f2f2018-01-07 12:45:08 +02004055 if (rt->rt6i_nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004056 *flags |= RTNH_F_LINKDOWN;
4057 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
4058 *flags |= RTNH_F_DEAD;
4059 }
4060
4061 if (rt->rt6i_flags & RTF_GATEWAY) {
4062 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
4063 goto nla_put_failure;
4064 }
4065
Ido Schimmelfe400792017-08-15 09:09:49 +02004066 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004067 *flags |= RTNH_F_OFFLOAD;
4068
David Ahern5be083c2017-03-06 15:57:31 -08004069 /* not needed for multipath encoding b/c it has a rtnexthop struct */
4070 if (!skip_oif && rt->dst.dev &&
David Ahernbeb1afac52017-02-02 12:37:09 -08004071 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
4072 goto nla_put_failure;
4073
4074 if (rt->dst.lwtstate &&
4075 lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
4076 goto nla_put_failure;
4077
4078 return 0;
4079
4080nla_put_failure:
4081 return -EMSGSIZE;
4082}
4083
David Ahern5be083c2017-03-06 15:57:31 -08004084/* add multipath next hop */
David Ahernbeb1afac52017-02-02 12:37:09 -08004085static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
4086{
4087 struct rtnexthop *rtnh;
4088 unsigned int flags = 0;
4089
4090 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4091 if (!rtnh)
4092 goto nla_put_failure;
4093
4094 rtnh->rtnh_hops = 0;
4095 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
4096
David Ahern5be083c2017-03-06 15:57:31 -08004097 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004098 goto nla_put_failure;
4099
4100 rtnh->rtnh_flags = flags;
4101
4102 /* length of rtnetlink header + attributes */
4103 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4104
4105 return 0;
4106
4107nla_put_failure:
4108 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004109}
4110
Brian Haley191cd582008-08-14 15:33:21 -07004111static int rt6_fill_node(struct net *net,
4112 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07004113 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004114 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004115 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07004117 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004119 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08004120 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07004121 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
Eric W. Biederman15e47302012-09-07 20:12:54 +00004123 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004124 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004125 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004126
4127 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 rtm->rtm_family = AF_INET6;
4129 rtm->rtm_dst_len = rt->rt6i_dst.plen;
4130 rtm->rtm_src_len = rt->rt6i_src.plen;
4131 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07004132 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07004133 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004134 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004135 table = RT6_TABLE_UNSPEC;
4136 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04004137 if (nla_put_u32(skb, RTA_TABLE, table))
4138 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004139 if (rt->rt6i_flags & RTF_REJECT) {
4140 switch (rt->dst.error) {
4141 case -EINVAL:
4142 rtm->rtm_type = RTN_BLACKHOLE;
4143 break;
4144 case -EACCES:
4145 rtm->rtm_type = RTN_PROHIBIT;
4146 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004147 case -EAGAIN:
4148 rtm->rtm_type = RTN_THROW;
4149 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004150 default:
4151 rtm->rtm_type = RTN_UNREACHABLE;
4152 break;
4153 }
4154 }
David S. Miller38308472011-12-03 18:02:47 -05004155 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004156 rtm->rtm_type = RTN_LOCAL;
David Ahern4ee39732017-03-15 18:14:33 -07004157 else if (rt->rt6i_flags & RTF_ANYCAST)
4158 rtm->rtm_type = RTN_ANYCAST;
David S. Millerd1918542011-12-28 20:19:20 -05004159 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 rtm->rtm_type = RTN_LOCAL;
4161 else
4162 rtm->rtm_type = RTN_UNICAST;
4163 rtm->rtm_flags = 0;
4164 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
4165 rtm->rtm_protocol = rt->rt6i_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166
David S. Miller38308472011-12-03 18:02:47 -05004167 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 rtm->rtm_flags |= RTM_F_CLONED;
4169
4170 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02004171 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04004172 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004173 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02004175 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004176 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177#ifdef CONFIG_IPV6_SUBTREES
4178 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004179 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004180 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004181 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004182 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02004183 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004184 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004186 if (iif) {
4187#ifdef CONFIG_IPV6_MROUTE
4188 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004189 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004190
David Ahernfd61c6b2017-01-17 15:51:07 -08004191 if (err == 0)
4192 return 0;
4193 if (err < 0)
4194 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004195 } else
4196#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004197 if (nla_put_u32(skb, RTA_IIF, iif))
4198 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004199 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04004201 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004202 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004203 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004205
Daniel Walterc3968a82011-04-13 21:10:57 +00004206 if (rt->rt6i_prefsrc.plen) {
4207 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004208 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004209 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004210 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004211 }
4212
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07004213 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
4214 if (rt->rt6i_pmtu)
4215 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
4216 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004217 goto nla_put_failure;
4218
David S. Millerc78679e2012-04-01 20:27:33 -04004219 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
4220 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004221
David Ahernbeb1afac52017-02-02 12:37:09 -08004222 /* For multipath routes, walk the siblings list and add
4223 * each as a nexthop within RTA_MULTIPATH.
4224 */
4225 if (rt->rt6i_nsiblings) {
4226 struct rt6_info *sibling, *next_sibling;
4227 struct nlattr *mp;
4228
4229 mp = nla_nest_start(skb, RTA_MULTIPATH);
4230 if (!mp)
4231 goto nla_put_failure;
4232
4233 if (rt6_add_nexthop(skb, rt) < 0)
4234 goto nla_put_failure;
4235
4236 list_for_each_entry_safe(sibling, next_sibling,
4237 &rt->rt6i_siblings, rt6i_siblings) {
4238 if (rt6_add_nexthop(skb, sibling) < 0)
4239 goto nla_put_failure;
4240 }
4241
4242 nla_nest_end(skb, mp);
4243 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004244 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004245 goto nla_put_failure;
4246 }
4247
Li Wei82539472012-07-29 16:01:30 +00004248 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004249
David S. Miller87a50692012-07-10 05:06:14 -07004250 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004251 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004253 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
4254 goto nla_put_failure;
4255
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004256
Johannes Berg053c0952015-01-16 22:09:00 +01004257 nlmsg_end(skb, nlh);
4258 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004259
4260nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004261 nlmsg_cancel(skb, nlh);
4262 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263}
4264
Patrick McHardy1b43af52006-08-10 23:11:17 -07004265int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
4267 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08004268 struct net *net = arg->net;
4269
4270 if (rt == net->ipv6.ip6_null_entry)
4271 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
Thomas Graf2d7202b2006-08-22 00:01:27 -07004273 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
4274 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08004275
4276 /* user wants prefix routes only */
4277 if (rtm->rtm_flags & RTM_F_PREFIX &&
4278 !(rt->rt6i_flags & RTF_PREFIX_RT)) {
4279 /* success since this is not a prefix route */
4280 return 1;
4281 }
4282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
David Ahern1f17e2f2017-01-26 13:54:08 -08004284 return rt6_fill_node(net,
Brian Haley191cd582008-08-14 15:33:21 -07004285 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004286 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004287 NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288}
4289
David Ahernc21ef3e2017-04-16 09:48:24 -07004290static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4291 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004293 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004294 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004295 int err, iif = 0, oif = 0;
4296 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004298 struct sk_buff *skb;
4299 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05004300 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004301 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004302
Johannes Bergfceb6432017-04-12 14:34:07 +02004303 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07004304 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004305 if (err < 0)
4306 goto errout;
4307
4308 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05004309 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004310 rtm = nlmsg_data(nlh);
4311 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004312 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004313
4314 if (tb[RTA_SRC]) {
4315 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4316 goto errout;
4317
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004318 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004319 }
4320
4321 if (tb[RTA_DST]) {
4322 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4323 goto errout;
4324
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004325 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004326 }
4327
4328 if (tb[RTA_IIF])
4329 iif = nla_get_u32(tb[RTA_IIF]);
4330
4331 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004332 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004333
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004334 if (tb[RTA_MARK])
4335 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4336
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004337 if (tb[RTA_UID])
4338 fl6.flowi6_uid = make_kuid(current_user_ns(),
4339 nla_get_u32(tb[RTA_UID]));
4340 else
4341 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4342
Thomas Grafab364a62006-08-22 00:01:47 -07004343 if (iif) {
4344 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004345 int flags = 0;
4346
Florian Westphal121622d2017-08-15 16:34:42 +02004347 rcu_read_lock();
4348
4349 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004350 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004351 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004352 err = -ENODEV;
4353 goto errout;
4354 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004355
4356 fl6.flowi6_iif = iif;
4357
4358 if (!ipv6_addr_any(&fl6.saddr))
4359 flags |= RT6_LOOKUP_F_HAS_SADDR;
4360
Ido Schimmel58acfd72017-12-20 12:28:25 +02004361 dst = ip6_route_input_lookup(net, dev, &fl6, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004362
4363 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004364 } else {
4365 fl6.flowi6_oif = oif;
4366
Ido Schimmel58acfd72017-12-20 12:28:25 +02004367 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004368 }
4369
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004370
4371 rt = container_of(dst, struct rt6_info, dst);
4372 if (rt->dst.error) {
4373 err = rt->dst.error;
4374 ip6_rt_put(rt);
4375 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377
WANG Cong9d6acb32017-03-01 20:48:39 -08004378 if (rt == net->ipv6.ip6_null_entry) {
4379 err = rt->dst.error;
4380 ip6_rt_put(rt);
4381 goto errout;
4382 }
4383
David S. Millerfba961a2017-12-22 11:16:31 -05004384 if (fibmatch && rt->from) {
4385 struct rt6_info *ort = rt->from;
Ido Schimmel58acfd72017-12-20 12:28:25 +02004386
4387 dst_hold(&ort->dst);
4388 ip6_rt_put(rt);
4389 rt = ort;
4390 }
4391
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004393 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004394 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07004395 err = -ENOBUFS;
4396 goto errout;
4397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398
Changli Gaod8d1f302010-06-10 23:31:35 -07004399 skb_dst_set(skb, &rt->dst);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004400 if (fibmatch)
4401 err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
4402 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
4403 nlh->nlmsg_seq, 0);
4404 else
4405 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
4406 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
4407 nlh->nlmsg_seq, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07004409 kfree_skb(skb);
4410 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 }
4412
Eric W. Biederman15e47302012-09-07 20:12:54 +00004413 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07004414errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416}
4417
Roopa Prabhu37a1d362015-09-13 10:18:33 -07004418void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
4419 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420{
4421 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08004422 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004423 u32 seq;
4424 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004426 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05004427 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07004428
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004429 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05004430 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07004431 goto errout;
4432
Brian Haley191cd582008-08-14 15:33:21 -07004433 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004434 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08004435 if (err < 0) {
4436 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
4437 WARN_ON(err == -EMSGSIZE);
4438 kfree_skb(skb);
4439 goto errout;
4440 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00004441 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08004442 info->nlh, gfp_any());
4443 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07004444errout:
4445 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08004446 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447}
4448
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004449static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00004450 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004451{
Jiri Pirko351638e2013-05-28 01:30:21 +00004452 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09004453 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004454
WANG Cong242d3a42017-05-08 10:12:13 -07004455 if (!(dev->flags & IFF_LOOPBACK))
4456 return NOTIFY_OK;
4457
4458 if (event == NETDEV_REGISTER) {
Changli Gaod8d1f302010-06-10 23:31:35 -07004459 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004460 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
4461#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07004462 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004463 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07004464 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004465 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
4466#endif
WANG Cong76da0702017-06-20 11:42:27 -07004467 } else if (event == NETDEV_UNREGISTER &&
4468 dev->reg_state != NETREG_UNREGISTERED) {
4469 /* NETDEV_UNREGISTER could be fired for multiple times by
4470 * netdev_wait_allrefs(). Make sure we only call this once.
4471 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07004472 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07004473#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07004474 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
4475 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07004476#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004477 }
4478
4479 return NOTIFY_OK;
4480}
4481
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482/*
4483 * /proc
4484 */
4485
4486#ifdef CONFIG_PROC_FS
4487
Alexey Dobriyan33120b32007-11-06 05:27:11 -08004488static const struct file_operations ipv6_route_proc_fops = {
4489 .owner = THIS_MODULE,
4490 .open = ipv6_route_open,
4491 .read = seq_read,
4492 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02004493 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08004494};
4495
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496static int rt6_stats_seq_show(struct seq_file *seq, void *v)
4497{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004498 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004500 net->ipv6.rt6_stats->fib_nodes,
4501 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07004502 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004503 net->ipv6.rt6_stats->fib_rt_entries,
4504 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00004505 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004506 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507
4508 return 0;
4509}
4510
4511static int rt6_stats_seq_open(struct inode *inode, struct file *file)
4512{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07004513 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08004514}
4515
Arjan van de Ven9a321442007-02-12 00:55:35 -08004516static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 .owner = THIS_MODULE,
4518 .open = rt6_stats_seq_open,
4519 .read = seq_read,
4520 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07004521 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522};
4523#endif /* CONFIG_PROC_FS */
4524
4525#ifdef CONFIG_SYSCTL
4526
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527static
Joe Perchesfe2c6332013-06-11 23:04:25 -07004528int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 void __user *buffer, size_t *lenp, loff_t *ppos)
4530{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004531 struct net *net;
4532 int delay;
4533 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004535
4536 net = (struct net *)ctl->extra1;
4537 delay = net->ipv6.sysctl.flush_delay;
4538 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02004539 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004540 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541}
4542
Joe Perchesfe2c6332013-06-11 23:04:25 -07004543struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004544 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08004546 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07004548 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004549 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 },
4551 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004553 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 .maxlen = sizeof(int),
4555 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004556 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 },
4558 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08004560 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 .maxlen = sizeof(int),
4562 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004563 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 },
4565 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08004567 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 .maxlen = sizeof(int),
4569 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004570 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 },
4572 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08004574 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 .maxlen = sizeof(int),
4576 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004577 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 },
4579 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08004581 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 .maxlen = sizeof(int),
4583 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004584 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 },
4586 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08004588 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 .maxlen = sizeof(int),
4590 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07004591 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 },
4593 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08004595 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 .maxlen = sizeof(int),
4597 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004598 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 },
4600 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08004602 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 .maxlen = sizeof(int),
4604 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07004605 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 },
4607 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08004609 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 .maxlen = sizeof(int),
4611 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08004612 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08004614 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615};
4616
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004617struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08004618{
4619 struct ctl_table *table;
4620
4621 table = kmemdup(ipv6_route_table_template,
4622 sizeof(ipv6_route_table_template),
4623 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09004624
4625 if (table) {
4626 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00004627 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00004628 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09004629 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
4630 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
4631 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
4632 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
4633 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
4634 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
4635 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08004636 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00004637
4638 /* Don't export sysctls to unprivileged users */
4639 if (net->user_ns != &init_user_ns)
4640 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09004641 }
4642
Daniel Lezcano760f2d02008-01-10 02:53:43 -08004643 return table;
4644}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645#endif
4646
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004647static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004648{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07004649 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004650
Alexey Dobriyan86393e52009-08-29 01:34:49 +00004651 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
4652 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004653
Eric Dumazetfc66f952010-10-08 06:37:34 +00004654 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
4655 goto out_ip6_dst_ops;
4656
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004657 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
4658 sizeof(*net->ipv6.ip6_null_entry),
4659 GFP_KERNEL);
4660 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00004661 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07004662 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004663 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
4664 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004665
4666#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02004667 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004668 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
4669 sizeof(*net->ipv6.ip6_prohibit_entry),
4670 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004671 if (!net->ipv6.ip6_prohibit_entry)
4672 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004673 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004674 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
4675 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004676
4677 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
4678 sizeof(*net->ipv6.ip6_blk_hole_entry),
4679 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004680 if (!net->ipv6.ip6_blk_hole_entry)
4681 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004682 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004683 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
4684 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004685#endif
4686
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07004687 net->ipv6.sysctl.flush_delay = 0;
4688 net->ipv6.sysctl.ip6_rt_max_size = 4096;
4689 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
4690 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
4691 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
4692 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
4693 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
4694 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
4695
Benjamin Thery6891a342008-03-04 13:49:47 -08004696 net->ipv6.ip6_rt_gc_expire = 30*HZ;
4697
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004698 ret = 0;
4699out:
4700 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004701
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004702#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4703out_ip6_prohibit_entry:
4704 kfree(net->ipv6.ip6_prohibit_entry);
4705out_ip6_null_entry:
4706 kfree(net->ipv6.ip6_null_entry);
4707#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00004708out_ip6_dst_entries:
4709 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004710out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004711 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004712}
4713
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004714static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004715{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004716 kfree(net->ipv6.ip6_null_entry);
4717#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4718 kfree(net->ipv6.ip6_prohibit_entry);
4719 kfree(net->ipv6.ip6_blk_hole_entry);
4720#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004721 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004722}
4723
Thomas Grafd1896342012-06-18 12:08:33 +00004724static int __net_init ip6_route_net_init_late(struct net *net)
4725{
4726#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00004727 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
4728 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00004729#endif
4730 return 0;
4731}
4732
4733static void __net_exit ip6_route_net_exit_late(struct net *net)
4734{
4735#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00004736 remove_proc_entry("ipv6_route", net->proc_net);
4737 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00004738#endif
4739}
4740
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004741static struct pernet_operations ip6_route_net_ops = {
4742 .init = ip6_route_net_init,
4743 .exit = ip6_route_net_exit,
4744};
4745
David S. Millerc3426b42012-06-09 16:27:05 -07004746static int __net_init ipv6_inetpeer_init(struct net *net)
4747{
4748 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
4749
4750 if (!bp)
4751 return -ENOMEM;
4752 inet_peer_base_init(bp);
4753 net->ipv6.peers = bp;
4754 return 0;
4755}
4756
4757static void __net_exit ipv6_inetpeer_exit(struct net *net)
4758{
4759 struct inet_peer_base *bp = net->ipv6.peers;
4760
4761 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07004762 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07004763 kfree(bp);
4764}
4765
David S. Miller2b823f72012-06-09 19:00:16 -07004766static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07004767 .init = ipv6_inetpeer_init,
4768 .exit = ipv6_inetpeer_exit,
4769};
4770
Thomas Grafd1896342012-06-18 12:08:33 +00004771static struct pernet_operations ip6_route_net_late_ops = {
4772 .init = ip6_route_net_init_late,
4773 .exit = ip6_route_net_exit_late,
4774};
4775
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004776static struct notifier_block ip6_route_dev_notifier = {
4777 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07004778 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004779};
4780
WANG Cong2f460932017-05-03 22:07:31 -07004781void __init ip6_route_init_special_entries(void)
4782{
4783 /* Registering of the loopback is done before this portion of code,
4784 * the loopback reference in rt6_info will not be taken, do it
4785 * manually for init_net */
4786 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
4787 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4788 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
4789 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
4790 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4791 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
4792 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4793 #endif
4794}
4795
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004796int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004798 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004799 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004800
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004801 ret = -ENOMEM;
4802 ip6_dst_ops_template.kmem_cachep =
4803 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
4804 SLAB_HWCACHE_ALIGN, NULL);
4805 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08004806 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07004807
Eric Dumazetfc66f952010-10-08 06:37:34 +00004808 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004809 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004810 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004811
David S. Millerc3426b42012-06-09 16:27:05 -07004812 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
4813 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004814 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00004815
David S. Miller7e52b332012-06-15 15:51:55 -07004816 ret = register_pernet_subsys(&ip6_route_net_ops);
4817 if (ret)
4818 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07004819
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07004820 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
4821
David S. Millere8803b62012-06-16 01:12:19 -07004822 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004823 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004824 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004825
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004826 ret = xfrm6_init();
4827 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004828 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08004829
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004830 ret = fib6_rules_init();
4831 if (ret)
4832 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08004833
Thomas Grafd1896342012-06-18 12:08:33 +00004834 ret = register_pernet_subsys(&ip6_route_net_late_ops);
4835 if (ret)
4836 goto fib6_rules_init;
4837
Florian Westphal16feebc2017-12-02 21:44:08 +01004838 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
4839 inet6_rtm_newroute, NULL, 0);
4840 if (ret < 0)
4841 goto out_register_late_subsys;
4842
4843 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
4844 inet6_rtm_delroute, NULL, 0);
4845 if (ret < 0)
4846 goto out_register_late_subsys;
4847
4848 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
4849 inet6_rtm_getroute, NULL,
4850 RTNL_FLAG_DOIT_UNLOCKED);
4851 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00004852 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004853
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004854 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004855 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00004856 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004857
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004858 for_each_possible_cpu(cpu) {
4859 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
4860
4861 INIT_LIST_HEAD(&ul->head);
4862 spin_lock_init(&ul->lock);
4863 }
4864
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004865out:
4866 return ret;
4867
Thomas Grafd1896342012-06-18 12:08:33 +00004868out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01004869 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00004870 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004871fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004872 fib6_rules_cleanup();
4873xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004874 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00004875out_fib6_init:
4876 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004877out_register_subsys:
4878 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07004879out_register_inetpeer:
4880 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00004881out_dst_entries:
4882 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004883out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004884 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004885 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886}
4887
4888void ip6_route_cleanup(void)
4889{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004890 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00004891 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07004892 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07004895 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004896 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004897 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004898 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899}