blob: 6b6528fa32921eceb51a2c3d37c5e386ca24a03f [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>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020047#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <net/snmp.h>
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#include <net/ndisc.h>
53#include <net/addrconf.h>
54#include <net/tcp.h>
55#include <linux/rtnetlink.h>
56#include <net/dst.h>
Jiri Benc904af042015-08-20 13:56:31 +020057#include <net/dst_metadata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070059#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070060#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000061#include <net/nexthop.h>
Roopa Prabhu19e42e42015-07-21 10:43:48 +020062#include <net/lwtunnel.h>
Jiri Benc904af042015-08-20 13:56:31 +020063#include <net/ip_tunnels.h>
David Ahernca254492015-10-12 11:47:10 -070064#include <net/l3mdev.h>
David Ahernb8115802015-11-19 12:24:22 -080065#include <trace/events/fib6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080067#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#ifdef CONFIG_SYSCTL
70#include <linux/sysctl.h>
71#endif
72
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020073enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010074 RT6_NUD_FAIL_HARD = -3,
75 RT6_NUD_FAIL_PROBE = -2,
76 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020077 RT6_NUD_SUCCEED = 1
78};
79
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070080static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080082static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000083static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static struct dst_entry *ip6_negative_advice(struct dst_entry *);
85static void ip6_dst_destroy(struct dst_entry *);
86static void ip6_dst_ifdown(struct dst_entry *,
87 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080088static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050091static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053092static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050093static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070095static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
96 struct sk_buff *skb, u32 mtu);
97static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
98 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070099static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200100static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
David Ahern16a16cd2017-02-02 12:37:11 -0800101static size_t rt6_nlmsg_size(struct rt6_info *rt);
102static int rt6_fill_node(struct net *net,
103 struct sk_buff *skb, struct rt6_info *rt,
104 struct in6_addr *dst, struct in6_addr *src,
105 int iif, int type, u32 portid, u32 seq,
106 unsigned int flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800108#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800109static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000110 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700111 const struct in6_addr *gwaddr,
112 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000113 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800114static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000115 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700116 const struct in6_addr *gwaddr,
117 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800118#endif
119
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700120struct uncached_list {
121 spinlock_t lock;
122 struct list_head head;
123};
124
125static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
126
127static void rt6_uncached_list_add(struct rt6_info *rt)
128{
129 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
130
131 rt->dst.flags |= DST_NOCACHE;
132 rt->rt6i_uncached_list = ul;
133
134 spin_lock_bh(&ul->lock);
135 list_add_tail(&rt->rt6i_uncached, &ul->head);
136 spin_unlock_bh(&ul->lock);
137}
138
139static void rt6_uncached_list_del(struct rt6_info *rt)
140{
141 if (!list_empty(&rt->rt6i_uncached)) {
142 struct uncached_list *ul = rt->rt6i_uncached_list;
143
144 spin_lock_bh(&ul->lock);
145 list_del(&rt->rt6i_uncached);
146 spin_unlock_bh(&ul->lock);
147 }
148}
149
150static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
151{
152 struct net_device *loopback_dev = net->loopback_dev;
153 int cpu;
154
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500155 if (dev == loopback_dev)
156 return;
157
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700158 for_each_possible_cpu(cpu) {
159 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
160 struct rt6_info *rt;
161
162 spin_lock_bh(&ul->lock);
163 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
164 struct inet6_dev *rt_idev = rt->rt6i_idev;
165 struct net_device *rt_dev = rt->dst.dev;
166
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500167 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700168 rt->rt6i_idev = in6_dev_get(loopback_dev);
169 in6_dev_put(rt_idev);
170 }
171
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500172 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700173 rt->dst.dev = loopback_dev;
174 dev_hold(rt->dst.dev);
175 dev_put(rt_dev);
176 }
177 }
178 spin_unlock_bh(&ul->lock);
179 }
180}
181
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700182static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
183{
184 return dst_metrics_write_ptr(rt->dst.from);
185}
186
David S. Miller06582542011-01-27 14:58:42 -0800187static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
188{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700189 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800190
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700191 if (rt->rt6i_flags & RTF_PCPU)
192 return rt6_pcpu_cow_metrics(rt);
193 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700194 return NULL;
195 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800196 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800197}
198
David S. Millerf894cbf2012-07-02 21:52:24 -0700199static inline const void *choose_neigh_daddr(struct rt6_info *rt,
200 struct sk_buff *skb,
201 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500202{
203 struct in6_addr *p = &rt->rt6i_gateway;
204
David S. Millera7563f32012-01-26 16:29:16 -0500205 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500206 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700207 else if (skb)
208 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500209 return daddr;
210}
211
David S. Millerf894cbf2012-07-02 21:52:24 -0700212static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
213 struct sk_buff *skb,
214 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700215{
David S. Miller39232972012-01-26 15:22:32 -0500216 struct rt6_info *rt = (struct rt6_info *) dst;
217 struct neighbour *n;
218
David S. Millerf894cbf2012-07-02 21:52:24 -0700219 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000220 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500221 if (n)
222 return n;
223 return neigh_create(&nd_tbl, daddr, dst->dev);
224}
225
Julian Anastasov63fca652017-02-06 23:14:15 +0200226static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
227{
228 struct net_device *dev = dst->dev;
229 struct rt6_info *rt = (struct rt6_info *)dst;
230
231 daddr = choose_neigh_daddr(rt, NULL, daddr);
232 if (!daddr)
233 return;
234 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
235 return;
236 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
237 return;
238 __ipv6_confirm_neigh(dev, daddr);
239}
240
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800241static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 .gc = ip6_dst_gc,
244 .gc_thresh = 1024,
245 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800246 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000247 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800248 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 .destroy = ip6_dst_destroy,
250 .ifdown = ip6_dst_ifdown,
251 .negative_advice = ip6_negative_advice,
252 .link_failure = ip6_link_failure,
253 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700254 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500255 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700256 .neigh_lookup = ip6_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200257 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258};
259
Steffen Klassertebb762f2011-11-23 02:12:51 +0000260static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800261{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000262 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
263
264 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800265}
266
David S. Miller6700c272012-07-17 03:29:28 -0700267static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
268 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700269{
270}
271
David S. Miller6700c272012-07-17 03:29:28 -0700272static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
273 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700274{
275}
276
David S. Miller14e50e52007-05-24 18:17:54 -0700277static struct dst_ops ip6_dst_blackhole_ops = {
278 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700279 .destroy = ip6_dst_destroy,
280 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000281 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800282 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700283 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700284 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700285 .cow_metrics = dst_cow_metrics_generic,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700286 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700287};
288
David S. Miller62fa8a82011-01-26 20:51:05 -0800289static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800290 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800291};
292
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000293static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700294 .dst = {
295 .__refcnt = ATOMIC_INIT(1),
296 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000297 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700298 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700299 .input = ip6_pkt_discard,
300 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 },
302 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700303 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 .rt6i_metric = ~(u32) 0,
305 .rt6i_ref = ATOMIC_INIT(1),
306};
307
Thomas Graf101367c2006-08-04 03:39:02 -0700308#ifdef CONFIG_IPV6_MULTIPLE_TABLES
309
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000310static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700311 .dst = {
312 .__refcnt = ATOMIC_INIT(1),
313 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000314 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700315 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700316 .input = ip6_pkt_prohibit,
317 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700318 },
319 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700320 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700321 .rt6i_metric = ~(u32) 0,
322 .rt6i_ref = ATOMIC_INIT(1),
323};
324
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000325static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700326 .dst = {
327 .__refcnt = ATOMIC_INIT(1),
328 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000329 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700330 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700331 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500332 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700333 },
334 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700335 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700336 .rt6i_metric = ~(u32) 0,
337 .rt6i_ref = ATOMIC_INIT(1),
338};
339
340#endif
341
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700342static void rt6_info_init(struct rt6_info *rt)
343{
344 struct dst_entry *dst = &rt->dst;
345
346 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
347 INIT_LIST_HEAD(&rt->rt6i_siblings);
348 INIT_LIST_HEAD(&rt->rt6i_uncached);
349}
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700352static struct rt6_info *__ip6_dst_alloc(struct net *net,
353 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700354 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
David S. Miller97bab732012-06-09 22:36:36 -0700356 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700357 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700358
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700359 if (rt)
360 rt6_info_init(rt);
Steffen Klassert81048912012-07-05 23:37:09 +0000361
David S. Millercf911662011-04-28 14:31:47 -0700362 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
David Ahern9ab179d2016-04-07 11:10:06 -0700365struct rt6_info *ip6_dst_alloc(struct net *net,
366 struct net_device *dev,
367 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700368{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700369 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700370
371 if (rt) {
372 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
373 if (rt->rt6i_pcpu) {
374 int cpu;
375
376 for_each_possible_cpu(cpu) {
377 struct rt6_info **p;
378
379 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
380 /* no one shares rt */
381 *p = NULL;
382 }
383 } else {
Wei Wang587fea72017-06-17 10:42:36 -0700384 dst_release_immediate(&rt->dst);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700385 return NULL;
386 }
387 }
388
389 return rt;
390}
David Ahern9ab179d2016-04-07 11:10:06 -0700391EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393static void ip6_dst_destroy(struct dst_entry *dst)
394{
395 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000396 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700397 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700399 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200400 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700401 rt6_uncached_list_del(rt);
402
403 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500404 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 rt->rt6i_idev = NULL;
406 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900407 }
Gao feng1716a962012-04-06 00:13:10 +0000408
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000409 dst->from = NULL;
410 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800411}
412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
414 int how)
415{
416 struct rt6_info *rt = (struct rt6_info *)dst;
417 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800418 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900419 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
David S. Miller97cac082012-07-02 22:43:47 -0700421 if (dev != loopback_dev) {
422 if (idev && idev->dev == dev) {
423 struct inet6_dev *loopback_idev =
424 in6_dev_get(loopback_dev);
425 if (loopback_idev) {
426 rt->rt6i_idev = loopback_idev;
427 in6_dev_put(idev);
428 }
429 }
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;
Gao feng1716a962012-04-06 00:13:10 +0000446 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000447 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000448 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000449 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000452/* Multipath route selection:
453 * Hash based function using packet header and flowlabel.
454 * Adapted from fib_info_hashfn()
455 */
456static int rt6_info_hash_nhsfn(unsigned int candidate_count,
457 const struct flowi6 *fl6)
458{
Tom Herbert644d0e62015-09-23 14:13:35 -0700459 return get_hash_from_flowi6(fl6) % candidate_count;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000460}
461
462static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200463 struct flowi6 *fl6, int oif,
464 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000465{
466 struct rt6_info *sibling, *next_sibling;
467 int route_choosen;
468
469 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
470 /* Don't change the route, if route_choosen == 0
471 * (siblings does not include ourself)
472 */
473 if (route_choosen)
474 list_for_each_entry_safe(sibling, next_sibling,
475 &match->rt6i_siblings, rt6i_siblings) {
476 route_choosen--;
477 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200478 if (rt6_score_route(sibling, oif, strict) < 0)
479 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000480 match = sibling;
481 break;
482 }
483 }
484 return match;
485}
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700488 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 */
490
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800491static inline struct rt6_info *rt6_device_match(struct net *net,
492 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000493 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700495 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
497 struct rt6_info *local = NULL;
498 struct rt6_info *sprt;
499
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900500 if (!oif && ipv6_addr_any(saddr))
501 goto out;
502
Changli Gaod8d1f302010-06-10 23:31:35 -0700503 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500504 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900505
506 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (dev->ifindex == oif)
508 return sprt;
509 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500510 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 sprt->rt6i_idev->dev->ifindex != oif) {
David Ahern17fb0b22015-09-25 15:22:54 -0600512 if (flags & RT6_LOOKUP_F_IFACE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 continue;
David Ahern17fb0b22015-09-25 15:22:54 -0600514 if (local &&
515 local->rt6i_idev->dev->ifindex == oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 continue;
517 }
518 local = sprt;
519 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900520 } else {
521 if (ipv6_chk_addr(net, saddr, dev,
522 flags & RT6_LOOKUP_F_IFACE))
523 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900527 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 if (local)
529 return local;
530
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700531 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800532 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900534out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return rt;
536}
537
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800538#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200539struct __rt6_probe_work {
540 struct work_struct work;
541 struct in6_addr target;
542 struct net_device *dev;
543};
544
545static void rt6_probe_deferred(struct work_struct *w)
546{
547 struct in6_addr mcaddr;
548 struct __rt6_probe_work *work =
549 container_of(w, struct __rt6_probe_work, work);
550
551 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800552 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200553 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100554 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200555}
556
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800557static void rt6_probe(struct rt6_info *rt)
558{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700559 struct __rt6_probe_work *work;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000560 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800561 /*
562 * Okay, this does not seem to be appropriate
563 * for now, however, we need to check if it
564 * is really so; aka Router Reachability Probing.
565 *
566 * Router Reachability Probe MUST be rate-limited
567 * to no more than one per minute.
568 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000569 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000570 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000571 rcu_read_lock_bh();
572 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
573 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700574 if (neigh->nud_state & NUD_VALID)
575 goto out;
576
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700577 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000578 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700579 if (!(neigh->nud_state & NUD_VALID) &&
580 time_after(jiffies,
581 neigh->updated +
582 rt->rt6i_idev->cnf.rtr_probe_interval)) {
583 work = kmalloc(sizeof(*work), GFP_ATOMIC);
584 if (work)
585 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200586 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000587 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700588 } else {
589 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000590 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700591
592 if (work) {
593 INIT_WORK(&work->work, rt6_probe_deferred);
594 work->target = rt->rt6i_gateway;
595 dev_hold(rt->dst.dev);
596 work->dev = rt->dst.dev;
597 schedule_work(&work->work);
598 }
599
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700600out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000601 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800602}
603#else
604static inline void rt6_probe(struct rt6_info *rt)
605{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800606}
607#endif
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800610 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700612static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
David S. Millerd1918542011-12-28 20:19:20 -0500614 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700615 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800616 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700617 if ((dev->flags & IFF_LOOPBACK) &&
618 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
619 return 1;
620 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200623static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000625 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200626 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000627
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700628 if (rt->rt6i_flags & RTF_NONEXTHOP ||
629 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200630 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000631
632 rcu_read_lock_bh();
633 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
634 if (neigh) {
635 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800636 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200637 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800638#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000639 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200640 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100641 else
642 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800643#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000644 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200645 } else {
646 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100647 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000648 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000649 rcu_read_unlock_bh();
650
Paul Marksa5a81f02012-12-03 10:26:54 +0000651 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800652}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800654static int rt6_score_route(struct rt6_info *rt, int oif,
655 int strict)
656{
Paul Marksa5a81f02012-12-03 10:26:54 +0000657 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900658
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700659 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700660 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200661 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800662#ifdef CONFIG_IPV6_ROUTER_PREF
663 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
664#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200665 if (strict & RT6_LOOKUP_F_REACHABLE) {
666 int n = rt6_check_neigh(rt);
667 if (n < 0)
668 return n;
669 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800670 return m;
671}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
David S. Millerf11e6652007-03-24 20:36:25 -0700673static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200674 int *mpri, struct rt6_info *match,
675 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800676{
David S. Millerf11e6652007-03-24 20:36:25 -0700677 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200678 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400679 struct inet6_dev *idev = rt->rt6i_idev;
680 struct net_device *dev = rt->dst.dev;
681
682 if (dev && !netif_carrier_ok(dev) &&
David Ahernd5d32e42016-10-24 12:27:23 -0700683 idev->cnf.ignore_routes_with_linkdown &&
684 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400685 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700686
687 if (rt6_check_expired(rt))
688 goto out;
689
690 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100691 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200692 match_do_rr = true;
693 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100694 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700695 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700696 }
697
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200698 if (strict & RT6_LOOKUP_F_REACHABLE)
699 rt6_probe(rt);
700
Jiri Benc7e980562013-12-11 13:48:20 +0100701 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200702 if (m > *mpri) {
703 *do_rr = match_do_rr;
704 *mpri = m;
705 match = rt;
706 }
David S. Millerf11e6652007-03-24 20:36:25 -0700707out:
708 return match;
709}
710
711static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
712 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200713 u32 metric, int oif, int strict,
714 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700715{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700716 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800717 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
David S. Millerf11e6652007-03-24 20:36:25 -0700719 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700720 cont = NULL;
721 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
722 if (rt->rt6i_metric != metric) {
723 cont = rt;
724 break;
725 }
726
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200727 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700728 }
729
730 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
731 if (rt->rt6i_metric != metric) {
732 cont = rt;
733 break;
734 }
735
736 match = find_match(rt, oif, strict, &mpri, match, do_rr);
737 }
738
739 if (match || !cont)
740 return match;
741
742 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200743 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800744
David S. Millerf11e6652007-03-24 20:36:25 -0700745 return match;
746}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800747
David S. Millerf11e6652007-03-24 20:36:25 -0700748static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
749{
750 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800751 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200752 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
David S. Millerf11e6652007-03-24 20:36:25 -0700754 rt0 = fn->rr_ptr;
755 if (!rt0)
756 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200758 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
759 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200761 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700762 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700763
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800764 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700765 if (!next || next->rt6i_metric != rt0->rt6i_metric)
766 next = fn->leaf;
767
768 if (next != rt0)
769 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 }
771
David S. Millerd1918542011-12-28 20:19:20 -0500772 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000773 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700776static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
777{
778 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
779}
780
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800781#ifdef CONFIG_IPV6_ROUTE_INFO
782int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000783 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800784{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900785 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800786 struct route_info *rinfo = (struct route_info *) opt;
787 struct in6_addr prefix_buf, *prefix;
788 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900789 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800790 struct rt6_info *rt;
791
792 if (len < sizeof(struct route_info)) {
793 return -EINVAL;
794 }
795
796 /* Sanity check for prefix_len and length */
797 if (rinfo->length > 3) {
798 return -EINVAL;
799 } else if (rinfo->prefix_len > 128) {
800 return -EINVAL;
801 } else if (rinfo->prefix_len > 64) {
802 if (rinfo->length < 2) {
803 return -EINVAL;
804 }
805 } else if (rinfo->prefix_len > 0) {
806 if (rinfo->length < 1) {
807 return -EINVAL;
808 }
809 }
810
811 pref = rinfo->route_pref;
812 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000813 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800814
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900815 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800816
817 if (rinfo->length == 3)
818 prefix = (struct in6_addr *)rinfo->prefix;
819 else {
820 /* this function is safe */
821 ipv6_addr_prefix(&prefix_buf,
822 (struct in6_addr *)rinfo->prefix,
823 rinfo->prefix_len);
824 prefix = &prefix_buf;
825 }
826
Duan Jiongf104a562013-11-08 09:56:53 +0800827 if (rinfo->prefix_len == 0)
828 rt = rt6_get_dflt_router(gwaddr, dev);
829 else
830 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700831 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800832
833 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700834 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800835 rt = NULL;
836 }
837
838 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700839 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
840 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800841 else if (rt)
842 rt->rt6i_flags = RTF_ROUTEINFO |
843 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
844
845 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000846 if (!addrconf_finite_timeout(lifetime))
847 rt6_clean_expires(rt);
848 else
849 rt6_set_expires(rt, jiffies + HZ * lifetime);
850
Amerigo Wang94e187c2012-10-29 00:13:19 +0000851 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800852 }
853 return 0;
854}
855#endif
856
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700857static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
858 struct in6_addr *saddr)
859{
860 struct fib6_node *pn;
861 while (1) {
862 if (fn->fn_flags & RTN_TL_ROOT)
863 return NULL;
864 pn = fn->parent;
865 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
866 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
867 else
868 fn = pn;
869 if (fn->fn_flags & RTN_RTINFO)
870 return fn;
871 }
872}
Thomas Grafc71099a2006-08-04 23:20:06 -0700873
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800874static struct rt6_info *ip6_pol_route_lookup(struct net *net,
875 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500876 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 struct fib6_node *fn;
879 struct rt6_info *rt;
880
Thomas Grafc71099a2006-08-04 23:20:06 -0700881 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500882 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700883restart:
884 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500885 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000886 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200887 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700888 if (rt == net->ipv6.ip6_null_entry) {
889 fn = fib6_backtrack(fn, &fl6->saddr);
890 if (fn)
891 goto restart;
892 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700893 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700894 read_unlock_bh(&table->tb6_lock);
David Ahernb8115802015-11-19 12:24:22 -0800895
896 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
897
Thomas Grafc71099a2006-08-04 23:20:06 -0700898 return rt;
899
900}
901
Ian Morris67ba4152014-08-24 21:53:10 +0100902struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200903 int flags)
904{
905 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
906}
907EXPORT_SYMBOL_GPL(ip6_route_lookup);
908
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900909struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
910 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700911{
David S. Miller4c9483b2011-03-12 16:22:43 -0500912 struct flowi6 fl6 = {
913 .flowi6_oif = oif,
914 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700915 };
916 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700917 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700918
Thomas Grafadaa70b2006-10-13 15:01:03 -0700919 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500920 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700921 flags |= RT6_LOOKUP_F_HAS_SADDR;
922 }
923
David S. Miller4c9483b2011-03-12 16:22:43 -0500924 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700925 if (dst->error == 0)
926 return (struct rt6_info *) dst;
927
928 dst_release(dst);
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 return NULL;
931}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900932EXPORT_SYMBOL(rt6_lookup);
933
Thomas Grafc71099a2006-08-04 23:20:06 -0700934/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -0700935 * It takes new route entry, the addition fails by any reason the
936 * route is released.
937 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 */
939
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100940static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -0600941 struct mx6_config *mxc,
942 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
944 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700945 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Thomas Grafc71099a2006-08-04 23:20:06 -0700947 table = rt->rt6i_table;
948 write_lock_bh(&table->tb6_lock);
David Ahern333c4302017-05-21 10:12:04 -0600949 err = fib6_add(&table->tb6_root, rt, info, mxc, extack);
Thomas Grafc71099a2006-08-04 23:20:06 -0700950 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 return err;
953}
954
Thomas Graf40e22e82006-08-22 00:00:45 -0700955int ip6_ins_rt(struct rt6_info *rt)
956{
Florian Westphale715b6d2015-01-05 23:57:44 +0100957 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
958 struct mx6_config mxc = { .mx = NULL, };
959
Wei Wang1cfb71e2017-06-17 10:42:33 -0700960 /* Hold dst to account for the reference from the fib6 tree */
961 dst_hold(&rt->dst);
David Ahern333c4302017-05-21 10:12:04 -0600962 return __ip6_ins_rt(rt, &info, &mxc, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -0700963}
964
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700965static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
966 const struct in6_addr *daddr,
967 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 struct rt6_info *rt;
970
971 /*
972 * Clone the route.
973 */
974
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700975 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700976 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Martin KaFai Lauad706862015-08-14 11:05:52 -0700978 rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700980 if (!rt)
981 return NULL;
982
983 ip6_rt_copy_init(rt, ort);
984 rt->rt6i_flags |= RTF_CACHE;
985 rt->rt6i_metric = 0;
986 rt->dst.flags |= DST_HOST;
987 rt->rt6i_dst.addr = *daddr;
988 rt->rt6i_dst.plen = 128;
989
990 if (!rt6_is_gw_or_nonexthop(ort)) {
991 if (ort->rt6i_dst.plen != 128 &&
992 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
993 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700995 if (rt->rt6i_src.plen && saddr) {
996 rt->rt6i_src.addr = *saddr;
997 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700998 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700999#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001002 return rt;
1003}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001005static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
1006{
1007 struct rt6_info *pcpu_rt;
1008
1009 pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
Martin KaFai Lauad706862015-08-14 11:05:52 -07001010 rt->dst.dev, rt->dst.flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001011
1012 if (!pcpu_rt)
1013 return NULL;
1014 ip6_rt_copy_init(pcpu_rt, rt);
1015 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
1016 pcpu_rt->rt6i_flags |= RTF_PCPU;
1017 return pcpu_rt;
1018}
1019
1020/* It should be called with read_lock_bh(&tb6_lock) acquired */
1021static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
1022{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001023 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001024
1025 p = this_cpu_ptr(rt->rt6i_pcpu);
1026 pcpu_rt = *p;
1027
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001028 if (pcpu_rt) {
1029 dst_hold(&pcpu_rt->dst);
1030 rt6_dst_from_metrics_check(pcpu_rt);
1031 }
1032 return pcpu_rt;
1033}
1034
1035static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
1036{
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001037 struct fib6_table *table = rt->rt6i_table;
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001038 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001039
1040 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1041 if (!pcpu_rt) {
1042 struct net *net = dev_net(rt->dst.dev);
1043
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001044 dst_hold(&net->ipv6.ip6_null_entry->dst);
1045 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001046 }
1047
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001048 read_lock_bh(&table->tb6_lock);
1049 if (rt->rt6i_pcpu) {
1050 p = this_cpu_ptr(rt->rt6i_pcpu);
1051 prev = cmpxchg(p, NULL, pcpu_rt);
1052 if (prev) {
1053 /* If someone did it before us, return prev instead */
Wei Wang587fea72017-06-17 10:42:36 -07001054 dst_release_immediate(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001055 pcpu_rt = prev;
1056 }
1057 } else {
1058 /* rt has been removed from the fib6 tree
1059 * before we have a chance to acquire the read_lock.
1060 * In this case, don't brother to create a pcpu rt
1061 * since rt is going away anyway. The next
1062 * dst_check() will trigger a re-lookup.
1063 */
Wei Wang587fea72017-06-17 10:42:36 -07001064 dst_release_immediate(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001065 pcpu_rt = rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001066 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001067 dst_hold(&pcpu_rt->dst);
1068 rt6_dst_from_metrics_check(pcpu_rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001069 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001070 return pcpu_rt;
1071}
1072
David Ahern9ff74382016-06-13 13:44:19 -07001073struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1074 int oif, struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001076 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001077 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001078 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001080 strict |= flags & RT6_LOOKUP_F_IFACE;
David Ahernd5d32e42016-10-24 12:27:23 -07001081 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001082 if (net->ipv6.devconf_all->forwarding == 0)
1083 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Thomas Grafc71099a2006-08-04 23:20:06 -07001085 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
David S. Miller4c9483b2011-03-12 16:22:43 -05001087 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001088 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
David Ahernca254492015-10-12 11:47:10 -07001090 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1091 oif = 0;
1092
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001093redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001094 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001095 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001096 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001097 if (rt == net->ipv6.ip6_null_entry) {
1098 fn = fib6_backtrack(fn, &fl6->saddr);
1099 if (fn)
1100 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001101 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1102 /* also consider unreachable route */
1103 strict &= ~RT6_LOOKUP_F_REACHABLE;
1104 fn = saved_fn;
1105 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001106 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001107 }
1108
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001109
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001110 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001111 dst_use(&rt->dst, jiffies);
1112 read_unlock_bh(&table->tb6_lock);
1113
1114 rt6_dst_from_metrics_check(rt);
David Ahernb8115802015-11-19 12:24:22 -08001115
1116 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001117 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001118 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1119 !(rt->rt6i_flags & RTF_GATEWAY))) {
1120 /* Create a RTF_CACHE clone which will not be
1121 * owned by the fib6 tree. It is for the special case where
1122 * the daddr in the skb during the neighbor look-up is different
1123 * from the fl6->daddr used to look-up route here.
1124 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001125
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001126 struct rt6_info *uncached_rt;
1127
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001128 dst_use(&rt->dst, jiffies);
1129 read_unlock_bh(&table->tb6_lock);
1130
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001131 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1132 dst_release(&rt->dst);
1133
Wei Wang1cfb71e2017-06-17 10:42:33 -07001134 if (uncached_rt) {
1135 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1136 * No need for another dst_hold()
1137 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001138 rt6_uncached_list_add(uncached_rt);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001139 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001140 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001141 dst_hold(&uncached_rt->dst);
1142 }
David Ahernb8115802015-11-19 12:24:22 -08001143
1144 trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001145 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001146
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001147 } else {
1148 /* Get a percpu copy */
1149
1150 struct rt6_info *pcpu_rt;
1151
1152 rt->dst.lastuse = jiffies;
1153 rt->dst.__use++;
1154 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001155
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001156 if (pcpu_rt) {
1157 read_unlock_bh(&table->tb6_lock);
1158 } else {
1159 /* We have to do the read_unlock first
1160 * because rt6_make_pcpu_route() may trigger
1161 * ip6_dst_gc() which will take the write_lock.
1162 */
1163 dst_hold(&rt->dst);
1164 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001165 pcpu_rt = rt6_make_pcpu_route(rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001166 dst_release(&rt->dst);
1167 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001168
David Ahernb8115802015-11-19 12:24:22 -08001169 trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001170 return pcpu_rt;
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001171
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001172 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001173}
David Ahern9ff74382016-06-13 13:44:19 -07001174EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001175
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001176static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001177 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001178{
David S. Miller4c9483b2011-03-12 16:22:43 -05001179 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001180}
1181
Mahesh Bandeward409b842016-09-16 12:59:08 -07001182struct dst_entry *ip6_route_input_lookup(struct net *net,
1183 struct net_device *dev,
1184 struct flowi6 *fl6, int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001185{
1186 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1187 flags |= RT6_LOOKUP_F_IFACE;
1188
1189 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1190}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001191EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001192
Thomas Grafc71099a2006-08-04 23:20:06 -07001193void ip6_route_input(struct sk_buff *skb)
1194{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001195 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001196 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001197 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001198 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001199 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07001200 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05001201 .daddr = iph->daddr,
1202 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001203 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001204 .flowi6_mark = skb->mark,
1205 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001206 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001207
Jiri Benc904af042015-08-20 13:56:31 +02001208 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001209 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001210 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jiri Benc06e9d042015-08-20 13:56:26 +02001211 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001212 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001213}
1214
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001215static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001216 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001217{
David S. Miller4c9483b2011-03-12 16:22:43 -05001218 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001219}
1220
Paolo Abeni6f21c962016-01-29 12:30:19 +01001221struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
1222 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001223{
David Ahernd46a9d62015-10-21 08:42:22 -07001224 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07001225
David Ahern4c1feac2016-09-10 12:09:56 -07001226 if (rt6_need_strict(&fl6->daddr)) {
1227 struct dst_entry *dst;
1228
1229 dst = l3mdev_link_scope_lookup(net, fl6);
1230 if (dst)
1231 return dst;
1232 }
David Ahernca254492015-10-12 11:47:10 -07001233
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001234 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001235
David Ahernd46a9d62015-10-21 08:42:22 -07001236 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07001237 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07001238 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001239 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001240
David Ahernd46a9d62015-10-21 08:42:22 -07001241 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07001242 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001243 else if (sk)
1244 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001245
David S. Miller4c9483b2011-03-12 16:22:43 -05001246 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247}
Paolo Abeni6f21c962016-01-29 12:30:19 +01001248EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
David S. Miller2774c132011-03-01 14:59:04 -08001250struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001251{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001252 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07001253 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07001254 struct dst_entry *new = NULL;
1255
Wei Wang1dbe32522017-06-17 10:42:26 -07001256 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Wei Wangb2a9c0e2017-06-17 10:42:41 -07001257 DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001258 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001259 rt6_info_init(rt);
1260
Changli Gaod8d1f302010-06-10 23:31:35 -07001261 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001262 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001263 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001264 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07001265
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001266 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001267
Wei Wang1dbe32522017-06-17 10:42:26 -07001268 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001269 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001270 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07001271 rt->rt6i_metric = 0;
1272
1273 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1274#ifdef CONFIG_IPV6_SUBTREES
1275 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1276#endif
David S. Miller14e50e52007-05-24 18:17:54 -07001277 }
1278
David S. Miller69ead7a2011-03-01 14:45:33 -08001279 dst_release(dst_orig);
1280 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001281}
David S. Miller14e50e52007-05-24 18:17:54 -07001282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283/*
1284 * Destination cache support functions
1285 */
1286
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001287static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1288{
1289 if (rt->dst.from &&
1290 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1291 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1292}
1293
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001294static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1295{
1296 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1297 return NULL;
1298
1299 if (rt6_check_expired(rt))
1300 return NULL;
1301
1302 return &rt->dst;
1303}
1304
1305static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1306{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08001307 if (!__rt6_check_expired(rt) &&
1308 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001309 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1310 return &rt->dst;
1311 else
1312 return NULL;
1313}
1314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1316{
1317 struct rt6_info *rt;
1318
1319 rt = (struct rt6_info *) dst;
1320
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001321 /* All IPV6 dsts are created with ->obsolete set to the value
1322 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1323 * into this function always.
1324 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001325
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001326 rt6_dst_from_metrics_check(rt);
1327
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08001328 if (rt->rt6i_flags & RTF_PCPU ||
1329 (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001330 return rt6_dst_from_check(rt, cookie);
1331 else
1332 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333}
1334
1335static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1336{
1337 struct rt6_info *rt = (struct rt6_info *) dst;
1338
1339 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001340 if (rt->rt6i_flags & RTF_CACHE) {
1341 if (rt6_check_expired(rt)) {
1342 ip6_del_rt(rt);
1343 dst = NULL;
1344 }
1345 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001347 dst = NULL;
1348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001350 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351}
1352
1353static void ip6_link_failure(struct sk_buff *skb)
1354{
1355 struct rt6_info *rt;
1356
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001357 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Eric Dumazetadf30902009-06-02 05:19:30 +00001359 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001361 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07001362 if (dst_hold_safe(&rt->dst))
1363 ip6_del_rt(rt);
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001364 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 }
1368}
1369
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001370static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1371{
1372 struct net *net = dev_net(rt->dst.dev);
1373
1374 rt->rt6i_flags |= RTF_MODIFIED;
1375 rt->rt6i_pmtu = mtu;
1376 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1377}
1378
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001379static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
1380{
1381 return !(rt->rt6i_flags & RTF_CACHE) &&
1382 (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
1383}
1384
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001385static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1386 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
Julian Anastasov0dec8792017-02-06 23:14:16 +02001388 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001389 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001391 if (rt6->rt6i_flags & RTF_LOCAL)
1392 return;
1393
Xin Long19bda362016-10-28 18:18:01 +08001394 if (dst_metric_locked(dst, RTAX_MTU))
1395 return;
1396
Julian Anastasov0dec8792017-02-06 23:14:16 +02001397 if (iph) {
1398 daddr = &iph->daddr;
1399 saddr = &iph->saddr;
1400 } else if (sk) {
1401 daddr = &sk->sk_v6_daddr;
1402 saddr = &inet6_sk(sk)->saddr;
1403 } else {
1404 daddr = NULL;
1405 saddr = NULL;
1406 }
1407 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001408 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1409 if (mtu >= dst_mtu(dst))
1410 return;
David S. Miller81aded22012-06-15 14:54:11 -07001411
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001412 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001413 rt6_do_update_pmtu(rt6, mtu);
Julian Anastasov0dec8792017-02-06 23:14:16 +02001414 } else if (daddr) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001415 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001416
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001417 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1418 if (nrt6) {
1419 rt6_do_update_pmtu(nrt6, mtu);
1420
1421 /* ip6_ins_rt(nrt6) will bump the
1422 * rt6->rt6i_node->fn_sernum
1423 * which will fail the next rt6_check() and
1424 * invalidate the sk->sk_dst_cache.
1425 */
1426 ip6_ins_rt(nrt6);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001427 /* Release the reference taken in
1428 * ip6_rt_cache_alloc()
1429 */
1430 dst_release(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 }
1433}
1434
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001435static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1436 struct sk_buff *skb, u32 mtu)
1437{
1438 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1439}
1440
David S. Miller42ae66c2012-06-15 20:01:57 -07001441void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001442 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07001443{
1444 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1445 struct dst_entry *dst;
1446 struct flowi6 fl6;
1447
1448 memset(&fl6, 0, sizeof(fl6));
1449 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001450 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001451 fl6.daddr = iph->daddr;
1452 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001453 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001454 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07001455
1456 dst = ip6_route_output(net, NULL, &fl6);
1457 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001458 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001459 dst_release(dst);
1460}
1461EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1462
1463void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1464{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001465 struct dst_entry *dst;
1466
David S. Miller81aded22012-06-15 14:54:11 -07001467 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001468 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001469
1470 dst = __sk_dst_get(sk);
1471 if (!dst || !dst->obsolete ||
1472 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
1473 return;
1474
1475 bh_lock_sock(sk);
1476 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
1477 ip6_datagram_dst_update(sk, false);
1478 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07001479}
1480EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1481
Duan Jiongb55b76b2013-09-04 19:44:21 +08001482/* Handle redirects */
1483struct ip6rd_flowi {
1484 struct flowi6 fl6;
1485 struct in6_addr gateway;
1486};
1487
1488static struct rt6_info *__ip6_route_redirect(struct net *net,
1489 struct fib6_table *table,
1490 struct flowi6 *fl6,
1491 int flags)
1492{
1493 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1494 struct rt6_info *rt;
1495 struct fib6_node *fn;
1496
1497 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01001498 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08001499 *
1500 * RFC 4861 specifies that redirects should only be
1501 * accepted if they come from the nexthop to the target.
1502 * Due to the way the routes are chosen, this notion
1503 * is a bit fuzzy and one might need to check all possible
1504 * routes.
1505 */
1506
1507 read_lock_bh(&table->tb6_lock);
1508 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1509restart:
1510 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1511 if (rt6_check_expired(rt))
1512 continue;
1513 if (rt->dst.error)
1514 break;
1515 if (!(rt->rt6i_flags & RTF_GATEWAY))
1516 continue;
1517 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1518 continue;
1519 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1520 continue;
1521 break;
1522 }
1523
1524 if (!rt)
1525 rt = net->ipv6.ip6_null_entry;
1526 else if (rt->dst.error) {
1527 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001528 goto out;
1529 }
1530
1531 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001532 fn = fib6_backtrack(fn, &fl6->saddr);
1533 if (fn)
1534 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001535 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001536
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001537out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001538 dst_hold(&rt->dst);
1539
1540 read_unlock_bh(&table->tb6_lock);
1541
David Ahernb8115802015-11-19 12:24:22 -08001542 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Duan Jiongb55b76b2013-09-04 19:44:21 +08001543 return rt;
1544};
1545
1546static struct dst_entry *ip6_route_redirect(struct net *net,
1547 const struct flowi6 *fl6,
1548 const struct in6_addr *gateway)
1549{
1550 int flags = RT6_LOOKUP_F_HAS_SADDR;
1551 struct ip6rd_flowi rdfl;
1552
1553 rdfl.fl6 = *fl6;
1554 rdfl.gateway = *gateway;
1555
1556 return fib6_rule_lookup(net, &rdfl.fl6,
1557 flags, __ip6_route_redirect);
1558}
1559
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001560void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
1561 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001562{
1563 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1564 struct dst_entry *dst;
1565 struct flowi6 fl6;
1566
1567 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001568 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001569 fl6.flowi6_oif = oif;
1570 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001571 fl6.daddr = iph->daddr;
1572 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001573 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001574 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001575
Duan Jiongb55b76b2013-09-04 19:44:21 +08001576 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1577 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001578 dst_release(dst);
1579}
1580EXPORT_SYMBOL_GPL(ip6_redirect);
1581
Duan Jiongc92a59e2013-08-22 12:07:35 +08001582void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1583 u32 mark)
1584{
1585 const struct ipv6hdr *iph = ipv6_hdr(skb);
1586 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1587 struct dst_entry *dst;
1588 struct flowi6 fl6;
1589
1590 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001591 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001592 fl6.flowi6_oif = oif;
1593 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001594 fl6.daddr = msg->dest;
1595 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001596 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001597
Duan Jiongb55b76b2013-09-04 19:44:21 +08001598 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1599 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001600 dst_release(dst);
1601}
1602
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001603void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1604{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001605 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
1606 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001607}
1608EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1609
David S. Miller0dbaee32010-12-13 12:52:14 -08001610static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611{
David S. Miller0dbaee32010-12-13 12:52:14 -08001612 struct net_device *dev = dst->dev;
1613 unsigned int mtu = dst_mtu(dst);
1614 struct net *net = dev_net(dev);
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1617
Daniel Lezcano55786892008-03-04 13:47:47 -08001618 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1619 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
1621 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001622 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1623 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1624 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 * rely only on pmtu discovery"
1626 */
1627 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1628 mtu = IPV6_MAXPLEN;
1629 return mtu;
1630}
1631
Steffen Klassertebb762f2011-11-23 02:12:51 +00001632static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001633{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001634 const struct rt6_info *rt = (const struct rt6_info *)dst;
1635 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001636 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001637
1638 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001639 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001640
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001641 mtu = dst_metric_raw(dst, RTAX_MTU);
1642 if (mtu)
1643 goto out;
1644
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001645 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001646
1647 rcu_read_lock();
1648 idev = __in6_dev_get(dst->dev);
1649 if (idev)
1650 mtu = idev->cnf.mtu6;
1651 rcu_read_unlock();
1652
Eric Dumazet30f78d82014-04-10 21:23:36 -07001653out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07001654 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1655
1656 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08001657}
1658
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001659struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001660 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661{
David S. Miller87a11572011-12-06 17:04:13 -05001662 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 struct rt6_info *rt;
1664 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001665 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
David S. Miller38308472011-12-03 18:02:47 -05001667 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001668 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Martin KaFai Lauad706862015-08-14 11:05:52 -07001670 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001671 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001673 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 goto out;
1675 }
1676
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001677 rt->dst.flags |= DST_HOST;
1678 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03001679 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001680 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001681 rt->rt6i_dst.plen = 128;
1682 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001683 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Wei Wang587fea72017-06-17 10:42:36 -07001685 /* Add this dst into uncached_list so that rt6_ifdown() can
1686 * do proper release of the net_device
1687 */
1688 rt6_uncached_list_add(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
David S. Miller87a11572011-12-06 17:04:13 -05001690 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692out:
David S. Miller87a11572011-12-06 17:04:13 -05001693 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694}
1695
Daniel Lezcano569d3642008-01-18 03:56:57 -08001696static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001698 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001699 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1700 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1701 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1702 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1703 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001704 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
Eric Dumazetfc66f952010-10-08 06:37:34 +00001706 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001707 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001708 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 goto out;
1710
Benjamin Thery6891a342008-03-04 13:49:47 -08001711 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001712 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001713 entries = dst_entries_get_slow(ops);
1714 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001715 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001717 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001718 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719}
1720
Florian Westphale715b6d2015-01-05 23:57:44 +01001721static int ip6_convert_metrics(struct mx6_config *mxc,
1722 const struct fib6_config *cfg)
1723{
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001724 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01001725 struct nlattr *nla;
1726 int remaining;
1727 u32 *mp;
1728
Ian Morris63159f22015-03-29 14:00:04 +01001729 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001730 return 0;
1731
1732 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1733 if (unlikely(!mp))
1734 return -ENOMEM;
1735
1736 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1737 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001738 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001739
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001740 if (!type)
1741 continue;
1742 if (unlikely(type > RTAX_MAX))
1743 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001744
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001745 if (type == RTAX_CC_ALGO) {
1746 char tmp[TCP_CA_NAME_MAX];
1747
1748 nla_strlcpy(tmp, nla, sizeof(tmp));
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001749 val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001750 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01001751 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001752 } else {
1753 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01001754 }
Paolo Abeni626abd52016-05-13 18:33:41 +02001755 if (type == RTAX_HOPLIMIT && val > 255)
1756 val = 255;
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02001757 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
1758 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001759
1760 mp[type - 1] = val;
1761 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01001762 }
1763
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001764 if (ecn_ca) {
1765 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
1766 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
1767 }
Florian Westphale715b6d2015-01-05 23:57:44 +01001768
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001769 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01001770 return 0;
1771 err:
1772 kfree(mp);
1773 return -EINVAL;
1774}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
David Ahern8c145862016-04-24 21:26:04 -07001776static struct rt6_info *ip6_nh_lookup_table(struct net *net,
1777 struct fib6_config *cfg,
1778 const struct in6_addr *gw_addr)
1779{
1780 struct flowi6 fl6 = {
1781 .flowi6_oif = cfg->fc_ifindex,
1782 .daddr = *gw_addr,
1783 .saddr = cfg->fc_prefsrc,
1784 };
1785 struct fib6_table *table;
1786 struct rt6_info *rt;
David Ahernd5d32e42016-10-24 12:27:23 -07001787 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahern8c145862016-04-24 21:26:04 -07001788
1789 table = fib6_get_table(net, cfg->fc_table);
1790 if (!table)
1791 return NULL;
1792
1793 if (!ipv6_addr_any(&cfg->fc_prefsrc))
1794 flags |= RT6_LOOKUP_F_HAS_SADDR;
1795
1796 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
1797
1798 /* if table lookup failed, fall back to full lookup */
1799 if (rt == net->ipv6.ip6_null_entry) {
1800 ip6_rt_put(rt);
1801 rt = NULL;
1802 }
1803
1804 return rt;
1805}
1806
David Ahern333c4302017-05-21 10:12:04 -06001807static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
1808 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809{
Daniel Lezcano55786892008-03-04 13:47:47 -08001810 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 struct rt6_info *rt = NULL;
1812 struct net_device *dev = NULL;
1813 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001814 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001816 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
David Ahern557c44b2017-04-19 14:19:43 -07001818 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06001819 if (cfg->fc_flags & RTF_PCPU) {
1820 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07001821 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001822 }
David Ahern557c44b2017-04-19 14:19:43 -07001823
David Ahernd5d531c2017-05-21 10:12:05 -06001824 if (cfg->fc_dst_len > 128) {
1825 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001826 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001827 }
1828 if (cfg->fc_src_len > 128) {
1829 NL_SET_ERR_MSG(extack, "Invalid source address length");
1830 goto out;
1831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06001833 if (cfg->fc_src_len) {
1834 NL_SET_ERR_MSG(extack,
1835 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001836 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001839 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001841 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if (!dev)
1843 goto out;
1844 idev = in6_dev_get(dev);
1845 if (!idev)
1846 goto out;
1847 }
1848
Thomas Graf86872cb2006-08-22 00:01:08 -07001849 if (cfg->fc_metric == 0)
1850 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Matti Vaittinend71314b2011-11-14 00:14:49 +00001852 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001853 if (cfg->fc_nlinfo.nlh &&
1854 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001855 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001856 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001857 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001858 table = fib6_new_table(net, cfg->fc_table);
1859 }
1860 } else {
1861 table = fib6_new_table(net, cfg->fc_table);
1862 }
David S. Miller38308472011-12-03 18:02:47 -05001863
1864 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001865 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001866
Martin KaFai Lauad706862015-08-14 11:05:52 -07001867 rt = ip6_dst_alloc(net, NULL,
1868 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
David S. Miller38308472011-12-03 18:02:47 -05001870 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 err = -ENOMEM;
1872 goto out;
1873 }
1874
Gao feng1716a962012-04-06 00:13:10 +00001875 if (cfg->fc_flags & RTF_EXPIRES)
1876 rt6_set_expires(rt, jiffies +
1877 clock_t_to_jiffies(cfg->fc_expires));
1878 else
1879 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Thomas Graf86872cb2006-08-22 00:01:08 -07001881 if (cfg->fc_protocol == RTPROT_UNSPEC)
1882 cfg->fc_protocol = RTPROT_BOOT;
1883 rt->rt6i_protocol = cfg->fc_protocol;
1884
1885 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
1887 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001888 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001889 else if (cfg->fc_flags & RTF_LOCAL)
1890 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001892 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
Changli Gaod8d1f302010-06-10 23:31:35 -07001894 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001896 if (cfg->fc_encap) {
1897 struct lwtunnel_state *lwtstate;
1898
David Ahern30357d72017-01-30 12:07:37 -08001899 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07001900 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06001901 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001902 if (err)
1903 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02001904 rt->dst.lwtstate = lwtstate_get(lwtstate);
1905 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
1906 rt->dst.lwtstate->orig_output = rt->dst.output;
1907 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07001908 }
Jiri Benc61adedf2015-08-20 13:56:25 +02001909 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
1910 rt->dst.lwtstate->orig_input = rt->dst.input;
1911 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07001912 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001913 }
1914
Thomas Graf86872cb2006-08-22 00:01:08 -07001915 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1916 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001917 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001918 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001919
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001921 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1922 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923#endif
1924
Thomas Graf86872cb2006-08-22 00:01:08 -07001925 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
1927 /* We cannot add true routes via loopback here,
1928 they would result in kernel looping; promote them to reject routes
1929 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001930 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001931 (dev && (dev->flags & IFF_LOOPBACK) &&
1932 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1933 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001935 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 if (dev) {
1937 dev_put(dev);
1938 in6_dev_put(idev);
1939 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001940 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 dev_hold(dev);
1942 idev = in6_dev_get(dev);
1943 if (!idev) {
1944 err = -ENODEV;
1945 goto out;
1946 }
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001949 switch (cfg->fc_type) {
1950 case RTN_BLACKHOLE:
1951 rt->dst.error = -EINVAL;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001952 rt->dst.output = dst_discard_out;
Kamala R7150aed2013-12-02 19:55:21 +05301953 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001954 break;
1955 case RTN_PROHIBIT:
1956 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301957 rt->dst.output = ip6_pkt_prohibit_out;
1958 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001959 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001960 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02001961 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001962 default:
Kamala R7150aed2013-12-02 19:55:21 +05301963 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02001964 : (cfg->fc_type == RTN_UNREACHABLE)
1965 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05301966 rt->dst.output = ip6_pkt_discard_out;
1967 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001968 break;
1969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 goto install_route;
1971 }
1972
Thomas Graf86872cb2006-08-22 00:01:08 -07001973 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001974 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 int gwa_type;
1976
Thomas Graf86872cb2006-08-22 00:01:08 -07001977 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02001978 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02001979
1980 /* if gw_addr is local we will fail to detect this in case
1981 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1982 * will return already-added prefix route via interface that
1983 * prefix route was assigned to, which might be non-loopback.
1984 */
1985 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02001986 if (ipv6_chk_addr_and_flags(net, gw_addr,
1987 gwa_type & IPV6_ADDR_LINKLOCAL ?
David Ahernd5d531c2017-05-21 10:12:05 -06001988 dev : NULL, 0, 0)) {
1989 NL_SET_ERR_MSG(extack, "Invalid gateway address");
Florian Westphal48ed7b22015-05-21 00:25:41 +02001990 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001991 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001992 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
David Ahern8c145862016-04-24 21:26:04 -07001995 struct rt6_info *grt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
1997 /* IPv6 strictly inhibits using not link-local
1998 addresses as nexthop address.
1999 Otherwise, router will not able to send redirects.
2000 It is very good, but in some (rare!) circumstances
2001 (SIT, PtP, NBMA NOARP links) it is handy to allow
2002 some exceptions. --ANK
Erik Nordmark96d58222016-12-03 20:57:09 -08002003 We allow IPv4-mapped nexthops to support RFC4798-type
2004 addressing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 */
Erik Nordmark96d58222016-12-03 20:57:09 -08002006 if (!(gwa_type & (IPV6_ADDR_UNICAST |
David Ahernd5d531c2017-05-21 10:12:05 -06002007 IPV6_ADDR_MAPPED))) {
2008 NL_SET_ERR_MSG(extack,
2009 "Invalid gateway address");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Vincent Bernata435a072016-09-18 17:46:07 +02002013 if (cfg->fc_table) {
David Ahern8c145862016-04-24 21:26:04 -07002014 grt = ip6_nh_lookup_table(net, cfg, gw_addr);
2015
Vincent Bernata435a072016-09-18 17:46:07 +02002016 if (grt) {
2017 if (grt->rt6i_flags & RTF_GATEWAY ||
2018 (dev && dev != grt->dst.dev)) {
2019 ip6_rt_put(grt);
2020 grt = NULL;
2021 }
2022 }
2023 }
2024
David Ahern8c145862016-04-24 21:26:04 -07002025 if (!grt)
2026 grt = rt6_lookup(net, gw_addr, NULL,
2027 cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
2029 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05002030 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 goto out;
2032 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05002033 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002034 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 goto out;
2036 }
2037 } else {
David S. Millerd1918542011-12-28 20:19:20 -05002038 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 idev = grt->rt6i_idev;
2040 dev_hold(dev);
2041 in6_dev_hold(grt->rt6i_idev);
2042 }
David S. Miller38308472011-12-03 18:02:47 -05002043 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00002045 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
2047 if (err)
2048 goto out;
2049 }
2050 err = -EINVAL;
David Ahernd5d531c2017-05-21 10:12:05 -06002051 if (!dev) {
2052 NL_SET_ERR_MSG(extack, "Egress device not specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002054 } else if (dev->flags & IFF_LOOPBACK) {
2055 NL_SET_ERR_MSG(extack,
2056 "Egress device can not be loopback device for this route");
2057 goto out;
2058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 }
2060
2061 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002062 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 goto out;
2064
Daniel Walterc3968a82011-04-13 21:10:57 +00002065 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2066 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06002067 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00002068 err = -EINVAL;
2069 goto out;
2070 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002071 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00002072 rt->rt6i_prefsrc.plen = 128;
2073 } else
2074 rt->rt6i_prefsrc.plen = 0;
2075
Thomas Graf86872cb2006-08-22 00:01:08 -07002076 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
2078install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07002079 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07002081 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002082
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002083 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002084
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002085 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086out:
2087 if (dev)
2088 dev_put(dev);
2089 if (idev)
2090 in6_dev_put(idev);
Wei Wang587fea72017-06-17 10:42:36 -07002091 if (rt)
2092 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002093
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002094 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002095}
2096
David Ahern333c4302017-05-21 10:12:04 -06002097int ip6_route_add(struct fib6_config *cfg,
2098 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002099{
2100 struct mx6_config mxc = { .mx = NULL, };
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002101 struct rt6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002102 int err;
2103
David Ahern333c4302017-05-21 10:12:04 -06002104 rt = ip6_route_info_create(cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002105 if (IS_ERR(rt)) {
2106 err = PTR_ERR(rt);
2107 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002108 goto out;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002109 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002110
2111 err = ip6_convert_metrics(&mxc, cfg);
2112 if (err)
2113 goto out;
2114
David Ahern333c4302017-05-21 10:12:04 -06002115 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002116
2117 kfree(mxc.mx);
2118
2119 return err;
2120out:
Wei Wang587fea72017-06-17 10:42:36 -07002121 if (rt)
2122 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002123
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 return err;
2125}
2126
Thomas Graf86872cb2006-08-22 00:01:08 -07002127static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128{
2129 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002130 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002131 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002133 if (rt == net->ipv6.ip6_null_entry ||
2134 rt->dst.flags & DST_NOCACHE) {
Gao feng6825a262012-09-19 19:25:34 +00002135 err = -ENOENT;
2136 goto out;
2137 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002138
Thomas Grafc71099a2006-08-04 23:20:06 -07002139 table = rt->rt6i_table;
2140 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002141 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07002142 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Gao feng6825a262012-09-19 19:25:34 +00002144out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002145 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 return err;
2147}
2148
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002149int ip6_del_rt(struct rt6_info *rt)
2150{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002151 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002152 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002153 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002154 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002155}
2156
David Ahern0ae81332017-02-02 12:37:08 -08002157static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
2158{
2159 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08002160 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08002161 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08002162 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08002163 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08002164
WANG Conge3330032017-02-27 16:07:43 -08002165 if (rt == net->ipv6.ip6_null_entry)
2166 goto out_put;
David Ahern0ae81332017-02-02 12:37:08 -08002167 table = rt->rt6i_table;
2168 write_lock_bh(&table->tb6_lock);
2169
2170 if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
2171 struct rt6_info *sibling, *next_sibling;
2172
David Ahern16a16cd2017-02-02 12:37:11 -08002173 /* prefer to send a single notification with all hops */
2174 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
2175 if (skb) {
2176 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
2177
WANG Conge3330032017-02-27 16:07:43 -08002178 if (rt6_fill_node(net, skb, rt,
David Ahern16a16cd2017-02-02 12:37:11 -08002179 NULL, NULL, 0, RTM_DELROUTE,
2180 info->portid, seq, 0) < 0) {
2181 kfree_skb(skb);
2182 skb = NULL;
2183 } else
2184 info->skip_notify = 1;
2185 }
2186
David Ahern0ae81332017-02-02 12:37:08 -08002187 list_for_each_entry_safe(sibling, next_sibling,
2188 &rt->rt6i_siblings,
2189 rt6i_siblings) {
2190 err = fib6_del(sibling, info);
2191 if (err)
WANG Conge3330032017-02-27 16:07:43 -08002192 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08002193 }
2194 }
2195
2196 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08002197out_unlock:
David Ahern0ae81332017-02-02 12:37:08 -08002198 write_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08002199out_put:
David Ahern0ae81332017-02-02 12:37:08 -08002200 ip6_rt_put(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08002201
2202 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08002203 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08002204 info->nlh, gfp_any());
2205 }
David Ahern0ae81332017-02-02 12:37:08 -08002206 return err;
2207}
2208
David Ahern333c4302017-05-21 10:12:04 -06002209static int ip6_route_del(struct fib6_config *cfg,
2210 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211{
Thomas Grafc71099a2006-08-04 23:20:06 -07002212 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 struct fib6_node *fn;
2214 struct rt6_info *rt;
2215 int err = -ESRCH;
2216
Daniel Lezcano55786892008-03-04 13:47:47 -08002217 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06002218 if (!table) {
2219 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07002220 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06002221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Thomas Grafc71099a2006-08-04 23:20:06 -07002223 read_lock_bh(&table->tb6_lock);
2224
2225 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002226 &cfg->fc_dst, cfg->fc_dst_len,
2227 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002230 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002231 if ((rt->rt6i_flags & RTF_CACHE) &&
2232 !(cfg->fc_flags & RTF_CACHE))
2233 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002234 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002235 (!rt->dst.dev ||
2236 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002238 if (cfg->fc_flags & RTF_GATEWAY &&
2239 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002241 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 continue;
Mantas Mc2ed1882016-12-16 10:30:59 +02002243 if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
2244 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002245 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002246 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
David Ahern0ae81332017-02-02 12:37:08 -08002248 /* if gateway was specified only delete the one hop */
2249 if (cfg->fc_flags & RTF_GATEWAY)
2250 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
2251
2252 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002255 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 return err;
2258}
2259
David S. Miller6700c272012-07-17 03:29:28 -07002260static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002261{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002262 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002263 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002264 struct ndisc_options ndopts;
2265 struct inet6_dev *in6_dev;
2266 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002267 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002268 int optlen, on_link;
2269 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002270
Simon Horman29a3cad2013-05-28 20:34:26 +00002271 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002272 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002273
2274 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002275 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002276 return;
2277 }
2278
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002279 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002280
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002281 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002282 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002283 return;
2284 }
2285
David S. Miller6e157b62012-07-12 00:05:02 -07002286 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002287 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002288 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002289 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002290 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002291 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002292 return;
2293 }
2294
2295 in6_dev = __in6_dev_get(skb->dev);
2296 if (!in6_dev)
2297 return;
2298 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2299 return;
2300
2301 /* RFC2461 8.1:
2302 * The IP source address of the Redirect MUST be the same as the current
2303 * first-hop router for the specified ICMP Destination Address.
2304 */
2305
Alexander Aringf997c552016-06-15 21:20:23 +02002306 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002307 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2308 return;
2309 }
David S. Miller6e157b62012-07-12 00:05:02 -07002310
2311 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002312 if (ndopts.nd_opts_tgt_lladdr) {
2313 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2314 skb->dev);
2315 if (!lladdr) {
2316 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2317 return;
2318 }
2319 }
2320
David S. Miller6e157b62012-07-12 00:05:02 -07002321 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01002322 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07002323 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2324 return;
2325 }
2326
2327 /* Redirect received -> path was valid.
2328 * Look, redirects are sent only in response to data packets,
2329 * so that this nexthop apparently is reachable. --ANK
2330 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02002331 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07002332
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002333 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002334 if (!neigh)
2335 return;
2336
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 /*
2338 * We have finally decided to accept it.
2339 */
2340
Alexander Aringf997c552016-06-15 21:20:23 +02002341 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2343 NEIGH_UPDATE_F_OVERRIDE|
2344 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02002345 NEIGH_UPDATE_F_ISROUTER)),
2346 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002348 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002349 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 goto out;
2351
2352 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2353 if (on_link)
2354 nrt->rt6i_flags &= ~RTF_GATEWAY;
2355
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002356 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
Thomas Graf40e22e82006-08-22 00:00:45 -07002358 if (ip6_ins_rt(nrt))
Wei Wang1cfb71e2017-06-17 10:42:33 -07002359 goto out_release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Changli Gaod8d1f302010-06-10 23:31:35 -07002361 netevent.old = &rt->dst;
2362 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002363 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002364 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002365 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2366
David S. Miller38308472011-12-03 18:02:47 -05002367 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002368 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002369 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 }
2371
Wei Wang1cfb71e2017-06-17 10:42:33 -07002372out_release:
2373 /* Release the reference taken in
2374 * ip6_rt_cache_alloc()
2375 */
2376 dst_release(&nrt->dst);
2377
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378out:
David S. Millere8599ff2012-07-11 23:43:53 -07002379 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002380}
2381
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 * Misc support functions
2384 */
2385
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002386static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2387{
2388 BUG_ON(from->dst.from);
2389
2390 rt->rt6i_flags &= ~RTF_EXPIRES;
2391 dst_hold(&from->dst);
2392 rt->dst.from = &from->dst;
2393 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2394}
2395
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002396static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002398 rt->dst.input = ort->dst.input;
2399 rt->dst.output = ort->dst.output;
2400 rt->rt6i_dst = ort->rt6i_dst;
2401 rt->dst.error = ort->dst.error;
2402 rt->rt6i_idev = ort->rt6i_idev;
2403 if (rt->rt6i_idev)
2404 in6_dev_hold(rt->rt6i_idev);
2405 rt->dst.lastuse = jiffies;
2406 rt->rt6i_gateway = ort->rt6i_gateway;
2407 rt->rt6i_flags = ort->rt6i_flags;
2408 rt6_set_from(rt, ort);
2409 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002411 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002413 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2414 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02002415 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416}
2417
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002418#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002419static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002420 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002421 const struct in6_addr *gwaddr,
2422 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002423{
David Ahern830218c2016-10-24 10:52:35 -07002424 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
2425 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002426 struct fib6_node *fn;
2427 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002428 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002429
David Ahern830218c2016-10-24 10:52:35 -07002430 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002431 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002432 return NULL;
2433
Li RongQing5744dd92012-09-11 21:59:01 +00002434 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002435 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002436 if (!fn)
2437 goto out;
2438
Changli Gaod8d1f302010-06-10 23:31:35 -07002439 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002440 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002441 continue;
2442 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2443 continue;
2444 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2445 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002446 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002447 break;
2448 }
2449out:
Li RongQing5744dd92012-09-11 21:59:01 +00002450 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002451 return rt;
2452}
2453
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002454static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002455 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002456 const struct in6_addr *gwaddr,
2457 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00002458 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002459{
Thomas Graf86872cb2006-08-22 00:01:08 -07002460 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08002461 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07002462 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07002463 .fc_dst_len = prefixlen,
2464 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2465 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002466 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002467 .fc_nlinfo.nlh = NULL,
2468 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002469 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002470
David Ahern830218c2016-10-24 10:52:35 -07002471 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002472 cfg.fc_dst = *prefix;
2473 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002474
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002475 /* We should treat it as a default route if prefix length is 0. */
2476 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002477 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002478
David Ahern333c4302017-05-21 10:12:04 -06002479 ip6_route_add(&cfg, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002480
David Ahern830218c2016-10-24 10:52:35 -07002481 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002482}
2483#endif
2484
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002485struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002486{
David Ahern830218c2016-10-24 10:52:35 -07002487 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002489 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
David Ahern830218c2016-10-24 10:52:35 -07002491 table = fib6_get_table(dev_net(dev), tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002492 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002493 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
Li RongQing5744dd92012-09-11 21:59:01 +00002495 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002496 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002497 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002498 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2500 break;
2501 }
2502 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002503 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002504 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 return rt;
2506}
2507
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002508struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002509 struct net_device *dev,
2510 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511{
Thomas Graf86872cb2006-08-22 00:01:08 -07002512 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07002513 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002514 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002515 .fc_ifindex = dev->ifindex,
2516 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2517 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002518 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002519 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002520 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002521 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002523 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524
David Ahern333c4302017-05-21 10:12:04 -06002525 if (!ip6_route_add(&cfg, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07002526 struct fib6_table *table;
2527
2528 table = fib6_get_table(dev_net(dev), cfg.fc_table);
2529 if (table)
2530 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
2531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 return rt6_get_dflt_router(gwaddr, dev);
2534}
2535
David Ahern830218c2016-10-24 10:52:35 -07002536static void __rt6_purge_dflt_routers(struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537{
2538 struct rt6_info *rt;
2539
2540restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002541 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002542 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002543 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2544 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002545 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002546 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002547 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 goto restart;
2549 }
2550 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002551 read_unlock_bh(&table->tb6_lock);
David Ahern830218c2016-10-24 10:52:35 -07002552
2553 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
2554}
2555
2556void rt6_purge_dflt_routers(struct net *net)
2557{
2558 struct fib6_table *table;
2559 struct hlist_head *head;
2560 unsigned int h;
2561
2562 rcu_read_lock();
2563
2564 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
2565 head = &net->ipv6.fib_table_hash[h];
2566 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
2567 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
2568 __rt6_purge_dflt_routers(table);
2569 }
2570 }
2571
2572 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573}
2574
Daniel Lezcano55786892008-03-04 13:47:47 -08002575static void rtmsg_to_fib6_config(struct net *net,
2576 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002577 struct fib6_config *cfg)
2578{
2579 memset(cfg, 0, sizeof(*cfg));
2580
David Ahernca254492015-10-12 11:47:10 -07002581 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
2582 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07002583 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2584 cfg->fc_metric = rtmsg->rtmsg_metric;
2585 cfg->fc_expires = rtmsg->rtmsg_info;
2586 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2587 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2588 cfg->fc_flags = rtmsg->rtmsg_flags;
2589
Daniel Lezcano55786892008-03-04 13:47:47 -08002590 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002591
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002592 cfg->fc_dst = rtmsg->rtmsg_dst;
2593 cfg->fc_src = rtmsg->rtmsg_src;
2594 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002595}
2596
Daniel Lezcano55786892008-03-04 13:47:47 -08002597int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598{
Thomas Graf86872cb2006-08-22 00:01:08 -07002599 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 struct in6_rtmsg rtmsg;
2601 int err;
2602
Ian Morris67ba4152014-08-24 21:53:10 +01002603 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 case SIOCADDRT: /* Add a route */
2605 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002606 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 return -EPERM;
2608 err = copy_from_user(&rtmsg, arg,
2609 sizeof(struct in6_rtmsg));
2610 if (err)
2611 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002612
Daniel Lezcano55786892008-03-04 13:47:47 -08002613 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002614
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 rtnl_lock();
2616 switch (cmd) {
2617 case SIOCADDRT:
David Ahern333c4302017-05-21 10:12:04 -06002618 err = ip6_route_add(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 break;
2620 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06002621 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 break;
2623 default:
2624 err = -EINVAL;
2625 }
2626 rtnl_unlock();
2627
2628 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
2631 return -EINVAL;
2632}
2633
2634/*
2635 * Drop the packet on the floor
2636 */
2637
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002638static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002640 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002641 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002642 switch (ipstats_mib_noroutes) {
2643 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002644 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002645 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002646 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2647 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002648 break;
2649 }
2650 /* FALLTHROUGH */
2651 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002652 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2653 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002654 break;
2655 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002656 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 kfree_skb(skb);
2658 return 0;
2659}
2660
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002661static int ip6_pkt_discard(struct sk_buff *skb)
2662{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002663 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002664}
2665
Eric W. Biedermanede20592015-10-07 16:48:47 -05002666static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667{
Eric Dumazetadf30902009-06-02 05:19:30 +00002668 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002669 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670}
2671
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002672static int ip6_pkt_prohibit(struct sk_buff *skb)
2673{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002674 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002675}
2676
Eric W. Biedermanede20592015-10-07 16:48:47 -05002677static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002678{
Eric Dumazetadf30902009-06-02 05:19:30 +00002679 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002680 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002681}
2682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683/*
2684 * Allocate a dst for local (unicast / anycast) address.
2685 */
2686
2687struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2688 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002689 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690{
David Ahernca254492015-10-12 11:47:10 -07002691 u32 tb_id;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002692 struct net *net = dev_net(idev->dev);
David Ahern5f02ce242016-09-10 12:09:54 -07002693 struct net_device *dev = net->loopback_dev;
2694 struct rt6_info *rt;
2695
2696 /* use L3 Master device as loopback for host routes if device
2697 * is enslaved and address is not link local or multicast
2698 */
2699 if (!rt6_need_strict(addr))
2700 dev = l3mdev_master_dev_rcu(idev->dev) ? : dev;
2701
2702 rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002703 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 return ERR_PTR(-ENOMEM);
2705
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 in6_dev_hold(idev);
2707
David S. Miller11d53b42011-06-24 15:23:34 -07002708 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002709 rt->dst.input = ip6_input;
2710 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
David Ahern94b5e0f2017-02-02 08:52:21 -08002713 rt->rt6i_protocol = RTPROT_KERNEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002715 if (anycast)
2716 rt->rt6i_flags |= RTF_ANYCAST;
2717 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
Julian Anastasov550bab42013-10-20 15:43:04 +03002720 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002721 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 rt->rt6i_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07002723 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
2724 rt->rt6i_table = fib6_get_table(net, tb_id);
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002725 rt->dst.flags |= DST_NOCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 return rt;
2728}
2729
Daniel Walterc3968a82011-04-13 21:10:57 +00002730/* remove deleted ip from prefsrc entries */
2731struct arg_dev_net_ip {
2732 struct net_device *dev;
2733 struct net *net;
2734 struct in6_addr *addr;
2735};
2736
2737static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2738{
2739 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2740 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2741 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2742
David S. Millerd1918542011-12-28 20:19:20 -05002743 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002744 rt != net->ipv6.ip6_null_entry &&
2745 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2746 /* remove prefsrc entry */
2747 rt->rt6i_prefsrc.plen = 0;
2748 }
2749 return 0;
2750}
2751
2752void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2753{
2754 struct net *net = dev_net(ifp->idev->dev);
2755 struct arg_dev_net_ip adni = {
2756 .dev = ifp->idev->dev,
2757 .net = net,
2758 .addr = &ifp->addr,
2759 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002760 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002761}
2762
Duan Jiongbe7a0102014-05-15 15:56:14 +08002763#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2764#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2765
2766/* Remove routers and update dst entries when gateway turn into host. */
2767static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2768{
2769 struct in6_addr *gateway = (struct in6_addr *)arg;
2770
2771 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2772 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2773 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2774 return -1;
2775 }
2776 return 0;
2777}
2778
2779void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2780{
2781 fib6_clean_all(net, fib6_clean_tohost, gateway);
2782}
2783
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002784struct arg_dev_net {
2785 struct net_device *dev;
2786 struct net *net;
2787};
2788
David Aherna1a22c12017-01-18 07:40:36 -08002789/* called with write lock held for table with rt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790static int fib6_ifdown(struct rt6_info *rt, void *arg)
2791{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002792 const struct arg_dev_net *adn = arg;
2793 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002794
David S. Millerd1918542011-12-28 20:19:20 -05002795 if ((rt->dst.dev == dev || !dev) &&
David Aherna1a22c12017-01-18 07:40:36 -08002796 rt != adn->net->ipv6.ip6_null_entry &&
2797 (rt->rt6i_nsiblings == 0 ||
David Ahern8397ed32017-06-07 12:26:23 -06002798 (dev && netdev_unregistering(dev)) ||
David Aherna1a22c12017-01-18 07:40:36 -08002799 !rt->rt6i_idev->cnf.ignore_routes_with_linkdown))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002801
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 return 0;
2803}
2804
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002805void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002807 struct arg_dev_net adn = {
2808 .dev = dev,
2809 .net = net,
2810 };
2811
Li RongQing0c3584d2013-12-27 16:32:38 +08002812 fib6_clean_all(net, fib6_ifdown, &adn);
Eric W. Biedermane332bc62015-10-12 11:02:08 -05002813 if (dev)
2814 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815}
2816
Eric Dumazet95c96172012-04-15 05:58:06 +00002817struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002819 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820};
2821
2822static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2823{
2824 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2825 struct inet6_dev *idev;
2826
2827 /* In IPv6 pmtu discovery is not optional,
2828 so that RTAX_MTU lock cannot disable it.
2829 We still use this lock to block changes
2830 caused by addrconf/ndisc.
2831 */
2832
2833 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002834 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 return 0;
2836
2837 /* For administrative MTU increase, there is no way to discover
2838 IPv6 PMTU increase, so PMTU increase should be updated here.
2839 Since RFC 1981 doesn't include administrative MTU increase
2840 update PMTU increase is a MUST. (i.e. jumbo frame)
2841 */
2842 /*
2843 If new MTU is less than route PMTU, this new MTU will be the
2844 lowest MTU in the path, update the route PMTU to reflect PMTU
2845 decreases; if new MTU is greater than route PMTU, and the
2846 old MTU is the lowest MTU in the path, update the route PMTU
2847 to reflect the increase. In this case if the other nodes' MTU
2848 also have the lowest MTU, TOO BIG MESSAGE will be lead to
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002849 PMTU discovery.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 */
David S. Millerd1918542011-12-28 20:19:20 -05002851 if (rt->dst.dev == arg->dev &&
Maciej Żenczykowskifb56be82016-11-04 14:51:54 -07002852 dst_metric_raw(&rt->dst, RTAX_MTU) &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002853 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2854 if (rt->rt6i_flags & RTF_CACHE) {
2855 /* For RTF_CACHE with rt6i_pmtu == 0
2856 * (i.e. a redirected route),
2857 * the metrics of its rt->dst.from has already
2858 * been updated.
2859 */
2860 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2861 rt->rt6i_pmtu = arg->mtu;
2862 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2863 (dst_mtu(&rt->dst) < arg->mtu &&
2864 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2865 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2866 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 return 0;
2869}
2870
Eric Dumazet95c96172012-04-15 05:58:06 +00002871void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872{
Thomas Grafc71099a2006-08-04 23:20:06 -07002873 struct rt6_mtu_change_arg arg = {
2874 .dev = dev,
2875 .mtu = mtu,
2876 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
Li RongQing0c3584d2013-12-27 16:32:38 +08002878 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879}
2880
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002881static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002882 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002883 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002884 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002885 [RTA_PRIORITY] = { .type = NLA_U32 },
2886 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002887 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002888 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002889 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2890 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08002891 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09002892 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08002893 [RTA_MARK] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002894};
2895
2896static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06002897 struct fib6_config *cfg,
2898 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899{
Thomas Graf86872cb2006-08-22 00:01:08 -07002900 struct rtmsg *rtm;
2901 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002902 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002903 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
Johannes Bergfceb6432017-04-12 14:34:07 +02002905 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
2906 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07002907 if (err < 0)
2908 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
Thomas Graf86872cb2006-08-22 00:01:08 -07002910 err = -EINVAL;
2911 rtm = nlmsg_data(nlh);
2912 memset(cfg, 0, sizeof(*cfg));
2913
2914 cfg->fc_table = rtm->rtm_table;
2915 cfg->fc_dst_len = rtm->rtm_dst_len;
2916 cfg->fc_src_len = rtm->rtm_src_len;
2917 cfg->fc_flags = RTF_UP;
2918 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002919 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002920
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002921 if (rtm->rtm_type == RTN_UNREACHABLE ||
2922 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002923 rtm->rtm_type == RTN_PROHIBIT ||
2924 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002925 cfg->fc_flags |= RTF_REJECT;
2926
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002927 if (rtm->rtm_type == RTN_LOCAL)
2928 cfg->fc_flags |= RTF_LOCAL;
2929
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002930 if (rtm->rtm_flags & RTM_F_CLONED)
2931 cfg->fc_flags |= RTF_CACHE;
2932
Eric W. Biederman15e47302012-09-07 20:12:54 +00002933 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002934 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002935 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002936
2937 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002938 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002939 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002941
2942 if (tb[RTA_DST]) {
2943 int plen = (rtm->rtm_dst_len + 7) >> 3;
2944
2945 if (nla_len(tb[RTA_DST]) < plen)
2946 goto errout;
2947
2948 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002950
2951 if (tb[RTA_SRC]) {
2952 int plen = (rtm->rtm_src_len + 7) >> 3;
2953
2954 if (nla_len(tb[RTA_SRC]) < plen)
2955 goto errout;
2956
2957 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002959
Daniel Walterc3968a82011-04-13 21:10:57 +00002960 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002961 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002962
Thomas Graf86872cb2006-08-22 00:01:08 -07002963 if (tb[RTA_OIF])
2964 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2965
2966 if (tb[RTA_PRIORITY])
2967 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2968
2969 if (tb[RTA_METRICS]) {
2970 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2971 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002973
2974 if (tb[RTA_TABLE])
2975 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2976
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002977 if (tb[RTA_MULTIPATH]) {
2978 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2979 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08002980
2981 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06002982 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08002983 if (err < 0)
2984 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002985 }
2986
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002987 if (tb[RTA_PREF]) {
2988 pref = nla_get_u8(tb[RTA_PREF]);
2989 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2990 pref != ICMPV6_ROUTER_PREF_HIGH)
2991 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2992 cfg->fc_flags |= RTF_PREF(pref);
2993 }
2994
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002995 if (tb[RTA_ENCAP])
2996 cfg->fc_encap = tb[RTA_ENCAP];
2997
David Ahern9ed59592017-01-17 14:57:36 -08002998 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002999 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
3000
David Ahernc255bd62017-05-27 16:19:27 -06003001 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003002 if (err < 0)
3003 goto errout;
3004 }
3005
Xin Long32bc2012015-12-16 17:50:11 +08003006 if (tb[RTA_EXPIRES]) {
3007 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
3008
3009 if (addrconf_finite_timeout(timeout)) {
3010 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
3011 cfg->fc_flags |= RTF_EXPIRES;
3012 }
3013 }
3014
Thomas Graf86872cb2006-08-22 00:01:08 -07003015 err = 0;
3016errout:
3017 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018}
3019
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003020struct rt6_nh {
3021 struct rt6_info *rt6_info;
3022 struct fib6_config r_cfg;
3023 struct mx6_config mxc;
3024 struct list_head next;
3025};
3026
3027static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
3028{
3029 struct rt6_nh *nh;
3030
3031 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08003032 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 -07003033 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
3034 nh->r_cfg.fc_ifindex);
3035 }
3036}
3037
3038static int ip6_route_info_append(struct list_head *rt6_nh_list,
3039 struct rt6_info *rt, struct fib6_config *r_cfg)
3040{
3041 struct rt6_nh *nh;
3042 struct rt6_info *rtnh;
3043 int err = -EEXIST;
3044
3045 list_for_each_entry(nh, rt6_nh_list, next) {
3046 /* check if rt6_info already exists */
3047 rtnh = nh->rt6_info;
3048
3049 if (rtnh->dst.dev == rt->dst.dev &&
3050 rtnh->rt6i_idev == rt->rt6i_idev &&
3051 ipv6_addr_equal(&rtnh->rt6i_gateway,
3052 &rt->rt6i_gateway))
3053 return err;
3054 }
3055
3056 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
3057 if (!nh)
3058 return -ENOMEM;
3059 nh->rt6_info = rt;
3060 err = ip6_convert_metrics(&nh->mxc, r_cfg);
3061 if (err) {
3062 kfree(nh);
3063 return err;
3064 }
3065 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
3066 list_add_tail(&nh->next, rt6_nh_list);
3067
3068 return 0;
3069}
3070
David Ahern3b1137f2017-02-02 12:37:10 -08003071static void ip6_route_mpath_notify(struct rt6_info *rt,
3072 struct rt6_info *rt_last,
3073 struct nl_info *info,
3074 __u16 nlflags)
3075{
3076 /* if this is an APPEND route, then rt points to the first route
3077 * inserted and rt_last points to last route inserted. Userspace
3078 * wants a consistent dump of the route which starts at the first
3079 * nexthop. Since sibling routes are always added at the end of
3080 * the list, find the first sibling of the last route appended
3081 */
3082 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
3083 rt = list_first_entry(&rt_last->rt6i_siblings,
3084 struct rt6_info,
3085 rt6i_siblings);
3086 }
3087
3088 if (rt)
3089 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
3090}
3091
David Ahern333c4302017-05-21 10:12:04 -06003092static int ip6_route_multipath_add(struct fib6_config *cfg,
3093 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003094{
David Ahern3b1137f2017-02-02 12:37:10 -08003095 struct rt6_info *rt_notif = NULL, *rt_last = NULL;
3096 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003097 struct fib6_config r_cfg;
3098 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003099 struct rt6_info *rt;
3100 struct rt6_nh *err_nh;
3101 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08003102 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003103 int remaining;
3104 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003105 int err = 1;
3106 int nhn = 0;
3107 int replace = (cfg->fc_nlinfo.nlh &&
3108 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
3109 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003110
David Ahern3b1137f2017-02-02 12:37:10 -08003111 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
3112 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
3113 nlflags |= NLM_F_APPEND;
3114
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02003115 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003116 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003117
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003118 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
3119 * rt6_info structs per nexthop
3120 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003121 while (rtnh_ok(rtnh, remaining)) {
3122 memcpy(&r_cfg, cfg, sizeof(*cfg));
3123 if (rtnh->rtnh_ifindex)
3124 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3125
3126 attrlen = rtnh_attrlen(rtnh);
3127 if (attrlen > 0) {
3128 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3129
3130 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3131 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003132 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003133 r_cfg.fc_flags |= RTF_GATEWAY;
3134 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003135 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
3136 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
3137 if (nla)
3138 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003139 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003140
David Ahern333c4302017-05-21 10:12:04 -06003141 rt = ip6_route_info_create(&r_cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003142 if (IS_ERR(rt)) {
3143 err = PTR_ERR(rt);
3144 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003145 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003146 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003147
3148 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003149 if (err) {
Wei Wang587fea72017-06-17 10:42:36 -07003150 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003151 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003152 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003153
3154 rtnh = rtnh_next(rtnh, &remaining);
3155 }
3156
David Ahern3b1137f2017-02-02 12:37:10 -08003157 /* for add and replace send one notification with all nexthops.
3158 * Skip the notification in fib6_add_rt2node and send one with
3159 * the full route when done
3160 */
3161 info->skip_notify = 1;
3162
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003163 err_nh = NULL;
3164 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern3b1137f2017-02-02 12:37:10 -08003165 rt_last = nh->rt6_info;
David Ahern333c4302017-05-21 10:12:04 -06003166 err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
David Ahern3b1137f2017-02-02 12:37:10 -08003167 /* save reference to first route for notification */
3168 if (!rt_notif && !err)
3169 rt_notif = nh->rt6_info;
3170
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003171 /* nh->rt6_info is used or freed at this point, reset to NULL*/
3172 nh->rt6_info = NULL;
3173 if (err) {
3174 if (replace && nhn)
3175 ip6_print_replace_route_err(&rt6_nh_list);
3176 err_nh = nh;
3177 goto add_errout;
3178 }
3179
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003180 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02003181 * these flags after the first nexthop: if there is a collision,
3182 * we have already failed to add the first nexthop:
3183 * fib6_add_rt2node() has rejected it; when replacing, old
3184 * nexthops have been replaced by first new, the rest should
3185 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003186 */
Michal Kubeček27596472015-05-18 20:54:00 +02003187 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
3188 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003189 nhn++;
3190 }
3191
David Ahern3b1137f2017-02-02 12:37:10 -08003192 /* success ... tell user about new route */
3193 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003194 goto cleanup;
3195
3196add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08003197 /* send notification for routes that were added so that
3198 * the delete notifications sent by ip6_route_del are
3199 * coherent
3200 */
3201 if (rt_notif)
3202 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
3203
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003204 /* Delete routes that were already added */
3205 list_for_each_entry(nh, &rt6_nh_list, next) {
3206 if (err_nh == nh)
3207 break;
David Ahern333c4302017-05-21 10:12:04 -06003208 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003209 }
3210
3211cleanup:
3212 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
Wei Wang587fea72017-06-17 10:42:36 -07003213 if (nh->rt6_info)
3214 dst_release_immediate(&nh->rt6_info->dst);
Wu Fengguang52fe51f2015-09-10 06:57:12 +08003215 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003216 list_del(&nh->next);
3217 kfree(nh);
3218 }
3219
3220 return err;
3221}
3222
David Ahern333c4302017-05-21 10:12:04 -06003223static int ip6_route_multipath_del(struct fib6_config *cfg,
3224 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003225{
3226 struct fib6_config r_cfg;
3227 struct rtnexthop *rtnh;
3228 int remaining;
3229 int attrlen;
3230 int err = 1, last_err = 0;
3231
3232 remaining = cfg->fc_mp_len;
3233 rtnh = (struct rtnexthop *)cfg->fc_mp;
3234
3235 /* Parse a Multipath Entry */
3236 while (rtnh_ok(rtnh, remaining)) {
3237 memcpy(&r_cfg, cfg, sizeof(*cfg));
3238 if (rtnh->rtnh_ifindex)
3239 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3240
3241 attrlen = rtnh_attrlen(rtnh);
3242 if (attrlen > 0) {
3243 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3244
3245 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3246 if (nla) {
3247 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
3248 r_cfg.fc_flags |= RTF_GATEWAY;
3249 }
3250 }
David Ahern333c4302017-05-21 10:12:04 -06003251 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003252 if (err)
3253 last_err = err;
3254
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003255 rtnh = rtnh_next(rtnh, &remaining);
3256 }
3257
3258 return last_err;
3259}
3260
David Ahernc21ef3e2017-04-16 09:48:24 -07003261static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3262 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263{
Thomas Graf86872cb2006-08-22 00:01:08 -07003264 struct fib6_config cfg;
3265 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266
David Ahern333c4302017-05-21 10:12:04 -06003267 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003268 if (err < 0)
3269 return err;
3270
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003271 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003272 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003273 else {
3274 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06003275 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277}
3278
David Ahernc21ef3e2017-04-16 09:48:24 -07003279static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3280 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281{
Thomas Graf86872cb2006-08-22 00:01:08 -07003282 struct fib6_config cfg;
3283 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
David Ahern333c4302017-05-21 10:12:04 -06003285 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003286 if (err < 0)
3287 return err;
3288
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003289 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003290 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003291 else
David Ahern333c4302017-05-21 10:12:04 -06003292 return ip6_route_add(&cfg, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293}
3294
David Ahernbeb1afac52017-02-02 12:37:09 -08003295static size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08003296{
David Ahernbeb1afac52017-02-02 12:37:09 -08003297 int nexthop_len = 0;
3298
3299 if (rt->rt6i_nsiblings) {
3300 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
3301 + NLA_ALIGN(sizeof(struct rtnexthop))
3302 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernbeb1afac52017-02-02 12:37:09 -08003303 + lwtunnel_get_encap_size(rt->dst.lwtstate);
3304
3305 nexthop_len *= rt->rt6i_nsiblings;
3306 }
3307
Thomas Graf339bf982006-11-10 14:10:15 -08003308 return NLMSG_ALIGN(sizeof(struct rtmsg))
3309 + nla_total_size(16) /* RTA_SRC */
3310 + nla_total_size(16) /* RTA_DST */
3311 + nla_total_size(16) /* RTA_GATEWAY */
3312 + nla_total_size(16) /* RTA_PREFSRC */
3313 + nla_total_size(4) /* RTA_TABLE */
3314 + nla_total_size(4) /* RTA_IIF */
3315 + nla_total_size(4) /* RTA_OIF */
3316 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08003317 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01003318 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003319 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003320 + nla_total_size(1) /* RTA_PREF */
David Ahernbeb1afac52017-02-02 12:37:09 -08003321 + lwtunnel_get_encap_size(rt->dst.lwtstate)
3322 + nexthop_len;
3323}
3324
3325static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08003326 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08003327{
3328 if (!netif_running(rt->dst.dev) || !netif_carrier_ok(rt->dst.dev)) {
3329 *flags |= RTNH_F_LINKDOWN;
3330 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3331 *flags |= RTNH_F_DEAD;
3332 }
3333
3334 if (rt->rt6i_flags & RTF_GATEWAY) {
3335 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
3336 goto nla_put_failure;
3337 }
3338
David Ahern5be083c2017-03-06 15:57:31 -08003339 /* not needed for multipath encoding b/c it has a rtnexthop struct */
3340 if (!skip_oif && rt->dst.dev &&
David Ahernbeb1afac52017-02-02 12:37:09 -08003341 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
3342 goto nla_put_failure;
3343
3344 if (rt->dst.lwtstate &&
3345 lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
3346 goto nla_put_failure;
3347
3348 return 0;
3349
3350nla_put_failure:
3351 return -EMSGSIZE;
3352}
3353
David Ahern5be083c2017-03-06 15:57:31 -08003354/* add multipath next hop */
David Ahernbeb1afac52017-02-02 12:37:09 -08003355static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
3356{
3357 struct rtnexthop *rtnh;
3358 unsigned int flags = 0;
3359
3360 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
3361 if (!rtnh)
3362 goto nla_put_failure;
3363
3364 rtnh->rtnh_hops = 0;
3365 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
3366
David Ahern5be083c2017-03-06 15:57:31 -08003367 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003368 goto nla_put_failure;
3369
3370 rtnh->rtnh_flags = flags;
3371
3372 /* length of rtnetlink header + attributes */
3373 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
3374
3375 return 0;
3376
3377nla_put_failure:
3378 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08003379}
3380
Brian Haley191cd582008-08-14 15:33:21 -07003381static int rt6_fill_node(struct net *net,
3382 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07003383 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003384 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003385 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003387 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003389 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08003390 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07003391 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
Eric W. Biederman15e47302012-09-07 20:12:54 +00003393 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05003394 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08003395 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003396
3397 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 rtm->rtm_family = AF_INET6;
3399 rtm->rtm_dst_len = rt->rt6i_dst.plen;
3400 rtm->rtm_src_len = rt->rt6i_src.plen;
3401 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07003402 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07003403 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07003404 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07003405 table = RT6_TABLE_UNSPEC;
3406 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04003407 if (nla_put_u32(skb, RTA_TABLE, table))
3408 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003409 if (rt->rt6i_flags & RTF_REJECT) {
3410 switch (rt->dst.error) {
3411 case -EINVAL:
3412 rtm->rtm_type = RTN_BLACKHOLE;
3413 break;
3414 case -EACCES:
3415 rtm->rtm_type = RTN_PROHIBIT;
3416 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003417 case -EAGAIN:
3418 rtm->rtm_type = RTN_THROW;
3419 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003420 default:
3421 rtm->rtm_type = RTN_UNREACHABLE;
3422 break;
3423 }
3424 }
David S. Miller38308472011-12-03 18:02:47 -05003425 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003426 rtm->rtm_type = RTN_LOCAL;
David Ahern4ee39732017-03-15 18:14:33 -07003427 else if (rt->rt6i_flags & RTF_ANYCAST)
3428 rtm->rtm_type = RTN_ANYCAST;
David S. Millerd1918542011-12-28 20:19:20 -05003429 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 rtm->rtm_type = RTN_LOCAL;
3431 else
3432 rtm->rtm_type = RTN_UNICAST;
3433 rtm->rtm_flags = 0;
3434 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
3435 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05003436 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00003438 else if (rt->rt6i_flags & RTF_ADDRCONF) {
3439 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
3440 rtm->rtm_protocol = RTPROT_RA;
3441 else
3442 rtm->rtm_protocol = RTPROT_KERNEL;
3443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
David S. Miller38308472011-12-03 18:02:47 -05003445 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 rtm->rtm_flags |= RTM_F_CLONED;
3447
3448 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02003449 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04003450 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003451 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02003453 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003454 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455#ifdef CONFIG_IPV6_SUBTREES
3456 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02003457 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04003458 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003459 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04003460 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02003461 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003462 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003464 if (iif) {
3465#ifdef CONFIG_IPV6_MROUTE
3466 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08003467 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02003468
David Ahernfd61c6b2017-01-17 15:51:07 -08003469 if (err == 0)
3470 return 0;
3471 if (err < 0)
3472 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003473 } else
3474#endif
David S. Millerc78679e2012-04-01 20:27:33 -04003475 if (nla_put_u32(skb, RTA_IIF, iif))
3476 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003477 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04003479 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02003480 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003481 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003483
Daniel Walterc3968a82011-04-13 21:10:57 +00003484 if (rt->rt6i_prefsrc.plen) {
3485 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003486 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02003487 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003488 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00003489 }
3490
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003491 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
3492 if (rt->rt6i_pmtu)
3493 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
3494 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07003495 goto nla_put_failure;
3496
David S. Millerc78679e2012-04-01 20:27:33 -04003497 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
3498 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00003499
David Ahernbeb1afac52017-02-02 12:37:09 -08003500 /* For multipath routes, walk the siblings list and add
3501 * each as a nexthop within RTA_MULTIPATH.
3502 */
3503 if (rt->rt6i_nsiblings) {
3504 struct rt6_info *sibling, *next_sibling;
3505 struct nlattr *mp;
3506
3507 mp = nla_nest_start(skb, RTA_MULTIPATH);
3508 if (!mp)
3509 goto nla_put_failure;
3510
3511 if (rt6_add_nexthop(skb, rt) < 0)
3512 goto nla_put_failure;
3513
3514 list_for_each_entry_safe(sibling, next_sibling,
3515 &rt->rt6i_siblings, rt6i_siblings) {
3516 if (rt6_add_nexthop(skb, sibling) < 0)
3517 goto nla_put_failure;
3518 }
3519
3520 nla_nest_end(skb, mp);
3521 } else {
David Ahern5be083c2017-03-06 15:57:31 -08003522 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003523 goto nla_put_failure;
3524 }
3525
Li Wei82539472012-07-29 16:01:30 +00003526 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07003527
David S. Miller87a50692012-07-10 05:06:14 -07003528 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08003529 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003531 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3532 goto nla_put_failure;
3533
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003534
Johannes Berg053c0952015-01-16 22:09:00 +01003535 nlmsg_end(skb, nlh);
3536 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003537
3538nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08003539 nlmsg_cancel(skb, nlh);
3540 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541}
3542
Patrick McHardy1b43af52006-08-10 23:11:17 -07003543int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544{
3545 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08003546 struct net *net = arg->net;
3547
3548 if (rt == net->ipv6.ip6_null_entry)
3549 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
Thomas Graf2d7202b2006-08-22 00:01:27 -07003551 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
3552 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08003553
3554 /* user wants prefix routes only */
3555 if (rtm->rtm_flags & RTM_F_PREFIX &&
3556 !(rt->rt6i_flags & RTF_PREFIX_RT)) {
3557 /* success since this is not a prefix route */
3558 return 1;
3559 }
3560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
David Ahern1f17e2f2017-01-26 13:54:08 -08003562 return rt6_fill_node(net,
Brian Haley191cd582008-08-14 15:33:21 -07003563 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003564 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003565 NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566}
3567
David Ahernc21ef3e2017-04-16 09:48:24 -07003568static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
3569 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003571 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003572 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003573 int err, iif = 0, oif = 0;
3574 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003576 struct sk_buff *skb;
3577 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003578 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003579 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07003580
Johannes Bergfceb6432017-04-12 14:34:07 +02003581 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07003582 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07003583 if (err < 0)
3584 goto errout;
3585
3586 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003587 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02003588 rtm = nlmsg_data(nlh);
3589 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003590 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07003591
3592 if (tb[RTA_SRC]) {
3593 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3594 goto errout;
3595
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003596 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003597 }
3598
3599 if (tb[RTA_DST]) {
3600 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3601 goto errout;
3602
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003603 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003604 }
3605
3606 if (tb[RTA_IIF])
3607 iif = nla_get_u32(tb[RTA_IIF]);
3608
3609 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003610 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003611
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003612 if (tb[RTA_MARK])
3613 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3614
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09003615 if (tb[RTA_UID])
3616 fl6.flowi6_uid = make_kuid(current_user_ns(),
3617 nla_get_u32(tb[RTA_UID]));
3618 else
3619 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
3620
Thomas Grafab364a62006-08-22 00:01:47 -07003621 if (iif) {
3622 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003623 int flags = 0;
3624
Daniel Lezcano55786892008-03-04 13:47:47 -08003625 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003626 if (!dev) {
3627 err = -ENODEV;
3628 goto errout;
3629 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003630
3631 fl6.flowi6_iif = iif;
3632
3633 if (!ipv6_addr_any(&fl6.saddr))
3634 flags |= RT6_LOOKUP_F_HAS_SADDR;
3635
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003636 if (!fibmatch)
3637 dst = ip6_route_input_lookup(net, dev, &fl6, flags);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003638 } else {
3639 fl6.flowi6_oif = oif;
3640
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003641 if (!fibmatch)
3642 dst = ip6_route_output(net, NULL, &fl6);
3643 }
3644
3645 if (fibmatch)
3646 dst = ip6_route_lookup(net, &fl6, 0);
3647
3648 rt = container_of(dst, struct rt6_info, dst);
3649 if (rt->dst.error) {
3650 err = rt->dst.error;
3651 ip6_rt_put(rt);
3652 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07003653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654
WANG Cong9d6acb32017-03-01 20:48:39 -08003655 if (rt == net->ipv6.ip6_null_entry) {
3656 err = rt->dst.error;
3657 ip6_rt_put(rt);
3658 goto errout;
3659 }
3660
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003662 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003663 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003664 err = -ENOBUFS;
3665 goto errout;
3666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667
Changli Gaod8d1f302010-06-10 23:31:35 -07003668 skb_dst_set(skb, &rt->dst);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003669 if (fibmatch)
3670 err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
3671 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3672 nlh->nlmsg_seq, 0);
3673 else
3674 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
3675 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3676 nlh->nlmsg_seq, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003678 kfree_skb(skb);
3679 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 }
3681
Eric W. Biederman15e47302012-09-07 20:12:54 +00003682 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003683errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685}
3686
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003687void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
3688 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689{
3690 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003691 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003692 u32 seq;
3693 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003695 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003696 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003697
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003698 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003699 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003700 goto errout;
3701
Brian Haley191cd582008-08-14 15:33:21 -07003702 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003703 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003704 if (err < 0) {
3705 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3706 WARN_ON(err == -EMSGSIZE);
3707 kfree_skb(skb);
3708 goto errout;
3709 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003710 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003711 info->nlh, gfp_any());
3712 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003713errout:
3714 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003715 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716}
3717
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003718static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003719 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003720{
Jiri Pirko351638e2013-05-28 01:30:21 +00003721 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003722 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003723
WANG Cong242d3a42017-05-08 10:12:13 -07003724 if (!(dev->flags & IFF_LOOPBACK))
3725 return NOTIFY_OK;
3726
3727 if (event == NETDEV_REGISTER) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003728 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003729 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3730#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003731 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003732 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003733 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003734 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3735#endif
WANG Cong242d3a42017-05-08 10:12:13 -07003736 } else if (event == NETDEV_UNREGISTER) {
3737 in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev);
3738#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3739 in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev);
3740 in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev);
3741#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003742 }
3743
3744 return NOTIFY_OK;
3745}
3746
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747/*
3748 * /proc
3749 */
3750
3751#ifdef CONFIG_PROC_FS
3752
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003753static const struct file_operations ipv6_route_proc_fops = {
3754 .owner = THIS_MODULE,
3755 .open = ipv6_route_open,
3756 .read = seq_read,
3757 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003758 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003759};
3760
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3762{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003763 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003765 net->ipv6.rt6_stats->fib_nodes,
3766 net->ipv6.rt6_stats->fib_route_nodes,
3767 net->ipv6.rt6_stats->fib_rt_alloc,
3768 net->ipv6.rt6_stats->fib_rt_entries,
3769 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003770 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003771 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
3773 return 0;
3774}
3775
3776static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3777{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003778 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003779}
3780
Arjan van de Ven9a321442007-02-12 00:55:35 -08003781static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 .owner = THIS_MODULE,
3783 .open = rt6_stats_seq_open,
3784 .read = seq_read,
3785 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003786 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787};
3788#endif /* CONFIG_PROC_FS */
3789
3790#ifdef CONFIG_SYSCTL
3791
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003793int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 void __user *buffer, size_t *lenp, loff_t *ppos)
3795{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003796 struct net *net;
3797 int delay;
3798 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003800
3801 net = (struct net *)ctl->extra1;
3802 delay = net->ipv6.sysctl.flush_delay;
3803 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003804 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003805 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806}
3807
Joe Perchesfe2c6332013-06-11 23:04:25 -07003808struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003809 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003811 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003813 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003814 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 },
3816 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003818 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 .maxlen = sizeof(int),
3820 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003821 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 },
3823 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003825 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 .maxlen = sizeof(int),
3827 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003828 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 },
3830 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003832 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 .maxlen = sizeof(int),
3834 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003835 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 },
3837 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003839 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 .maxlen = sizeof(int),
3841 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003842 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 },
3844 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003846 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 .maxlen = sizeof(int),
3848 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003849 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 },
3851 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003853 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 .maxlen = sizeof(int),
3855 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003856 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 },
3858 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003860 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 .maxlen = sizeof(int),
3862 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003863 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 },
3865 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003867 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 .maxlen = sizeof(int),
3869 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003870 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 },
3872 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003874 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 .maxlen = sizeof(int),
3876 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003877 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003879 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880};
3881
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003882struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003883{
3884 struct ctl_table *table;
3885
3886 table = kmemdup(ipv6_route_table_template,
3887 sizeof(ipv6_route_table_template),
3888 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003889
3890 if (table) {
3891 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003892 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003893 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003894 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3895 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3896 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3897 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3898 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3899 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3900 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003901 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003902
3903 /* Don't export sysctls to unprivileged users */
3904 if (net->user_ns != &init_user_ns)
3905 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003906 }
3907
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003908 return table;
3909}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910#endif
3911
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003912static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003913{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003914 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003915
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003916 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3917 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003918
Eric Dumazetfc66f952010-10-08 06:37:34 +00003919 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3920 goto out_ip6_dst_ops;
3921
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003922 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3923 sizeof(*net->ipv6.ip6_null_entry),
3924 GFP_KERNEL);
3925 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003926 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003927 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003928 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003929 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003930 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3931 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003932
3933#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3934 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3935 sizeof(*net->ipv6.ip6_prohibit_entry),
3936 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003937 if (!net->ipv6.ip6_prohibit_entry)
3938 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003939 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003940 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003941 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003942 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3943 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003944
3945 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3946 sizeof(*net->ipv6.ip6_blk_hole_entry),
3947 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003948 if (!net->ipv6.ip6_blk_hole_entry)
3949 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003950 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003951 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003952 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003953 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3954 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003955#endif
3956
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003957 net->ipv6.sysctl.flush_delay = 0;
3958 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3959 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3960 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3961 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3962 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3963 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3964 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3965
Benjamin Thery6891a342008-03-04 13:49:47 -08003966 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3967
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003968 ret = 0;
3969out:
3970 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003971
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003972#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3973out_ip6_prohibit_entry:
3974 kfree(net->ipv6.ip6_prohibit_entry);
3975out_ip6_null_entry:
3976 kfree(net->ipv6.ip6_null_entry);
3977#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003978out_ip6_dst_entries:
3979 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003980out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003981 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003982}
3983
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003984static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003985{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003986 kfree(net->ipv6.ip6_null_entry);
3987#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3988 kfree(net->ipv6.ip6_prohibit_entry);
3989 kfree(net->ipv6.ip6_blk_hole_entry);
3990#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003991 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003992}
3993
Thomas Grafd1896342012-06-18 12:08:33 +00003994static int __net_init ip6_route_net_init_late(struct net *net)
3995{
3996#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003997 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3998 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003999#endif
4000 return 0;
4001}
4002
4003static void __net_exit ip6_route_net_exit_late(struct net *net)
4004{
4005#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00004006 remove_proc_entry("ipv6_route", net->proc_net);
4007 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00004008#endif
4009}
4010
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004011static struct pernet_operations ip6_route_net_ops = {
4012 .init = ip6_route_net_init,
4013 .exit = ip6_route_net_exit,
4014};
4015
David S. Millerc3426b42012-06-09 16:27:05 -07004016static int __net_init ipv6_inetpeer_init(struct net *net)
4017{
4018 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
4019
4020 if (!bp)
4021 return -ENOMEM;
4022 inet_peer_base_init(bp);
4023 net->ipv6.peers = bp;
4024 return 0;
4025}
4026
4027static void __net_exit ipv6_inetpeer_exit(struct net *net)
4028{
4029 struct inet_peer_base *bp = net->ipv6.peers;
4030
4031 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07004032 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07004033 kfree(bp);
4034}
4035
David S. Miller2b823f72012-06-09 19:00:16 -07004036static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07004037 .init = ipv6_inetpeer_init,
4038 .exit = ipv6_inetpeer_exit,
4039};
4040
Thomas Grafd1896342012-06-18 12:08:33 +00004041static struct pernet_operations ip6_route_net_late_ops = {
4042 .init = ip6_route_net_init_late,
4043 .exit = ip6_route_net_exit_late,
4044};
4045
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004046static struct notifier_block ip6_route_dev_notifier = {
4047 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07004048 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004049};
4050
WANG Cong2f460932017-05-03 22:07:31 -07004051void __init ip6_route_init_special_entries(void)
4052{
4053 /* Registering of the loopback is done before this portion of code,
4054 * the loopback reference in rt6_info will not be taken, do it
4055 * manually for init_net */
4056 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
4057 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4058 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
4059 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
4060 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4061 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
4062 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4063 #endif
4064}
4065
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004066int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004068 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004069 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004070
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004071 ret = -ENOMEM;
4072 ip6_dst_ops_template.kmem_cachep =
4073 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
4074 SLAB_HWCACHE_ALIGN, NULL);
4075 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08004076 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07004077
Eric Dumazetfc66f952010-10-08 06:37:34 +00004078 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004079 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004080 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004081
David S. Millerc3426b42012-06-09 16:27:05 -07004082 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
4083 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004084 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00004085
David S. Miller7e52b332012-06-15 15:51:55 -07004086 ret = register_pernet_subsys(&ip6_route_net_ops);
4087 if (ret)
4088 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07004089
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07004090 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
4091
David S. Millere8803b62012-06-16 01:12:19 -07004092 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004093 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004094 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004095
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004096 ret = xfrm6_init();
4097 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004098 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08004099
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004100 ret = fib6_rules_init();
4101 if (ret)
4102 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08004103
Thomas Grafd1896342012-06-18 12:08:33 +00004104 ret = register_pernet_subsys(&ip6_route_net_late_ops);
4105 if (ret)
4106 goto fib6_rules_init;
4107
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004108 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00004109 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
4110 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
4111 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00004112 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004113
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004114 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004115 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00004116 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004117
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004118 for_each_possible_cpu(cpu) {
4119 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
4120
4121 INIT_LIST_HEAD(&ul->head);
4122 spin_lock_init(&ul->lock);
4123 }
4124
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004125out:
4126 return ret;
4127
Thomas Grafd1896342012-06-18 12:08:33 +00004128out_register_late_subsys:
4129 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004130fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004131 fib6_rules_cleanup();
4132xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004133 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00004134out_fib6_init:
4135 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004136out_register_subsys:
4137 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07004138out_register_inetpeer:
4139 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00004140out_dst_entries:
4141 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004142out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004143 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004144 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145}
4146
4147void ip6_route_cleanup(void)
4148{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004149 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00004150 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07004151 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07004154 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004155 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004156 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004157 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158}