blob: 9b02064c33351a0345f878add3dc10374d691cb1 [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
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700131 rt->rt6i_uncached_list = ul;
132
133 spin_lock_bh(&ul->lock);
134 list_add_tail(&rt->rt6i_uncached, &ul->head);
135 spin_unlock_bh(&ul->lock);
136}
137
138static void rt6_uncached_list_del(struct rt6_info *rt)
139{
140 if (!list_empty(&rt->rt6i_uncached)) {
141 struct uncached_list *ul = rt->rt6i_uncached_list;
142
143 spin_lock_bh(&ul->lock);
144 list_del(&rt->rt6i_uncached);
145 spin_unlock_bh(&ul->lock);
146 }
147}
148
149static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
150{
151 struct net_device *loopback_dev = net->loopback_dev;
152 int cpu;
153
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500154 if (dev == loopback_dev)
155 return;
156
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700157 for_each_possible_cpu(cpu) {
158 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
159 struct rt6_info *rt;
160
161 spin_lock_bh(&ul->lock);
162 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
163 struct inet6_dev *rt_idev = rt->rt6i_idev;
164 struct net_device *rt_dev = rt->dst.dev;
165
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500166 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700167 rt->rt6i_idev = in6_dev_get(loopback_dev);
168 in6_dev_put(rt_idev);
169 }
170
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500171 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700172 rt->dst.dev = loopback_dev;
173 dev_hold(rt->dst.dev);
174 dev_put(rt_dev);
175 }
176 }
177 spin_unlock_bh(&ul->lock);
178 }
179}
180
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700181static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
182{
183 return dst_metrics_write_ptr(rt->dst.from);
184}
185
David S. Miller06582542011-01-27 14:58:42 -0800186static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
187{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700188 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800189
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700190 if (rt->rt6i_flags & RTF_PCPU)
191 return rt6_pcpu_cow_metrics(rt);
192 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700193 return NULL;
194 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800195 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800196}
197
David S. Millerf894cbf2012-07-02 21:52:24 -0700198static inline const void *choose_neigh_daddr(struct rt6_info *rt,
199 struct sk_buff *skb,
200 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500201{
202 struct in6_addr *p = &rt->rt6i_gateway;
203
David S. Millera7563f32012-01-26 16:29:16 -0500204 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500205 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700206 else if (skb)
207 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500208 return daddr;
209}
210
David S. Millerf894cbf2012-07-02 21:52:24 -0700211static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
212 struct sk_buff *skb,
213 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700214{
David S. Miller39232972012-01-26 15:22:32 -0500215 struct rt6_info *rt = (struct rt6_info *) dst;
216 struct neighbour *n;
217
David S. Millerf894cbf2012-07-02 21:52:24 -0700218 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000219 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500220 if (n)
221 return n;
222 return neigh_create(&nd_tbl, daddr, dst->dev);
223}
224
Julian Anastasov63fca652017-02-06 23:14:15 +0200225static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
226{
227 struct net_device *dev = dst->dev;
228 struct rt6_info *rt = (struct rt6_info *)dst;
229
230 daddr = choose_neigh_daddr(rt, NULL, daddr);
231 if (!daddr)
232 return;
233 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
234 return;
235 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
236 return;
237 __ipv6_confirm_neigh(dev, daddr);
238}
239
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800240static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .gc = ip6_dst_gc,
243 .gc_thresh = 1024,
244 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800245 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000246 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800247 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 .destroy = ip6_dst_destroy,
249 .ifdown = ip6_dst_ifdown,
250 .negative_advice = ip6_negative_advice,
251 .link_failure = ip6_link_failure,
252 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700253 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500254 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700255 .neigh_lookup = ip6_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200256 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257};
258
Steffen Klassertebb762f2011-11-23 02:12:51 +0000259static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800260{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000261 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
262
263 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800264}
265
David S. Miller6700c272012-07-17 03:29:28 -0700266static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
267 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700268{
269}
270
David S. Miller6700c272012-07-17 03:29:28 -0700271static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
272 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700273{
274}
275
David S. Miller14e50e52007-05-24 18:17:54 -0700276static struct dst_ops ip6_dst_blackhole_ops = {
277 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700278 .destroy = ip6_dst_destroy,
279 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000280 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800281 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700282 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700283 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700284 .cow_metrics = dst_cow_metrics_generic,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700285 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700286};
287
David S. Miller62fa8a82011-01-26 20:51:05 -0800288static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800289 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800290};
291
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000292static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700293 .dst = {
294 .__refcnt = ATOMIC_INIT(1),
295 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000296 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700297 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700298 .input = ip6_pkt_discard,
299 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 },
301 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700302 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 .rt6i_metric = ~(u32) 0,
304 .rt6i_ref = ATOMIC_INIT(1),
305};
306
Thomas Graf101367c2006-08-04 03:39:02 -0700307#ifdef CONFIG_IPV6_MULTIPLE_TABLES
308
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000309static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700310 .dst = {
311 .__refcnt = ATOMIC_INIT(1),
312 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000313 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700314 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700315 .input = ip6_pkt_prohibit,
316 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700317 },
318 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700319 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700320 .rt6i_metric = ~(u32) 0,
321 .rt6i_ref = ATOMIC_INIT(1),
322};
323
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000324static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700325 .dst = {
326 .__refcnt = ATOMIC_INIT(1),
327 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000328 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700329 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700330 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500331 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700332 },
333 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700334 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700335 .rt6i_metric = ~(u32) 0,
336 .rt6i_ref = ATOMIC_INIT(1),
337};
338
339#endif
340
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700341static void rt6_info_init(struct rt6_info *rt)
342{
343 struct dst_entry *dst = &rt->dst;
344
345 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
346 INIT_LIST_HEAD(&rt->rt6i_siblings);
347 INIT_LIST_HEAD(&rt->rt6i_uncached);
348}
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700351static struct rt6_info *__ip6_dst_alloc(struct net *net,
352 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700353 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
David S. Miller97bab732012-06-09 22:36:36 -0700355 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700356 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700357
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700358 if (rt)
359 rt6_info_init(rt);
Steffen Klassert81048912012-07-05 23:37:09 +0000360
David S. Millercf911662011-04-28 14:31:47 -0700361 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
David Ahern9ab179d2016-04-07 11:10:06 -0700364struct rt6_info *ip6_dst_alloc(struct net *net,
365 struct net_device *dev,
366 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700367{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700368 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700369
370 if (rt) {
371 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
372 if (rt->rt6i_pcpu) {
373 int cpu;
374
375 for_each_possible_cpu(cpu) {
376 struct rt6_info **p;
377
378 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
379 /* no one shares rt */
380 *p = NULL;
381 }
382 } else {
Wei Wang587fea72017-06-17 10:42:36 -0700383 dst_release_immediate(&rt->dst);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700384 return NULL;
385 }
386 }
387
388 return rt;
389}
David Ahern9ab179d2016-04-07 11:10:06 -0700390EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392static void ip6_dst_destroy(struct dst_entry *dst)
393{
394 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000395 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700396 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700398 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200399 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700400 rt6_uncached_list_del(rt);
401
402 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500403 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 rt->rt6i_idev = NULL;
405 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900406 }
Gao feng1716a962012-04-06 00:13:10 +0000407
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000408 dst->from = NULL;
409 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800410}
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
413 int how)
414{
415 struct rt6_info *rt = (struct rt6_info *)dst;
416 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800417 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900418 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Wei Wange5645f52017-08-14 10:44:59 -0700420 if (idev && idev->dev != loopback_dev) {
421 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
422 if (loopback_idev) {
423 rt->rt6i_idev = loopback_idev;
424 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427}
428
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800429static bool __rt6_check_expired(const struct rt6_info *rt)
430{
431 if (rt->rt6i_flags & RTF_EXPIRES)
432 return time_after(jiffies, rt->dst.expires);
433 else
434 return false;
435}
436
Eric Dumazeta50feda2012-05-18 18:57:34 +0000437static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
Gao feng1716a962012-04-06 00:13:10 +0000439 if (rt->rt6i_flags & RTF_EXPIRES) {
440 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000441 return true;
Gao feng1716a962012-04-06 00:13:10 +0000442 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000443 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000444 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000445 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
447
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000448/* Multipath route selection:
449 * Hash based function using packet header and flowlabel.
450 * Adapted from fib_info_hashfn()
451 */
452static int rt6_info_hash_nhsfn(unsigned int candidate_count,
453 const struct flowi6 *fl6)
454{
Tom Herbert644d0e62015-09-23 14:13:35 -0700455 return get_hash_from_flowi6(fl6) % candidate_count;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000456}
457
458static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200459 struct flowi6 *fl6, int oif,
460 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000461{
462 struct rt6_info *sibling, *next_sibling;
463 int route_choosen;
464
465 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
466 /* Don't change the route, if route_choosen == 0
467 * (siblings does not include ourself)
468 */
469 if (route_choosen)
470 list_for_each_entry_safe(sibling, next_sibling,
471 &match->rt6i_siblings, rt6i_siblings) {
472 route_choosen--;
473 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200474 if (rt6_score_route(sibling, oif, strict) < 0)
475 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000476 match = sibling;
477 break;
478 }
479 }
480 return match;
481}
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700484 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 */
486
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800487static inline struct rt6_info *rt6_device_match(struct net *net,
488 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000489 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700491 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
493 struct rt6_info *local = NULL;
494 struct rt6_info *sprt;
495
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900496 if (!oif && ipv6_addr_any(saddr))
497 goto out;
498
Changli Gaod8d1f302010-06-10 23:31:35 -0700499 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500500 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900501
502 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (dev->ifindex == oif)
504 return sprt;
505 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500506 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 sprt->rt6i_idev->dev->ifindex != oif) {
David Ahern17fb0b22015-09-25 15:22:54 -0600508 if (flags & RT6_LOOKUP_F_IFACE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 continue;
David Ahern17fb0b22015-09-25 15:22:54 -0600510 if (local &&
511 local->rt6i_idev->dev->ifindex == oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 continue;
513 }
514 local = sprt;
515 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900516 } else {
517 if (ipv6_chk_addr(net, saddr, dev,
518 flags & RT6_LOOKUP_F_IFACE))
519 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900523 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (local)
525 return local;
526
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700527 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800528 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900530out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return rt;
532}
533
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800534#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200535struct __rt6_probe_work {
536 struct work_struct work;
537 struct in6_addr target;
538 struct net_device *dev;
539};
540
541static void rt6_probe_deferred(struct work_struct *w)
542{
543 struct in6_addr mcaddr;
544 struct __rt6_probe_work *work =
545 container_of(w, struct __rt6_probe_work, work);
546
547 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800548 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200549 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100550 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200551}
552
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800553static void rt6_probe(struct rt6_info *rt)
554{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700555 struct __rt6_probe_work *work;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000556 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800557 /*
558 * Okay, this does not seem to be appropriate
559 * for now, however, we need to check if it
560 * is really so; aka Router Reachability Probing.
561 *
562 * Router Reachability Probe MUST be rate-limited
563 * to no more than one per minute.
564 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000565 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000566 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000567 rcu_read_lock_bh();
568 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
569 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700570 if (neigh->nud_state & NUD_VALID)
571 goto out;
572
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700573 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000574 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700575 if (!(neigh->nud_state & NUD_VALID) &&
576 time_after(jiffies,
577 neigh->updated +
578 rt->rt6i_idev->cnf.rtr_probe_interval)) {
579 work = kmalloc(sizeof(*work), GFP_ATOMIC);
580 if (work)
581 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200582 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000583 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700584 } else {
585 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000586 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700587
588 if (work) {
589 INIT_WORK(&work->work, rt6_probe_deferred);
590 work->target = rt->rt6i_gateway;
591 dev_hold(rt->dst.dev);
592 work->dev = rt->dst.dev;
593 schedule_work(&work->work);
594 }
595
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700596out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000597 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800598}
599#else
600static inline void rt6_probe(struct rt6_info *rt)
601{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800602}
603#endif
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800606 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700608static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609{
David S. Millerd1918542011-12-28 20:19:20 -0500610 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700611 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800612 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700613 if ((dev->flags & IFF_LOOPBACK) &&
614 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
615 return 1;
616 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617}
618
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200619static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000621 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200622 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000623
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700624 if (rt->rt6i_flags & RTF_NONEXTHOP ||
625 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200626 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000627
628 rcu_read_lock_bh();
629 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
630 if (neigh) {
631 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800632 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200633 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800634#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000635 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200636 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100637 else
638 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800639#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000640 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200641 } else {
642 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100643 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000644 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000645 rcu_read_unlock_bh();
646
Paul Marksa5a81f02012-12-03 10:26:54 +0000647 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800648}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800650static int rt6_score_route(struct rt6_info *rt, int oif,
651 int strict)
652{
Paul Marksa5a81f02012-12-03 10:26:54 +0000653 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900654
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700655 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700656 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200657 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800658#ifdef CONFIG_IPV6_ROUTER_PREF
659 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
660#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200661 if (strict & RT6_LOOKUP_F_REACHABLE) {
662 int n = rt6_check_neigh(rt);
663 if (n < 0)
664 return n;
665 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800666 return m;
667}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
David S. Millerf11e6652007-03-24 20:36:25 -0700669static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200670 int *mpri, struct rt6_info *match,
671 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800672{
David S. Millerf11e6652007-03-24 20:36:25 -0700673 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200674 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400675 struct inet6_dev *idev = rt->rt6i_idev;
676 struct net_device *dev = rt->dst.dev;
677
678 if (dev && !netif_carrier_ok(dev) &&
David Ahernd5d32e42016-10-24 12:27:23 -0700679 idev->cnf.ignore_routes_with_linkdown &&
680 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400681 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700682
683 if (rt6_check_expired(rt))
684 goto out;
685
686 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100687 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200688 match_do_rr = true;
689 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100690 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700691 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700692 }
693
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200694 if (strict & RT6_LOOKUP_F_REACHABLE)
695 rt6_probe(rt);
696
Jiri Benc7e980562013-12-11 13:48:20 +0100697 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200698 if (m > *mpri) {
699 *do_rr = match_do_rr;
700 *mpri = m;
701 match = rt;
702 }
David S. Millerf11e6652007-03-24 20:36:25 -0700703out:
704 return match;
705}
706
707static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
708 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200709 u32 metric, int oif, int strict,
710 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700711{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700712 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800713 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
David S. Millerf11e6652007-03-24 20:36:25 -0700715 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700716 cont = NULL;
717 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
718 if (rt->rt6i_metric != metric) {
719 cont = rt;
720 break;
721 }
722
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200723 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700724 }
725
726 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
727 if (rt->rt6i_metric != metric) {
728 cont = rt;
729 break;
730 }
731
732 match = find_match(rt, oif, strict, &mpri, match, do_rr);
733 }
734
735 if (match || !cont)
736 return match;
737
738 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200739 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800740
David S. Millerf11e6652007-03-24 20:36:25 -0700741 return match;
742}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800743
David S. Millerf11e6652007-03-24 20:36:25 -0700744static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
745{
746 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800747 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200748 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
David S. Millerf11e6652007-03-24 20:36:25 -0700750 rt0 = fn->rr_ptr;
751 if (!rt0)
752 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200754 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
755 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200757 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700758 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700759
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800760 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700761 if (!next || next->rt6i_metric != rt0->rt6i_metric)
762 next = fn->leaf;
763
764 if (next != rt0)
765 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
David S. Millerd1918542011-12-28 20:19:20 -0500768 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000769 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700772static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
773{
774 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
775}
776
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800777#ifdef CONFIG_IPV6_ROUTE_INFO
778int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000779 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800780{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900781 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800782 struct route_info *rinfo = (struct route_info *) opt;
783 struct in6_addr prefix_buf, *prefix;
784 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900785 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800786 struct rt6_info *rt;
787
788 if (len < sizeof(struct route_info)) {
789 return -EINVAL;
790 }
791
792 /* Sanity check for prefix_len and length */
793 if (rinfo->length > 3) {
794 return -EINVAL;
795 } else if (rinfo->prefix_len > 128) {
796 return -EINVAL;
797 } else if (rinfo->prefix_len > 64) {
798 if (rinfo->length < 2) {
799 return -EINVAL;
800 }
801 } else if (rinfo->prefix_len > 0) {
802 if (rinfo->length < 1) {
803 return -EINVAL;
804 }
805 }
806
807 pref = rinfo->route_pref;
808 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000809 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800810
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900811 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800812
813 if (rinfo->length == 3)
814 prefix = (struct in6_addr *)rinfo->prefix;
815 else {
816 /* this function is safe */
817 ipv6_addr_prefix(&prefix_buf,
818 (struct in6_addr *)rinfo->prefix,
819 rinfo->prefix_len);
820 prefix = &prefix_buf;
821 }
822
Duan Jiongf104a562013-11-08 09:56:53 +0800823 if (rinfo->prefix_len == 0)
824 rt = rt6_get_dflt_router(gwaddr, dev);
825 else
826 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700827 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800828
829 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700830 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800831 rt = NULL;
832 }
833
834 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700835 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
836 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800837 else if (rt)
838 rt->rt6i_flags = RTF_ROUTEINFO |
839 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
840
841 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000842 if (!addrconf_finite_timeout(lifetime))
843 rt6_clean_expires(rt);
844 else
845 rt6_set_expires(rt, jiffies + HZ * lifetime);
846
Amerigo Wang94e187c2012-10-29 00:13:19 +0000847 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800848 }
849 return 0;
850}
851#endif
852
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700853static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
854 struct in6_addr *saddr)
855{
856 struct fib6_node *pn;
857 while (1) {
858 if (fn->fn_flags & RTN_TL_ROOT)
859 return NULL;
860 pn = fn->parent;
861 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
862 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
863 else
864 fn = pn;
865 if (fn->fn_flags & RTN_RTINFO)
866 return fn;
867 }
868}
Thomas Grafc71099a2006-08-04 23:20:06 -0700869
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800870static struct rt6_info *ip6_pol_route_lookup(struct net *net,
871 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500872 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
874 struct fib6_node *fn;
875 struct rt6_info *rt;
876
Thomas Grafc71099a2006-08-04 23:20:06 -0700877 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500878 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700879restart:
880 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500881 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000882 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200883 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700884 if (rt == net->ipv6.ip6_null_entry) {
885 fn = fib6_backtrack(fn, &fl6->saddr);
886 if (fn)
887 goto restart;
888 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700889 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700890 read_unlock_bh(&table->tb6_lock);
David Ahernb8115802015-11-19 12:24:22 -0800891
892 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
893
Thomas Grafc71099a2006-08-04 23:20:06 -0700894 return rt;
895
896}
897
Ian Morris67ba4152014-08-24 21:53:10 +0100898struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200899 int flags)
900{
901 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
902}
903EXPORT_SYMBOL_GPL(ip6_route_lookup);
904
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900905struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
906 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700907{
David S. Miller4c9483b2011-03-12 16:22:43 -0500908 struct flowi6 fl6 = {
909 .flowi6_oif = oif,
910 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700911 };
912 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700913 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700914
Thomas Grafadaa70b2006-10-13 15:01:03 -0700915 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500916 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700917 flags |= RT6_LOOKUP_F_HAS_SADDR;
918 }
919
David S. Miller4c9483b2011-03-12 16:22:43 -0500920 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700921 if (dst->error == 0)
922 return (struct rt6_info *) dst;
923
924 dst_release(dst);
925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 return NULL;
927}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900928EXPORT_SYMBOL(rt6_lookup);
929
Thomas Grafc71099a2006-08-04 23:20:06 -0700930/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -0700931 * It takes new route entry, the addition fails by any reason the
932 * route is released.
933 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 */
935
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100936static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -0600937 struct mx6_config *mxc,
938 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939{
940 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700941 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Thomas Grafc71099a2006-08-04 23:20:06 -0700943 table = rt->rt6i_table;
944 write_lock_bh(&table->tb6_lock);
David Ahern333c4302017-05-21 10:12:04 -0600945 err = fib6_add(&table->tb6_root, rt, info, mxc, extack);
Thomas Grafc71099a2006-08-04 23:20:06 -0700946 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 return err;
949}
950
Thomas Graf40e22e82006-08-22 00:00:45 -0700951int ip6_ins_rt(struct rt6_info *rt)
952{
Florian Westphale715b6d2015-01-05 23:57:44 +0100953 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
954 struct mx6_config mxc = { .mx = NULL, };
955
Wei Wang1cfb71e2017-06-17 10:42:33 -0700956 /* Hold dst to account for the reference from the fib6 tree */
957 dst_hold(&rt->dst);
David Ahern333c4302017-05-21 10:12:04 -0600958 return __ip6_ins_rt(rt, &info, &mxc, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -0700959}
960
David Ahern4832c302017-08-17 12:17:20 -0700961/* called with rcu_lock held */
962static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt)
963{
964 struct net_device *dev = rt->dst.dev;
965
966 if (rt->rt6i_flags & RTF_LOCAL) {
967 /* for copies of local routes, dst->dev needs to be the
968 * device if it is a master device, the master device if
969 * device is enslaved, and the loopback as the default
970 */
971 if (netif_is_l3_slave(dev) &&
972 !rt6_need_strict(&rt->rt6i_dst.addr))
973 dev = l3mdev_master_dev_rcu(dev);
974 else if (!netif_is_l3_master(dev))
975 dev = dev_net(dev)->loopback_dev;
976 /* last case is netif_is_l3_master(dev) is true in which
977 * case we want dev returned to be dev
978 */
979 }
980
981 return dev;
982}
983
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700984static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
985 const struct in6_addr *daddr,
986 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
David Ahern4832c302017-08-17 12:17:20 -0700988 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 struct rt6_info *rt;
990
991 /*
992 * Clone the route.
993 */
994
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700995 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700996 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
David Ahern4832c302017-08-17 12:17:20 -0700998 rcu_read_lock();
999 dev = ip6_rt_get_dev_rcu(ort);
1000 rt = __ip6_dst_alloc(dev_net(dev), dev, 0);
1001 rcu_read_unlock();
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001002 if (!rt)
1003 return NULL;
1004
1005 ip6_rt_copy_init(rt, ort);
1006 rt->rt6i_flags |= RTF_CACHE;
1007 rt->rt6i_metric = 0;
1008 rt->dst.flags |= DST_HOST;
1009 rt->rt6i_dst.addr = *daddr;
1010 rt->rt6i_dst.plen = 128;
1011
1012 if (!rt6_is_gw_or_nonexthop(ort)) {
1013 if (ort->rt6i_dst.plen != 128 &&
1014 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
1015 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001017 if (rt->rt6i_src.plen && saddr) {
1018 rt->rt6i_src.addr = *saddr;
1019 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001020 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001021#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001024 return rt;
1025}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001027static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
1028{
David Ahern4832c302017-08-17 12:17:20 -07001029 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001030 struct rt6_info *pcpu_rt;
1031
David Ahern4832c302017-08-17 12:17:20 -07001032 rcu_read_lock();
1033 dev = ip6_rt_get_dev_rcu(rt);
1034 pcpu_rt = __ip6_dst_alloc(dev_net(dev), dev, rt->dst.flags);
1035 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001036 if (!pcpu_rt)
1037 return NULL;
1038 ip6_rt_copy_init(pcpu_rt, rt);
1039 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
1040 pcpu_rt->rt6i_flags |= RTF_PCPU;
1041 return pcpu_rt;
1042}
1043
1044/* It should be called with read_lock_bh(&tb6_lock) acquired */
1045static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
1046{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001047 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001048
1049 p = this_cpu_ptr(rt->rt6i_pcpu);
1050 pcpu_rt = *p;
1051
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001052 if (pcpu_rt) {
1053 dst_hold(&pcpu_rt->dst);
1054 rt6_dst_from_metrics_check(pcpu_rt);
1055 }
1056 return pcpu_rt;
1057}
1058
1059static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
1060{
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001061 struct fib6_table *table = rt->rt6i_table;
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001062 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001063
1064 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1065 if (!pcpu_rt) {
1066 struct net *net = dev_net(rt->dst.dev);
1067
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001068 dst_hold(&net->ipv6.ip6_null_entry->dst);
1069 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001070 }
1071
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001072 read_lock_bh(&table->tb6_lock);
1073 if (rt->rt6i_pcpu) {
1074 p = this_cpu_ptr(rt->rt6i_pcpu);
1075 prev = cmpxchg(p, NULL, pcpu_rt);
1076 if (prev) {
1077 /* If someone did it before us, return prev instead */
Wei Wang587fea72017-06-17 10:42:36 -07001078 dst_release_immediate(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001079 pcpu_rt = prev;
1080 }
1081 } else {
1082 /* rt has been removed from the fib6 tree
1083 * before we have a chance to acquire the read_lock.
1084 * In this case, don't brother to create a pcpu rt
1085 * since rt is going away anyway. The next
1086 * dst_check() will trigger a re-lookup.
1087 */
Wei Wang587fea72017-06-17 10:42:36 -07001088 dst_release_immediate(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001089 pcpu_rt = rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001090 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001091 dst_hold(&pcpu_rt->dst);
1092 rt6_dst_from_metrics_check(pcpu_rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001093 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001094 return pcpu_rt;
1095}
1096
David Ahern9ff74382016-06-13 13:44:19 -07001097struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1098 int oif, struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001100 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001101 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001102 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001104 strict |= flags & RT6_LOOKUP_F_IFACE;
David Ahernd5d32e42016-10-24 12:27:23 -07001105 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001106 if (net->ipv6.devconf_all->forwarding == 0)
1107 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Thomas Grafc71099a2006-08-04 23:20:06 -07001109 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
David S. Miller4c9483b2011-03-12 16:22:43 -05001111 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001112 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
David Ahernca254492015-10-12 11:47:10 -07001114 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1115 oif = 0;
1116
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001117redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001118 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001119 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001120 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001121 if (rt == net->ipv6.ip6_null_entry) {
1122 fn = fib6_backtrack(fn, &fl6->saddr);
1123 if (fn)
1124 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001125 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1126 /* also consider unreachable route */
1127 strict &= ~RT6_LOOKUP_F_REACHABLE;
1128 fn = saved_fn;
1129 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001130 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001131 }
1132
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001133
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001134 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001135 dst_use(&rt->dst, jiffies);
1136 read_unlock_bh(&table->tb6_lock);
1137
1138 rt6_dst_from_metrics_check(rt);
David Ahernb8115802015-11-19 12:24:22 -08001139
1140 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001141 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001142 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1143 !(rt->rt6i_flags & RTF_GATEWAY))) {
1144 /* Create a RTF_CACHE clone which will not be
1145 * owned by the fib6 tree. It is for the special case where
1146 * the daddr in the skb during the neighbor look-up is different
1147 * from the fl6->daddr used to look-up route here.
1148 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001149
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001150 struct rt6_info *uncached_rt;
1151
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001152 dst_use(&rt->dst, jiffies);
1153 read_unlock_bh(&table->tb6_lock);
1154
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001155 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1156 dst_release(&rt->dst);
1157
Wei Wang1cfb71e2017-06-17 10:42:33 -07001158 if (uncached_rt) {
1159 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1160 * No need for another dst_hold()
1161 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001162 rt6_uncached_list_add(uncached_rt);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001163 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001164 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001165 dst_hold(&uncached_rt->dst);
1166 }
David Ahernb8115802015-11-19 12:24:22 -08001167
1168 trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001169 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001170
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001171 } else {
1172 /* Get a percpu copy */
1173
1174 struct rt6_info *pcpu_rt;
1175
1176 rt->dst.lastuse = jiffies;
1177 rt->dst.__use++;
1178 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001179
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001180 if (pcpu_rt) {
1181 read_unlock_bh(&table->tb6_lock);
1182 } else {
1183 /* We have to do the read_unlock first
1184 * because rt6_make_pcpu_route() may trigger
1185 * ip6_dst_gc() which will take the write_lock.
1186 */
1187 dst_hold(&rt->dst);
1188 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001189 pcpu_rt = rt6_make_pcpu_route(rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001190 dst_release(&rt->dst);
1191 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001192
David Ahernb8115802015-11-19 12:24:22 -08001193 trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001194 return pcpu_rt;
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001195
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001196 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001197}
David Ahern9ff74382016-06-13 13:44:19 -07001198EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001199
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001200static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001201 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001202{
David S. Miller4c9483b2011-03-12 16:22:43 -05001203 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001204}
1205
Mahesh Bandeward409b842016-09-16 12:59:08 -07001206struct dst_entry *ip6_route_input_lookup(struct net *net,
1207 struct net_device *dev,
1208 struct flowi6 *fl6, int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001209{
1210 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1211 flags |= RT6_LOOKUP_F_IFACE;
1212
1213 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1214}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001215EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001216
Thomas Grafc71099a2006-08-04 23:20:06 -07001217void ip6_route_input(struct sk_buff *skb)
1218{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001219 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001220 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001221 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001222 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001223 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07001224 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05001225 .daddr = iph->daddr,
1226 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001227 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001228 .flowi6_mark = skb->mark,
1229 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001230 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001231
Jiri Benc904af042015-08-20 13:56:31 +02001232 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001233 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001234 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jiri Benc06e9d042015-08-20 13:56:26 +02001235 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001236 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001237}
1238
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001239static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001240 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001241{
David S. Miller4c9483b2011-03-12 16:22:43 -05001242 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001243}
1244
Paolo Abeni6f21c962016-01-29 12:30:19 +01001245struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
1246 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001247{
David Ahernd46a9d62015-10-21 08:42:22 -07001248 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07001249
David Ahern4c1feac2016-09-10 12:09:56 -07001250 if (rt6_need_strict(&fl6->daddr)) {
1251 struct dst_entry *dst;
1252
1253 dst = l3mdev_link_scope_lookup(net, fl6);
1254 if (dst)
1255 return dst;
1256 }
David Ahernca254492015-10-12 11:47:10 -07001257
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001258 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001259
David Ahernd46a9d62015-10-21 08:42:22 -07001260 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07001261 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07001262 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001263 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001264
David Ahernd46a9d62015-10-21 08:42:22 -07001265 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07001266 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001267 else if (sk)
1268 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001269
David S. Miller4c9483b2011-03-12 16:22:43 -05001270 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271}
Paolo Abeni6f21c962016-01-29 12:30:19 +01001272EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
David S. Miller2774c132011-03-01 14:59:04 -08001274struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001275{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001276 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07001277 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07001278 struct dst_entry *new = NULL;
1279
Wei Wang1dbe32522017-06-17 10:42:26 -07001280 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Wei Wangb2a9c0e2017-06-17 10:42:41 -07001281 DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001282 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001283 rt6_info_init(rt);
1284
Changli Gaod8d1f302010-06-10 23:31:35 -07001285 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001286 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001287 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001288 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07001289
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001290 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001291
Wei Wang1dbe32522017-06-17 10:42:26 -07001292 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001293 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001294 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07001295 rt->rt6i_metric = 0;
1296
1297 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1298#ifdef CONFIG_IPV6_SUBTREES
1299 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1300#endif
David S. Miller14e50e52007-05-24 18:17:54 -07001301 }
1302
David S. Miller69ead7a2011-03-01 14:45:33 -08001303 dst_release(dst_orig);
1304 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001305}
David S. Miller14e50e52007-05-24 18:17:54 -07001306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307/*
1308 * Destination cache support functions
1309 */
1310
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001311static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1312{
1313 if (rt->dst.from &&
1314 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1315 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1316}
1317
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001318static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1319{
1320 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1321 return NULL;
1322
1323 if (rt6_check_expired(rt))
1324 return NULL;
1325
1326 return &rt->dst;
1327}
1328
1329static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1330{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08001331 if (!__rt6_check_expired(rt) &&
1332 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001333 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1334 return &rt->dst;
1335 else
1336 return NULL;
1337}
1338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1340{
1341 struct rt6_info *rt;
1342
1343 rt = (struct rt6_info *) dst;
1344
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001345 /* All IPV6 dsts are created with ->obsolete set to the value
1346 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1347 * into this function always.
1348 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001349
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001350 rt6_dst_from_metrics_check(rt);
1351
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08001352 if (rt->rt6i_flags & RTF_PCPU ||
Wei Wanga4c2fd72017-06-17 10:42:42 -07001353 (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001354 return rt6_dst_from_check(rt, cookie);
1355 else
1356 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
1358
1359static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1360{
1361 struct rt6_info *rt = (struct rt6_info *) dst;
1362
1363 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001364 if (rt->rt6i_flags & RTF_CACHE) {
1365 if (rt6_check_expired(rt)) {
1366 ip6_del_rt(rt);
1367 dst = NULL;
1368 }
1369 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001371 dst = NULL;
1372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001374 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
1377static void ip6_link_failure(struct sk_buff *skb)
1378{
1379 struct rt6_info *rt;
1380
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001381 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
Eric Dumazetadf30902009-06-02 05:19:30 +00001383 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001385 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07001386 if (dst_hold_safe(&rt->dst))
1387 ip6_del_rt(rt);
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001388 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 }
1392}
1393
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001394static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1395{
1396 struct net *net = dev_net(rt->dst.dev);
1397
1398 rt->rt6i_flags |= RTF_MODIFIED;
1399 rt->rt6i_pmtu = mtu;
1400 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1401}
1402
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001403static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
1404{
1405 return !(rt->rt6i_flags & RTF_CACHE) &&
1406 (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
1407}
1408
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001409static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1410 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411{
Julian Anastasov0dec8792017-02-06 23:14:16 +02001412 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001413 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001415 if (rt6->rt6i_flags & RTF_LOCAL)
1416 return;
1417
Xin Long19bda362016-10-28 18:18:01 +08001418 if (dst_metric_locked(dst, RTAX_MTU))
1419 return;
1420
Julian Anastasov0dec8792017-02-06 23:14:16 +02001421 if (iph) {
1422 daddr = &iph->daddr;
1423 saddr = &iph->saddr;
1424 } else if (sk) {
1425 daddr = &sk->sk_v6_daddr;
1426 saddr = &inet6_sk(sk)->saddr;
1427 } else {
1428 daddr = NULL;
1429 saddr = NULL;
1430 }
1431 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001432 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1433 if (mtu >= dst_mtu(dst))
1434 return;
David S. Miller81aded22012-06-15 14:54:11 -07001435
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001436 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001437 rt6_do_update_pmtu(rt6, mtu);
Julian Anastasov0dec8792017-02-06 23:14:16 +02001438 } else if (daddr) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001439 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001440
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001441 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1442 if (nrt6) {
1443 rt6_do_update_pmtu(nrt6, mtu);
1444
1445 /* ip6_ins_rt(nrt6) will bump the
1446 * rt6->rt6i_node->fn_sernum
1447 * which will fail the next rt6_check() and
1448 * invalidate the sk->sk_dst_cache.
1449 */
1450 ip6_ins_rt(nrt6);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001451 /* Release the reference taken in
1452 * ip6_rt_cache_alloc()
1453 */
1454 dst_release(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 }
1457}
1458
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001459static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1460 struct sk_buff *skb, u32 mtu)
1461{
1462 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1463}
1464
David S. Miller42ae66c2012-06-15 20:01:57 -07001465void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001466 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07001467{
1468 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1469 struct dst_entry *dst;
1470 struct flowi6 fl6;
1471
1472 memset(&fl6, 0, sizeof(fl6));
1473 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001474 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001475 fl6.daddr = iph->daddr;
1476 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001477 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001478 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07001479
1480 dst = ip6_route_output(net, NULL, &fl6);
1481 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001482 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001483 dst_release(dst);
1484}
1485EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1486
1487void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1488{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001489 struct dst_entry *dst;
1490
David S. Miller81aded22012-06-15 14:54:11 -07001491 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001492 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001493
1494 dst = __sk_dst_get(sk);
1495 if (!dst || !dst->obsolete ||
1496 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
1497 return;
1498
1499 bh_lock_sock(sk);
1500 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
1501 ip6_datagram_dst_update(sk, false);
1502 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07001503}
1504EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1505
Duan Jiongb55b76b2013-09-04 19:44:21 +08001506/* Handle redirects */
1507struct ip6rd_flowi {
1508 struct flowi6 fl6;
1509 struct in6_addr gateway;
1510};
1511
1512static struct rt6_info *__ip6_route_redirect(struct net *net,
1513 struct fib6_table *table,
1514 struct flowi6 *fl6,
1515 int flags)
1516{
1517 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1518 struct rt6_info *rt;
1519 struct fib6_node *fn;
1520
1521 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01001522 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08001523 *
1524 * RFC 4861 specifies that redirects should only be
1525 * accepted if they come from the nexthop to the target.
1526 * Due to the way the routes are chosen, this notion
1527 * is a bit fuzzy and one might need to check all possible
1528 * routes.
1529 */
1530
1531 read_lock_bh(&table->tb6_lock);
1532 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1533restart:
1534 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1535 if (rt6_check_expired(rt))
1536 continue;
1537 if (rt->dst.error)
1538 break;
1539 if (!(rt->rt6i_flags & RTF_GATEWAY))
1540 continue;
1541 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1542 continue;
1543 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1544 continue;
1545 break;
1546 }
1547
1548 if (!rt)
1549 rt = net->ipv6.ip6_null_entry;
1550 else if (rt->dst.error) {
1551 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001552 goto out;
1553 }
1554
1555 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001556 fn = fib6_backtrack(fn, &fl6->saddr);
1557 if (fn)
1558 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001559 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001560
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001561out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001562 dst_hold(&rt->dst);
1563
1564 read_unlock_bh(&table->tb6_lock);
1565
David Ahernb8115802015-11-19 12:24:22 -08001566 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Duan Jiongb55b76b2013-09-04 19:44:21 +08001567 return rt;
1568};
1569
1570static struct dst_entry *ip6_route_redirect(struct net *net,
1571 const struct flowi6 *fl6,
1572 const struct in6_addr *gateway)
1573{
1574 int flags = RT6_LOOKUP_F_HAS_SADDR;
1575 struct ip6rd_flowi rdfl;
1576
1577 rdfl.fl6 = *fl6;
1578 rdfl.gateway = *gateway;
1579
1580 return fib6_rule_lookup(net, &rdfl.fl6,
1581 flags, __ip6_route_redirect);
1582}
1583
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001584void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
1585 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001586{
1587 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1588 struct dst_entry *dst;
1589 struct flowi6 fl6;
1590
1591 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001592 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001593 fl6.flowi6_oif = oif;
1594 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001595 fl6.daddr = iph->daddr;
1596 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001597 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001598 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001599
Duan Jiongb55b76b2013-09-04 19:44:21 +08001600 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1601 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001602 dst_release(dst);
1603}
1604EXPORT_SYMBOL_GPL(ip6_redirect);
1605
Duan Jiongc92a59e2013-08-22 12:07:35 +08001606void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1607 u32 mark)
1608{
1609 const struct ipv6hdr *iph = ipv6_hdr(skb);
1610 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1611 struct dst_entry *dst;
1612 struct flowi6 fl6;
1613
1614 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001615 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001616 fl6.flowi6_oif = oif;
1617 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001618 fl6.daddr = msg->dest;
1619 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001620 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001621
Duan Jiongb55b76b2013-09-04 19:44:21 +08001622 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1623 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001624 dst_release(dst);
1625}
1626
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001627void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1628{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001629 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
1630 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001631}
1632EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1633
David S. Miller0dbaee32010-12-13 12:52:14 -08001634static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635{
David S. Miller0dbaee32010-12-13 12:52:14 -08001636 struct net_device *dev = dst->dev;
1637 unsigned int mtu = dst_mtu(dst);
1638 struct net *net = dev_net(dev);
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1641
Daniel Lezcano55786892008-03-04 13:47:47 -08001642 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1643 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
1645 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001646 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1647 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1648 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 * rely only on pmtu discovery"
1650 */
1651 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1652 mtu = IPV6_MAXPLEN;
1653 return mtu;
1654}
1655
Steffen Klassertebb762f2011-11-23 02:12:51 +00001656static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001657{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001658 const struct rt6_info *rt = (const struct rt6_info *)dst;
1659 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001660 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001661
1662 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001663 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001664
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001665 mtu = dst_metric_raw(dst, RTAX_MTU);
1666 if (mtu)
1667 goto out;
1668
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001669 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001670
1671 rcu_read_lock();
1672 idev = __in6_dev_get(dst->dev);
1673 if (idev)
1674 mtu = idev->cnf.mtu6;
1675 rcu_read_unlock();
1676
Eric Dumazet30f78d82014-04-10 21:23:36 -07001677out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07001678 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1679
1680 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08001681}
1682
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001683struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001684 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685{
David S. Miller87a11572011-12-06 17:04:13 -05001686 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 struct rt6_info *rt;
1688 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001689 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
David S. Miller38308472011-12-03 18:02:47 -05001691 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001692 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Martin KaFai Lauad706862015-08-14 11:05:52 -07001694 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001695 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001697 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 goto out;
1699 }
1700
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001701 rt->dst.flags |= DST_HOST;
1702 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03001703 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001704 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001705 rt->rt6i_dst.plen = 128;
1706 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001707 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Wei Wang587fea72017-06-17 10:42:36 -07001709 /* Add this dst into uncached_list so that rt6_ifdown() can
1710 * do proper release of the net_device
1711 */
1712 rt6_uncached_list_add(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
David S. Miller87a11572011-12-06 17:04:13 -05001714 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716out:
David S. Miller87a11572011-12-06 17:04:13 -05001717 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718}
1719
Daniel Lezcano569d3642008-01-18 03:56:57 -08001720static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001722 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001723 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1724 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1725 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1726 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1727 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001728 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Eric Dumazetfc66f952010-10-08 06:37:34 +00001730 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001731 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001732 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 goto out;
1734
Benjamin Thery6891a342008-03-04 13:49:47 -08001735 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001736 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001737 entries = dst_entries_get_slow(ops);
1738 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001739 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001741 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001742 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743}
1744
Florian Westphale715b6d2015-01-05 23:57:44 +01001745static int ip6_convert_metrics(struct mx6_config *mxc,
1746 const struct fib6_config *cfg)
1747{
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001748 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01001749 struct nlattr *nla;
1750 int remaining;
1751 u32 *mp;
1752
Ian Morris63159f22015-03-29 14:00:04 +01001753 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001754 return 0;
1755
1756 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1757 if (unlikely(!mp))
1758 return -ENOMEM;
1759
1760 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1761 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001762 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001763
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001764 if (!type)
1765 continue;
1766 if (unlikely(type > RTAX_MAX))
1767 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001768
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001769 if (type == RTAX_CC_ALGO) {
1770 char tmp[TCP_CA_NAME_MAX];
1771
1772 nla_strlcpy(tmp, nla, sizeof(tmp));
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001773 val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001774 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01001775 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001776 } else {
1777 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01001778 }
Paolo Abeni626abd52016-05-13 18:33:41 +02001779 if (type == RTAX_HOPLIMIT && val > 255)
1780 val = 255;
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02001781 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
1782 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001783
1784 mp[type - 1] = val;
1785 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01001786 }
1787
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001788 if (ecn_ca) {
1789 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
1790 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
1791 }
Florian Westphale715b6d2015-01-05 23:57:44 +01001792
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001793 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01001794 return 0;
1795 err:
1796 kfree(mp);
1797 return -EINVAL;
1798}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
David Ahern8c145862016-04-24 21:26:04 -07001800static struct rt6_info *ip6_nh_lookup_table(struct net *net,
1801 struct fib6_config *cfg,
1802 const struct in6_addr *gw_addr)
1803{
1804 struct flowi6 fl6 = {
1805 .flowi6_oif = cfg->fc_ifindex,
1806 .daddr = *gw_addr,
1807 .saddr = cfg->fc_prefsrc,
1808 };
1809 struct fib6_table *table;
1810 struct rt6_info *rt;
David Ahernd5d32e42016-10-24 12:27:23 -07001811 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahern8c145862016-04-24 21:26:04 -07001812
1813 table = fib6_get_table(net, cfg->fc_table);
1814 if (!table)
1815 return NULL;
1816
1817 if (!ipv6_addr_any(&cfg->fc_prefsrc))
1818 flags |= RT6_LOOKUP_F_HAS_SADDR;
1819
1820 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
1821
1822 /* if table lookup failed, fall back to full lookup */
1823 if (rt == net->ipv6.ip6_null_entry) {
1824 ip6_rt_put(rt);
1825 rt = NULL;
1826 }
1827
1828 return rt;
1829}
1830
David Ahern333c4302017-05-21 10:12:04 -06001831static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
1832 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833{
Daniel Lezcano55786892008-03-04 13:47:47 -08001834 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 struct rt6_info *rt = NULL;
1836 struct net_device *dev = NULL;
1837 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001838 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001840 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
David Ahern557c44b2017-04-19 14:19:43 -07001842 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06001843 if (cfg->fc_flags & RTF_PCPU) {
1844 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07001845 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001846 }
David Ahern557c44b2017-04-19 14:19:43 -07001847
David Ahernd5d531c2017-05-21 10:12:05 -06001848 if (cfg->fc_dst_len > 128) {
1849 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001850 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001851 }
1852 if (cfg->fc_src_len > 128) {
1853 NL_SET_ERR_MSG(extack, "Invalid source address length");
1854 goto out;
1855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06001857 if (cfg->fc_src_len) {
1858 NL_SET_ERR_MSG(extack,
1859 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001860 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001863 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001865 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 if (!dev)
1867 goto out;
1868 idev = in6_dev_get(dev);
1869 if (!idev)
1870 goto out;
1871 }
1872
Thomas Graf86872cb2006-08-22 00:01:08 -07001873 if (cfg->fc_metric == 0)
1874 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
Matti Vaittinend71314b2011-11-14 00:14:49 +00001876 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001877 if (cfg->fc_nlinfo.nlh &&
1878 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001879 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001880 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001881 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001882 table = fib6_new_table(net, cfg->fc_table);
1883 }
1884 } else {
1885 table = fib6_new_table(net, cfg->fc_table);
1886 }
David S. Miller38308472011-12-03 18:02:47 -05001887
1888 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001889 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001890
Martin KaFai Lauad706862015-08-14 11:05:52 -07001891 rt = ip6_dst_alloc(net, NULL,
1892 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
David S. Miller38308472011-12-03 18:02:47 -05001894 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 err = -ENOMEM;
1896 goto out;
1897 }
1898
Gao feng1716a962012-04-06 00:13:10 +00001899 if (cfg->fc_flags & RTF_EXPIRES)
1900 rt6_set_expires(rt, jiffies +
1901 clock_t_to_jiffies(cfg->fc_expires));
1902 else
1903 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Thomas Graf86872cb2006-08-22 00:01:08 -07001905 if (cfg->fc_protocol == RTPROT_UNSPEC)
1906 cfg->fc_protocol = RTPROT_BOOT;
1907 rt->rt6i_protocol = cfg->fc_protocol;
1908
1909 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
1911 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001912 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001913 else if (cfg->fc_flags & RTF_LOCAL)
1914 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001916 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
Changli Gaod8d1f302010-06-10 23:31:35 -07001918 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001920 if (cfg->fc_encap) {
1921 struct lwtunnel_state *lwtstate;
1922
David Ahern30357d72017-01-30 12:07:37 -08001923 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07001924 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06001925 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001926 if (err)
1927 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02001928 rt->dst.lwtstate = lwtstate_get(lwtstate);
1929 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
1930 rt->dst.lwtstate->orig_output = rt->dst.output;
1931 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07001932 }
Jiri Benc61adedf2015-08-20 13:56:25 +02001933 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
1934 rt->dst.lwtstate->orig_input = rt->dst.input;
1935 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07001936 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001937 }
1938
Thomas Graf86872cb2006-08-22 00:01:08 -07001939 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1940 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001941 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001942 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001943
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001945 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1946 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947#endif
1948
Thomas Graf86872cb2006-08-22 00:01:08 -07001949 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
1951 /* We cannot add true routes via loopback here,
1952 they would result in kernel looping; promote them to reject routes
1953 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001954 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001955 (dev && (dev->flags & IFF_LOOPBACK) &&
1956 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1957 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001959 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 if (dev) {
1961 dev_put(dev);
1962 in6_dev_put(idev);
1963 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001964 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 dev_hold(dev);
1966 idev = in6_dev_get(dev);
1967 if (!idev) {
1968 err = -ENODEV;
1969 goto out;
1970 }
1971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001973 switch (cfg->fc_type) {
1974 case RTN_BLACKHOLE:
1975 rt->dst.error = -EINVAL;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001976 rt->dst.output = dst_discard_out;
Kamala R7150aed2013-12-02 19:55:21 +05301977 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001978 break;
1979 case RTN_PROHIBIT:
1980 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301981 rt->dst.output = ip6_pkt_prohibit_out;
1982 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001983 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001984 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02001985 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001986 default:
Kamala R7150aed2013-12-02 19:55:21 +05301987 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02001988 : (cfg->fc_type == RTN_UNREACHABLE)
1989 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05301990 rt->dst.output = ip6_pkt_discard_out;
1991 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001992 break;
1993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 goto install_route;
1995 }
1996
Thomas Graf86872cb2006-08-22 00:01:08 -07001997 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001998 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 int gwa_type;
2000
Thomas Graf86872cb2006-08-22 00:01:08 -07002001 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02002002 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02002003
2004 /* if gw_addr is local we will fail to detect this in case
2005 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2006 * will return already-added prefix route via interface that
2007 * prefix route was assigned to, which might be non-loopback.
2008 */
2009 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02002010 if (ipv6_chk_addr_and_flags(net, gw_addr,
2011 gwa_type & IPV6_ADDR_LINKLOCAL ?
David Ahernd5d531c2017-05-21 10:12:05 -06002012 dev : NULL, 0, 0)) {
2013 NL_SET_ERR_MSG(extack, "Invalid gateway address");
Florian Westphal48ed7b22015-05-21 00:25:41 +02002014 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002015 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002016 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
David Ahern8c145862016-04-24 21:26:04 -07002019 struct rt6_info *grt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
2021 /* IPv6 strictly inhibits using not link-local
2022 addresses as nexthop address.
2023 Otherwise, router will not able to send redirects.
2024 It is very good, but in some (rare!) circumstances
2025 (SIT, PtP, NBMA NOARP links) it is handy to allow
2026 some exceptions. --ANK
Erik Nordmark96d58222016-12-03 20:57:09 -08002027 We allow IPv4-mapped nexthops to support RFC4798-type
2028 addressing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 */
Erik Nordmark96d58222016-12-03 20:57:09 -08002030 if (!(gwa_type & (IPV6_ADDR_UNICAST |
David Ahernd5d531c2017-05-21 10:12:05 -06002031 IPV6_ADDR_MAPPED))) {
2032 NL_SET_ERR_MSG(extack,
2033 "Invalid gateway address");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Vincent Bernata435a072016-09-18 17:46:07 +02002037 if (cfg->fc_table) {
David Ahern8c145862016-04-24 21:26:04 -07002038 grt = ip6_nh_lookup_table(net, cfg, gw_addr);
2039
Vincent Bernata435a072016-09-18 17:46:07 +02002040 if (grt) {
2041 if (grt->rt6i_flags & RTF_GATEWAY ||
2042 (dev && dev != grt->dst.dev)) {
2043 ip6_rt_put(grt);
2044 grt = NULL;
2045 }
2046 }
2047 }
2048
David Ahern8c145862016-04-24 21:26:04 -07002049 if (!grt)
2050 grt = rt6_lookup(net, gw_addr, NULL,
2051 cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
2053 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05002054 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 goto out;
2056 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05002057 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002058 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 goto out;
2060 }
2061 } else {
David S. Millerd1918542011-12-28 20:19:20 -05002062 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 idev = grt->rt6i_idev;
2064 dev_hold(dev);
2065 in6_dev_hold(grt->rt6i_idev);
2066 }
David S. Miller38308472011-12-03 18:02:47 -05002067 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00002069 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
2071 if (err)
2072 goto out;
2073 }
2074 err = -EINVAL;
David Ahernd5d531c2017-05-21 10:12:05 -06002075 if (!dev) {
2076 NL_SET_ERR_MSG(extack, "Egress device not specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002078 } else if (dev->flags & IFF_LOOPBACK) {
2079 NL_SET_ERR_MSG(extack,
2080 "Egress device can not be loopback device for this route");
2081 goto out;
2082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 }
2084
2085 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002086 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 goto out;
2088
Daniel Walterc3968a82011-04-13 21:10:57 +00002089 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2090 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06002091 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00002092 err = -EINVAL;
2093 goto out;
2094 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002095 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00002096 rt->rt6i_prefsrc.plen = 128;
2097 } else
2098 rt->rt6i_prefsrc.plen = 0;
2099
Thomas Graf86872cb2006-08-22 00:01:08 -07002100 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07002103 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07002105 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002106
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002107 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002108
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002109 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110out:
2111 if (dev)
2112 dev_put(dev);
2113 if (idev)
2114 in6_dev_put(idev);
Wei Wang587fea72017-06-17 10:42:36 -07002115 if (rt)
2116 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002117
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002118 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002119}
2120
David Ahern333c4302017-05-21 10:12:04 -06002121int ip6_route_add(struct fib6_config *cfg,
2122 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002123{
2124 struct mx6_config mxc = { .mx = NULL, };
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002125 struct rt6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002126 int err;
2127
David Ahern333c4302017-05-21 10:12:04 -06002128 rt = ip6_route_info_create(cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002129 if (IS_ERR(rt)) {
2130 err = PTR_ERR(rt);
2131 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002132 goto out;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002133 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002134
2135 err = ip6_convert_metrics(&mxc, cfg);
2136 if (err)
2137 goto out;
2138
David Ahern333c4302017-05-21 10:12:04 -06002139 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002140
2141 kfree(mxc.mx);
2142
2143 return err;
2144out:
Wei Wang587fea72017-06-17 10:42:36 -07002145 if (rt)
2146 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002147
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 return err;
2149}
2150
Thomas Graf86872cb2006-08-22 00:01:08 -07002151static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152{
2153 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002154 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002155 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Wei Wanga4c2fd72017-06-17 10:42:42 -07002157 if (rt == net->ipv6.ip6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00002158 err = -ENOENT;
2159 goto out;
2160 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002161
Thomas Grafc71099a2006-08-04 23:20:06 -07002162 table = rt->rt6i_table;
2163 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002164 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07002165 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Gao feng6825a262012-09-19 19:25:34 +00002167out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002168 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 return err;
2170}
2171
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002172int ip6_del_rt(struct rt6_info *rt)
2173{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002174 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002175 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002176 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002177 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002178}
2179
David Ahern0ae81332017-02-02 12:37:08 -08002180static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
2181{
2182 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08002183 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08002184 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08002185 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08002186 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08002187
WANG Conge3330032017-02-27 16:07:43 -08002188 if (rt == net->ipv6.ip6_null_entry)
2189 goto out_put;
David Ahern0ae81332017-02-02 12:37:08 -08002190 table = rt->rt6i_table;
2191 write_lock_bh(&table->tb6_lock);
2192
2193 if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
2194 struct rt6_info *sibling, *next_sibling;
2195
David Ahern16a16cd2017-02-02 12:37:11 -08002196 /* prefer to send a single notification with all hops */
2197 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
2198 if (skb) {
2199 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
2200
WANG Conge3330032017-02-27 16:07:43 -08002201 if (rt6_fill_node(net, skb, rt,
David Ahern16a16cd2017-02-02 12:37:11 -08002202 NULL, NULL, 0, RTM_DELROUTE,
2203 info->portid, seq, 0) < 0) {
2204 kfree_skb(skb);
2205 skb = NULL;
2206 } else
2207 info->skip_notify = 1;
2208 }
2209
David Ahern0ae81332017-02-02 12:37:08 -08002210 list_for_each_entry_safe(sibling, next_sibling,
2211 &rt->rt6i_siblings,
2212 rt6i_siblings) {
2213 err = fib6_del(sibling, info);
2214 if (err)
WANG Conge3330032017-02-27 16:07:43 -08002215 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08002216 }
2217 }
2218
2219 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08002220out_unlock:
David Ahern0ae81332017-02-02 12:37:08 -08002221 write_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08002222out_put:
David Ahern0ae81332017-02-02 12:37:08 -08002223 ip6_rt_put(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08002224
2225 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08002226 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08002227 info->nlh, gfp_any());
2228 }
David Ahern0ae81332017-02-02 12:37:08 -08002229 return err;
2230}
2231
David Ahern333c4302017-05-21 10:12:04 -06002232static int ip6_route_del(struct fib6_config *cfg,
2233 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234{
Thomas Grafc71099a2006-08-04 23:20:06 -07002235 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 struct fib6_node *fn;
2237 struct rt6_info *rt;
2238 int err = -ESRCH;
2239
Daniel Lezcano55786892008-03-04 13:47:47 -08002240 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06002241 if (!table) {
2242 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07002243 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06002244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
Thomas Grafc71099a2006-08-04 23:20:06 -07002246 read_lock_bh(&table->tb6_lock);
2247
2248 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002249 &cfg->fc_dst, cfg->fc_dst_len,
2250 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002251
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002253 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002254 if ((rt->rt6i_flags & RTF_CACHE) &&
2255 !(cfg->fc_flags & RTF_CACHE))
2256 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002257 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002258 (!rt->dst.dev ||
2259 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002261 if (cfg->fc_flags & RTF_GATEWAY &&
2262 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002264 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 continue;
Mantas Mc2ed1882016-12-16 10:30:59 +02002266 if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
2267 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002268 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002269 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270
David Ahern0ae81332017-02-02 12:37:08 -08002271 /* if gateway was specified only delete the one hop */
2272 if (cfg->fc_flags & RTF_GATEWAY)
2273 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
2274
2275 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 }
2277 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002278 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
2280 return err;
2281}
2282
David S. Miller6700c272012-07-17 03:29:28 -07002283static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002284{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002285 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002286 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002287 struct ndisc_options ndopts;
2288 struct inet6_dev *in6_dev;
2289 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002290 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002291 int optlen, on_link;
2292 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002293
Simon Horman29a3cad2013-05-28 20:34:26 +00002294 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002295 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002296
2297 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002298 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002299 return;
2300 }
2301
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002302 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002303
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002304 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002305 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002306 return;
2307 }
2308
David S. Miller6e157b62012-07-12 00:05:02 -07002309 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002310 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002311 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002312 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002313 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002314 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002315 return;
2316 }
2317
2318 in6_dev = __in6_dev_get(skb->dev);
2319 if (!in6_dev)
2320 return;
2321 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2322 return;
2323
2324 /* RFC2461 8.1:
2325 * The IP source address of the Redirect MUST be the same as the current
2326 * first-hop router for the specified ICMP Destination Address.
2327 */
2328
Alexander Aringf997c552016-06-15 21:20:23 +02002329 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002330 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2331 return;
2332 }
David S. Miller6e157b62012-07-12 00:05:02 -07002333
2334 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002335 if (ndopts.nd_opts_tgt_lladdr) {
2336 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2337 skb->dev);
2338 if (!lladdr) {
2339 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2340 return;
2341 }
2342 }
2343
David S. Miller6e157b62012-07-12 00:05:02 -07002344 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01002345 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07002346 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2347 return;
2348 }
2349
2350 /* Redirect received -> path was valid.
2351 * Look, redirects are sent only in response to data packets,
2352 * so that this nexthop apparently is reachable. --ANK
2353 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02002354 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07002355
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002356 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002357 if (!neigh)
2358 return;
2359
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 /*
2361 * We have finally decided to accept it.
2362 */
2363
Alexander Aringf997c552016-06-15 21:20:23 +02002364 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2366 NEIGH_UPDATE_F_OVERRIDE|
2367 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02002368 NEIGH_UPDATE_F_ISROUTER)),
2369 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002371 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002372 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 goto out;
2374
2375 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2376 if (on_link)
2377 nrt->rt6i_flags &= ~RTF_GATEWAY;
2378
Xin Longb91d5322017-08-03 14:13:46 +08002379 nrt->rt6i_protocol = RTPROT_REDIRECT;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002380 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Thomas Graf40e22e82006-08-22 00:00:45 -07002382 if (ip6_ins_rt(nrt))
Wei Wang1cfb71e2017-06-17 10:42:33 -07002383 goto out_release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
Changli Gaod8d1f302010-06-10 23:31:35 -07002385 netevent.old = &rt->dst;
2386 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002387 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002388 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002389 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2390
David S. Miller38308472011-12-03 18:02:47 -05002391 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002392 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002393 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 }
2395
Wei Wang1cfb71e2017-06-17 10:42:33 -07002396out_release:
2397 /* Release the reference taken in
2398 * ip6_rt_cache_alloc()
2399 */
2400 dst_release(&nrt->dst);
2401
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402out:
David S. Millere8599ff2012-07-11 23:43:53 -07002403 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002404}
2405
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 * Misc support functions
2408 */
2409
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002410static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2411{
2412 BUG_ON(from->dst.from);
2413
2414 rt->rt6i_flags &= ~RTF_EXPIRES;
2415 dst_hold(&from->dst);
2416 rt->dst.from = &from->dst;
2417 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2418}
2419
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002420static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002422 rt->dst.input = ort->dst.input;
2423 rt->dst.output = ort->dst.output;
2424 rt->rt6i_dst = ort->rt6i_dst;
2425 rt->dst.error = ort->dst.error;
2426 rt->rt6i_idev = ort->rt6i_idev;
2427 if (rt->rt6i_idev)
2428 in6_dev_hold(rt->rt6i_idev);
2429 rt->dst.lastuse = jiffies;
2430 rt->rt6i_gateway = ort->rt6i_gateway;
2431 rt->rt6i_flags = ort->rt6i_flags;
2432 rt6_set_from(rt, ort);
2433 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002435 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002437 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2438 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02002439 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440}
2441
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002442#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002443static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002444 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002445 const struct in6_addr *gwaddr,
2446 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002447{
David Ahern830218c2016-10-24 10:52:35 -07002448 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
2449 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002450 struct fib6_node *fn;
2451 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002452 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002453
David Ahern830218c2016-10-24 10:52:35 -07002454 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002455 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002456 return NULL;
2457
Li RongQing5744dd92012-09-11 21:59:01 +00002458 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002459 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002460 if (!fn)
2461 goto out;
2462
Changli Gaod8d1f302010-06-10 23:31:35 -07002463 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002464 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002465 continue;
2466 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2467 continue;
2468 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2469 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002470 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002471 break;
2472 }
2473out:
Li RongQing5744dd92012-09-11 21:59:01 +00002474 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002475 return rt;
2476}
2477
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002478static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002479 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002480 const struct in6_addr *gwaddr,
2481 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00002482 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002483{
Thomas Graf86872cb2006-08-22 00:01:08 -07002484 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08002485 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07002486 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07002487 .fc_dst_len = prefixlen,
2488 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2489 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08002490 .fc_protocol = RTPROT_RA,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002491 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002492 .fc_nlinfo.nlh = NULL,
2493 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002494 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002495
David Ahern830218c2016-10-24 10:52:35 -07002496 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002497 cfg.fc_dst = *prefix;
2498 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002499
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002500 /* We should treat it as a default route if prefix length is 0. */
2501 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002502 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002503
David Ahern333c4302017-05-21 10:12:04 -06002504 ip6_route_add(&cfg, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002505
David Ahern830218c2016-10-24 10:52:35 -07002506 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002507}
2508#endif
2509
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002510struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002511{
David Ahern830218c2016-10-24 10:52:35 -07002512 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002514 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
David Ahern830218c2016-10-24 10:52:35 -07002516 table = fib6_get_table(dev_net(dev), tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002517 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002518 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
Li RongQing5744dd92012-09-11 21:59:01 +00002520 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002521 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002522 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002523 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2525 break;
2526 }
2527 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002528 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002529 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 return rt;
2531}
2532
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002533struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002534 struct net_device *dev,
2535 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
Thomas Graf86872cb2006-08-22 00:01:08 -07002537 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07002538 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002539 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002540 .fc_ifindex = dev->ifindex,
2541 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2542 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08002543 .fc_protocol = RTPROT_RA,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002544 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002545 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002546 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002547 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002549 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550
David Ahern333c4302017-05-21 10:12:04 -06002551 if (!ip6_route_add(&cfg, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07002552 struct fib6_table *table;
2553
2554 table = fib6_get_table(dev_net(dev), cfg.fc_table);
2555 if (table)
2556 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
2557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 return rt6_get_dflt_router(gwaddr, dev);
2560}
2561
David Ahern830218c2016-10-24 10:52:35 -07002562static void __rt6_purge_dflt_routers(struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563{
2564 struct rt6_info *rt;
2565
2566restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002567 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002568 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002569 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2570 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002571 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002572 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002573 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 goto restart;
2575 }
2576 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002577 read_unlock_bh(&table->tb6_lock);
David Ahern830218c2016-10-24 10:52:35 -07002578
2579 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
2580}
2581
2582void rt6_purge_dflt_routers(struct net *net)
2583{
2584 struct fib6_table *table;
2585 struct hlist_head *head;
2586 unsigned int h;
2587
2588 rcu_read_lock();
2589
2590 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
2591 head = &net->ipv6.fib_table_hash[h];
2592 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
2593 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
2594 __rt6_purge_dflt_routers(table);
2595 }
2596 }
2597
2598 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599}
2600
Daniel Lezcano55786892008-03-04 13:47:47 -08002601static void rtmsg_to_fib6_config(struct net *net,
2602 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002603 struct fib6_config *cfg)
2604{
2605 memset(cfg, 0, sizeof(*cfg));
2606
David Ahernca254492015-10-12 11:47:10 -07002607 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
2608 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07002609 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2610 cfg->fc_metric = rtmsg->rtmsg_metric;
2611 cfg->fc_expires = rtmsg->rtmsg_info;
2612 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2613 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2614 cfg->fc_flags = rtmsg->rtmsg_flags;
2615
Daniel Lezcano55786892008-03-04 13:47:47 -08002616 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002617
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002618 cfg->fc_dst = rtmsg->rtmsg_dst;
2619 cfg->fc_src = rtmsg->rtmsg_src;
2620 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002621}
2622
Daniel Lezcano55786892008-03-04 13:47:47 -08002623int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624{
Thomas Graf86872cb2006-08-22 00:01:08 -07002625 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 struct in6_rtmsg rtmsg;
2627 int err;
2628
Ian Morris67ba4152014-08-24 21:53:10 +01002629 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 case SIOCADDRT: /* Add a route */
2631 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002632 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return -EPERM;
2634 err = copy_from_user(&rtmsg, arg,
2635 sizeof(struct in6_rtmsg));
2636 if (err)
2637 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002638
Daniel Lezcano55786892008-03-04 13:47:47 -08002639 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 rtnl_lock();
2642 switch (cmd) {
2643 case SIOCADDRT:
David Ahern333c4302017-05-21 10:12:04 -06002644 err = ip6_route_add(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 break;
2646 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06002647 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 break;
2649 default:
2650 err = -EINVAL;
2651 }
2652 rtnl_unlock();
2653
2654 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657 return -EINVAL;
2658}
2659
2660/*
2661 * Drop the packet on the floor
2662 */
2663
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002664static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002666 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002667 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002668 switch (ipstats_mib_noroutes) {
2669 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002670 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002671 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002672 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2673 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002674 break;
2675 }
2676 /* FALLTHROUGH */
2677 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002678 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2679 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002680 break;
2681 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002682 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 kfree_skb(skb);
2684 return 0;
2685}
2686
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002687static int ip6_pkt_discard(struct sk_buff *skb)
2688{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002689 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002690}
2691
Eric W. Biedermanede20592015-10-07 16:48:47 -05002692static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
Eric Dumazetadf30902009-06-02 05:19:30 +00002694 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002695 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696}
2697
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002698static int ip6_pkt_prohibit(struct sk_buff *skb)
2699{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002700 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002701}
2702
Eric W. Biedermanede20592015-10-07 16:48:47 -05002703static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002704{
Eric Dumazetadf30902009-06-02 05:19:30 +00002705 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002706 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002707}
2708
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709/*
2710 * Allocate a dst for local (unicast / anycast) address.
2711 */
2712
2713struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2714 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002715 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716{
David Ahernca254492015-10-12 11:47:10 -07002717 u32 tb_id;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002718 struct net *net = dev_net(idev->dev);
David Ahern4832c302017-08-17 12:17:20 -07002719 struct net_device *dev = idev->dev;
David Ahern5f02ce242016-09-10 12:09:54 -07002720 struct rt6_info *rt;
2721
David Ahern5f02ce242016-09-10 12:09:54 -07002722 rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002723 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return ERR_PTR(-ENOMEM);
2725
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 in6_dev_hold(idev);
2727
David S. Miller11d53b42011-06-24 15:23:34 -07002728 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002729 rt->dst.input = ip6_input;
2730 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
David Ahern94b5e0f2017-02-02 08:52:21 -08002733 rt->rt6i_protocol = RTPROT_KERNEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002735 if (anycast)
2736 rt->rt6i_flags |= RTF_ANYCAST;
2737 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
Julian Anastasov550bab42013-10-20 15:43:04 +03002740 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002741 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 rt->rt6i_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07002743 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
2744 rt->rt6i_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 return rt;
2747}
2748
Daniel Walterc3968a82011-04-13 21:10:57 +00002749/* remove deleted ip from prefsrc entries */
2750struct arg_dev_net_ip {
2751 struct net_device *dev;
2752 struct net *net;
2753 struct in6_addr *addr;
2754};
2755
2756static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2757{
2758 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2759 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2760 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2761
David S. Millerd1918542011-12-28 20:19:20 -05002762 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002763 rt != net->ipv6.ip6_null_entry &&
2764 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2765 /* remove prefsrc entry */
2766 rt->rt6i_prefsrc.plen = 0;
2767 }
2768 return 0;
2769}
2770
2771void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2772{
2773 struct net *net = dev_net(ifp->idev->dev);
2774 struct arg_dev_net_ip adni = {
2775 .dev = ifp->idev->dev,
2776 .net = net,
2777 .addr = &ifp->addr,
2778 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002779 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002780}
2781
Duan Jiongbe7a0102014-05-15 15:56:14 +08002782#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2783#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2784
2785/* Remove routers and update dst entries when gateway turn into host. */
2786static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2787{
2788 struct in6_addr *gateway = (struct in6_addr *)arg;
2789
2790 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2791 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2792 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2793 return -1;
2794 }
2795 return 0;
2796}
2797
2798void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2799{
2800 fib6_clean_all(net, fib6_clean_tohost, gateway);
2801}
2802
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002803struct arg_dev_net {
2804 struct net_device *dev;
2805 struct net *net;
2806};
2807
David Aherna1a22c12017-01-18 07:40:36 -08002808/* called with write lock held for table with rt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809static int fib6_ifdown(struct rt6_info *rt, void *arg)
2810{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002811 const struct arg_dev_net *adn = arg;
2812 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002813
David S. Millerd1918542011-12-28 20:19:20 -05002814 if ((rt->dst.dev == dev || !dev) &&
David Aherna1a22c12017-01-18 07:40:36 -08002815 rt != adn->net->ipv6.ip6_null_entry &&
2816 (rt->rt6i_nsiblings == 0 ||
David Ahern8397ed32017-06-07 12:26:23 -06002817 (dev && netdev_unregistering(dev)) ||
David Aherna1a22c12017-01-18 07:40:36 -08002818 !rt->rt6i_idev->cnf.ignore_routes_with_linkdown))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002820
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 return 0;
2822}
2823
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002824void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002826 struct arg_dev_net adn = {
2827 .dev = dev,
2828 .net = net,
2829 };
2830
Li RongQing0c3584d2013-12-27 16:32:38 +08002831 fib6_clean_all(net, fib6_ifdown, &adn);
Eric W. Biedermane332bc62015-10-12 11:02:08 -05002832 if (dev)
2833 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834}
2835
Eric Dumazet95c96172012-04-15 05:58:06 +00002836struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002838 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839};
2840
2841static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2842{
2843 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2844 struct inet6_dev *idev;
2845
2846 /* In IPv6 pmtu discovery is not optional,
2847 so that RTAX_MTU lock cannot disable it.
2848 We still use this lock to block changes
2849 caused by addrconf/ndisc.
2850 */
2851
2852 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002853 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 return 0;
2855
2856 /* For administrative MTU increase, there is no way to discover
2857 IPv6 PMTU increase, so PMTU increase should be updated here.
2858 Since RFC 1981 doesn't include administrative MTU increase
2859 update PMTU increase is a MUST. (i.e. jumbo frame)
2860 */
2861 /*
2862 If new MTU is less than route PMTU, this new MTU will be the
2863 lowest MTU in the path, update the route PMTU to reflect PMTU
2864 decreases; if new MTU is greater than route PMTU, and the
2865 old MTU is the lowest MTU in the path, update the route PMTU
2866 to reflect the increase. In this case if the other nodes' MTU
2867 also have the lowest MTU, TOO BIG MESSAGE will be lead to
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002868 PMTU discovery.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 */
David S. Millerd1918542011-12-28 20:19:20 -05002870 if (rt->dst.dev == arg->dev &&
Maciej Żenczykowskifb56be82016-11-04 14:51:54 -07002871 dst_metric_raw(&rt->dst, RTAX_MTU) &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002872 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2873 if (rt->rt6i_flags & RTF_CACHE) {
2874 /* For RTF_CACHE with rt6i_pmtu == 0
2875 * (i.e. a redirected route),
2876 * the metrics of its rt->dst.from has already
2877 * been updated.
2878 */
2879 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2880 rt->rt6i_pmtu = arg->mtu;
2881 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2882 (dst_mtu(&rt->dst) < arg->mtu &&
2883 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2884 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2885 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 return 0;
2888}
2889
Eric Dumazet95c96172012-04-15 05:58:06 +00002890void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891{
Thomas Grafc71099a2006-08-04 23:20:06 -07002892 struct rt6_mtu_change_arg arg = {
2893 .dev = dev,
2894 .mtu = mtu,
2895 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
Li RongQing0c3584d2013-12-27 16:32:38 +08002897 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898}
2899
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002900static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002901 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002902 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002903 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002904 [RTA_PRIORITY] = { .type = NLA_U32 },
2905 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002906 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002907 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002908 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2909 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08002910 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09002911 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08002912 [RTA_MARK] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002913};
2914
2915static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06002916 struct fib6_config *cfg,
2917 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918{
Thomas Graf86872cb2006-08-22 00:01:08 -07002919 struct rtmsg *rtm;
2920 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002921 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002922 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Johannes Bergfceb6432017-04-12 14:34:07 +02002924 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
2925 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07002926 if (err < 0)
2927 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
Thomas Graf86872cb2006-08-22 00:01:08 -07002929 err = -EINVAL;
2930 rtm = nlmsg_data(nlh);
2931 memset(cfg, 0, sizeof(*cfg));
2932
2933 cfg->fc_table = rtm->rtm_table;
2934 cfg->fc_dst_len = rtm->rtm_dst_len;
2935 cfg->fc_src_len = rtm->rtm_src_len;
2936 cfg->fc_flags = RTF_UP;
2937 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002938 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002939
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002940 if (rtm->rtm_type == RTN_UNREACHABLE ||
2941 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002942 rtm->rtm_type == RTN_PROHIBIT ||
2943 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002944 cfg->fc_flags |= RTF_REJECT;
2945
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002946 if (rtm->rtm_type == RTN_LOCAL)
2947 cfg->fc_flags |= RTF_LOCAL;
2948
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002949 if (rtm->rtm_flags & RTM_F_CLONED)
2950 cfg->fc_flags |= RTF_CACHE;
2951
Eric W. Biederman15e47302012-09-07 20:12:54 +00002952 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002953 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002954 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002955
2956 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002957 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002958 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002960
2961 if (tb[RTA_DST]) {
2962 int plen = (rtm->rtm_dst_len + 7) >> 3;
2963
2964 if (nla_len(tb[RTA_DST]) < plen)
2965 goto errout;
2966
2967 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002969
2970 if (tb[RTA_SRC]) {
2971 int plen = (rtm->rtm_src_len + 7) >> 3;
2972
2973 if (nla_len(tb[RTA_SRC]) < plen)
2974 goto errout;
2975
2976 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002978
Daniel Walterc3968a82011-04-13 21:10:57 +00002979 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002980 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002981
Thomas Graf86872cb2006-08-22 00:01:08 -07002982 if (tb[RTA_OIF])
2983 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2984
2985 if (tb[RTA_PRIORITY])
2986 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2987
2988 if (tb[RTA_METRICS]) {
2989 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2990 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002992
2993 if (tb[RTA_TABLE])
2994 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2995
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002996 if (tb[RTA_MULTIPATH]) {
2997 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2998 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08002999
3000 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06003001 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003002 if (err < 0)
3003 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003004 }
3005
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003006 if (tb[RTA_PREF]) {
3007 pref = nla_get_u8(tb[RTA_PREF]);
3008 if (pref != ICMPV6_ROUTER_PREF_LOW &&
3009 pref != ICMPV6_ROUTER_PREF_HIGH)
3010 pref = ICMPV6_ROUTER_PREF_MEDIUM;
3011 cfg->fc_flags |= RTF_PREF(pref);
3012 }
3013
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003014 if (tb[RTA_ENCAP])
3015 cfg->fc_encap = tb[RTA_ENCAP];
3016
David Ahern9ed59592017-01-17 14:57:36 -08003017 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003018 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
3019
David Ahernc255bd62017-05-27 16:19:27 -06003020 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003021 if (err < 0)
3022 goto errout;
3023 }
3024
Xin Long32bc2012015-12-16 17:50:11 +08003025 if (tb[RTA_EXPIRES]) {
3026 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
3027
3028 if (addrconf_finite_timeout(timeout)) {
3029 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
3030 cfg->fc_flags |= RTF_EXPIRES;
3031 }
3032 }
3033
Thomas Graf86872cb2006-08-22 00:01:08 -07003034 err = 0;
3035errout:
3036 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037}
3038
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003039struct rt6_nh {
3040 struct rt6_info *rt6_info;
3041 struct fib6_config r_cfg;
3042 struct mx6_config mxc;
3043 struct list_head next;
3044};
3045
3046static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
3047{
3048 struct rt6_nh *nh;
3049
3050 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08003051 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 -07003052 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
3053 nh->r_cfg.fc_ifindex);
3054 }
3055}
3056
3057static int ip6_route_info_append(struct list_head *rt6_nh_list,
3058 struct rt6_info *rt, struct fib6_config *r_cfg)
3059{
3060 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003061 int err = -EEXIST;
3062
3063 list_for_each_entry(nh, rt6_nh_list, next) {
3064 /* check if rt6_info already exists */
David Ahernf06b7542017-07-05 14:41:46 -06003065 if (rt6_duplicate_nexthop(nh->rt6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003066 return err;
3067 }
3068
3069 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
3070 if (!nh)
3071 return -ENOMEM;
3072 nh->rt6_info = rt;
3073 err = ip6_convert_metrics(&nh->mxc, r_cfg);
3074 if (err) {
3075 kfree(nh);
3076 return err;
3077 }
3078 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
3079 list_add_tail(&nh->next, rt6_nh_list);
3080
3081 return 0;
3082}
3083
David Ahern3b1137f2017-02-02 12:37:10 -08003084static void ip6_route_mpath_notify(struct rt6_info *rt,
3085 struct rt6_info *rt_last,
3086 struct nl_info *info,
3087 __u16 nlflags)
3088{
3089 /* if this is an APPEND route, then rt points to the first route
3090 * inserted and rt_last points to last route inserted. Userspace
3091 * wants a consistent dump of the route which starts at the first
3092 * nexthop. Since sibling routes are always added at the end of
3093 * the list, find the first sibling of the last route appended
3094 */
3095 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
3096 rt = list_first_entry(&rt_last->rt6i_siblings,
3097 struct rt6_info,
3098 rt6i_siblings);
3099 }
3100
3101 if (rt)
3102 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
3103}
3104
David Ahern333c4302017-05-21 10:12:04 -06003105static int ip6_route_multipath_add(struct fib6_config *cfg,
3106 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003107{
David Ahern3b1137f2017-02-02 12:37:10 -08003108 struct rt6_info *rt_notif = NULL, *rt_last = NULL;
3109 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003110 struct fib6_config r_cfg;
3111 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003112 struct rt6_info *rt;
3113 struct rt6_nh *err_nh;
3114 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08003115 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003116 int remaining;
3117 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003118 int err = 1;
3119 int nhn = 0;
3120 int replace = (cfg->fc_nlinfo.nlh &&
3121 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
3122 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003123
David Ahern3b1137f2017-02-02 12:37:10 -08003124 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
3125 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
3126 nlflags |= NLM_F_APPEND;
3127
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02003128 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003129 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003130
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003131 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
3132 * rt6_info structs per nexthop
3133 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003134 while (rtnh_ok(rtnh, remaining)) {
3135 memcpy(&r_cfg, cfg, sizeof(*cfg));
3136 if (rtnh->rtnh_ifindex)
3137 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3138
3139 attrlen = rtnh_attrlen(rtnh);
3140 if (attrlen > 0) {
3141 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3142
3143 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3144 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003145 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003146 r_cfg.fc_flags |= RTF_GATEWAY;
3147 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003148 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
3149 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
3150 if (nla)
3151 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003152 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003153
David Ahern333c4302017-05-21 10:12:04 -06003154 rt = ip6_route_info_create(&r_cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003155 if (IS_ERR(rt)) {
3156 err = PTR_ERR(rt);
3157 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003158 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003159 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003160
3161 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003162 if (err) {
Wei Wang587fea72017-06-17 10:42:36 -07003163 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003164 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003165 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003166
3167 rtnh = rtnh_next(rtnh, &remaining);
3168 }
3169
David Ahern3b1137f2017-02-02 12:37:10 -08003170 /* for add and replace send one notification with all nexthops.
3171 * Skip the notification in fib6_add_rt2node and send one with
3172 * the full route when done
3173 */
3174 info->skip_notify = 1;
3175
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003176 err_nh = NULL;
3177 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern3b1137f2017-02-02 12:37:10 -08003178 rt_last = nh->rt6_info;
David Ahern333c4302017-05-21 10:12:04 -06003179 err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
David Ahern3b1137f2017-02-02 12:37:10 -08003180 /* save reference to first route for notification */
3181 if (!rt_notif && !err)
3182 rt_notif = nh->rt6_info;
3183
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003184 /* nh->rt6_info is used or freed at this point, reset to NULL*/
3185 nh->rt6_info = NULL;
3186 if (err) {
3187 if (replace && nhn)
3188 ip6_print_replace_route_err(&rt6_nh_list);
3189 err_nh = nh;
3190 goto add_errout;
3191 }
3192
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003193 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02003194 * these flags after the first nexthop: if there is a collision,
3195 * we have already failed to add the first nexthop:
3196 * fib6_add_rt2node() has rejected it; when replacing, old
3197 * nexthops have been replaced by first new, the rest should
3198 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003199 */
Michal Kubeček27596472015-05-18 20:54:00 +02003200 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
3201 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003202 nhn++;
3203 }
3204
David Ahern3b1137f2017-02-02 12:37:10 -08003205 /* success ... tell user about new route */
3206 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003207 goto cleanup;
3208
3209add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08003210 /* send notification for routes that were added so that
3211 * the delete notifications sent by ip6_route_del are
3212 * coherent
3213 */
3214 if (rt_notif)
3215 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
3216
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003217 /* Delete routes that were already added */
3218 list_for_each_entry(nh, &rt6_nh_list, next) {
3219 if (err_nh == nh)
3220 break;
David Ahern333c4302017-05-21 10:12:04 -06003221 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003222 }
3223
3224cleanup:
3225 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
Wei Wang587fea72017-06-17 10:42:36 -07003226 if (nh->rt6_info)
3227 dst_release_immediate(&nh->rt6_info->dst);
Wu Fengguang52fe51f2015-09-10 06:57:12 +08003228 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003229 list_del(&nh->next);
3230 kfree(nh);
3231 }
3232
3233 return err;
3234}
3235
David Ahern333c4302017-05-21 10:12:04 -06003236static int ip6_route_multipath_del(struct fib6_config *cfg,
3237 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003238{
3239 struct fib6_config r_cfg;
3240 struct rtnexthop *rtnh;
3241 int remaining;
3242 int attrlen;
3243 int err = 1, last_err = 0;
3244
3245 remaining = cfg->fc_mp_len;
3246 rtnh = (struct rtnexthop *)cfg->fc_mp;
3247
3248 /* Parse a Multipath Entry */
3249 while (rtnh_ok(rtnh, remaining)) {
3250 memcpy(&r_cfg, cfg, sizeof(*cfg));
3251 if (rtnh->rtnh_ifindex)
3252 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3253
3254 attrlen = rtnh_attrlen(rtnh);
3255 if (attrlen > 0) {
3256 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3257
3258 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3259 if (nla) {
3260 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
3261 r_cfg.fc_flags |= RTF_GATEWAY;
3262 }
3263 }
David Ahern333c4302017-05-21 10:12:04 -06003264 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003265 if (err)
3266 last_err = err;
3267
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003268 rtnh = rtnh_next(rtnh, &remaining);
3269 }
3270
3271 return last_err;
3272}
3273
David Ahernc21ef3e2017-04-16 09:48:24 -07003274static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3275 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276{
Thomas Graf86872cb2006-08-22 00:01:08 -07003277 struct fib6_config cfg;
3278 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
David Ahern333c4302017-05-21 10:12:04 -06003280 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003281 if (err < 0)
3282 return err;
3283
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003284 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003285 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003286 else {
3287 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06003288 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290}
3291
David Ahernc21ef3e2017-04-16 09:48:24 -07003292static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3293 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294{
Thomas Graf86872cb2006-08-22 00:01:08 -07003295 struct fib6_config cfg;
3296 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
David Ahern333c4302017-05-21 10:12:04 -06003298 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003299 if (err < 0)
3300 return err;
3301
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003302 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003303 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003304 else
David Ahern333c4302017-05-21 10:12:04 -06003305 return ip6_route_add(&cfg, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306}
3307
David Ahernbeb1afac52017-02-02 12:37:09 -08003308static size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08003309{
David Ahernbeb1afac52017-02-02 12:37:09 -08003310 int nexthop_len = 0;
3311
3312 if (rt->rt6i_nsiblings) {
3313 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
3314 + NLA_ALIGN(sizeof(struct rtnexthop))
3315 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernbeb1afac52017-02-02 12:37:09 -08003316 + lwtunnel_get_encap_size(rt->dst.lwtstate);
3317
3318 nexthop_len *= rt->rt6i_nsiblings;
3319 }
3320
Thomas Graf339bf982006-11-10 14:10:15 -08003321 return NLMSG_ALIGN(sizeof(struct rtmsg))
3322 + nla_total_size(16) /* RTA_SRC */
3323 + nla_total_size(16) /* RTA_DST */
3324 + nla_total_size(16) /* RTA_GATEWAY */
3325 + nla_total_size(16) /* RTA_PREFSRC */
3326 + nla_total_size(4) /* RTA_TABLE */
3327 + nla_total_size(4) /* RTA_IIF */
3328 + nla_total_size(4) /* RTA_OIF */
3329 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08003330 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01003331 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003332 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003333 + nla_total_size(1) /* RTA_PREF */
David Ahernbeb1afac52017-02-02 12:37:09 -08003334 + lwtunnel_get_encap_size(rt->dst.lwtstate)
3335 + nexthop_len;
3336}
3337
3338static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08003339 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08003340{
3341 if (!netif_running(rt->dst.dev) || !netif_carrier_ok(rt->dst.dev)) {
3342 *flags |= RTNH_F_LINKDOWN;
3343 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3344 *flags |= RTNH_F_DEAD;
3345 }
3346
3347 if (rt->rt6i_flags & RTF_GATEWAY) {
3348 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
3349 goto nla_put_failure;
3350 }
3351
Ido Schimmelfe400792017-08-15 09:09:49 +02003352 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02003353 *flags |= RTNH_F_OFFLOAD;
3354
David Ahern5be083c2017-03-06 15:57:31 -08003355 /* not needed for multipath encoding b/c it has a rtnexthop struct */
3356 if (!skip_oif && rt->dst.dev &&
David Ahernbeb1afac52017-02-02 12:37:09 -08003357 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
3358 goto nla_put_failure;
3359
3360 if (rt->dst.lwtstate &&
3361 lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
3362 goto nla_put_failure;
3363
3364 return 0;
3365
3366nla_put_failure:
3367 return -EMSGSIZE;
3368}
3369
David Ahern5be083c2017-03-06 15:57:31 -08003370/* add multipath next hop */
David Ahernbeb1afac52017-02-02 12:37:09 -08003371static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
3372{
3373 struct rtnexthop *rtnh;
3374 unsigned int flags = 0;
3375
3376 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
3377 if (!rtnh)
3378 goto nla_put_failure;
3379
3380 rtnh->rtnh_hops = 0;
3381 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
3382
David Ahern5be083c2017-03-06 15:57:31 -08003383 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003384 goto nla_put_failure;
3385
3386 rtnh->rtnh_flags = flags;
3387
3388 /* length of rtnetlink header + attributes */
3389 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
3390
3391 return 0;
3392
3393nla_put_failure:
3394 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08003395}
3396
Brian Haley191cd582008-08-14 15:33:21 -07003397static int rt6_fill_node(struct net *net,
3398 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07003399 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003400 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003401 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003403 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003405 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08003406 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07003407 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
Eric W. Biederman15e47302012-09-07 20:12:54 +00003409 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05003410 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08003411 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003412
3413 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 rtm->rtm_family = AF_INET6;
3415 rtm->rtm_dst_len = rt->rt6i_dst.plen;
3416 rtm->rtm_src_len = rt->rt6i_src.plen;
3417 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07003418 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07003419 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07003420 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07003421 table = RT6_TABLE_UNSPEC;
3422 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04003423 if (nla_put_u32(skb, RTA_TABLE, table))
3424 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003425 if (rt->rt6i_flags & RTF_REJECT) {
3426 switch (rt->dst.error) {
3427 case -EINVAL:
3428 rtm->rtm_type = RTN_BLACKHOLE;
3429 break;
3430 case -EACCES:
3431 rtm->rtm_type = RTN_PROHIBIT;
3432 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003433 case -EAGAIN:
3434 rtm->rtm_type = RTN_THROW;
3435 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003436 default:
3437 rtm->rtm_type = RTN_UNREACHABLE;
3438 break;
3439 }
3440 }
David S. Miller38308472011-12-03 18:02:47 -05003441 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003442 rtm->rtm_type = RTN_LOCAL;
David Ahern4ee39732017-03-15 18:14:33 -07003443 else if (rt->rt6i_flags & RTF_ANYCAST)
3444 rtm->rtm_type = RTN_ANYCAST;
David S. Millerd1918542011-12-28 20:19:20 -05003445 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 rtm->rtm_type = RTN_LOCAL;
3447 else
3448 rtm->rtm_type = RTN_UNICAST;
3449 rtm->rtm_flags = 0;
3450 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
3451 rtm->rtm_protocol = rt->rt6i_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452
David S. Miller38308472011-12-03 18:02:47 -05003453 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 rtm->rtm_flags |= RTM_F_CLONED;
3455
3456 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02003457 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04003458 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003459 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02003461 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003462 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463#ifdef CONFIG_IPV6_SUBTREES
3464 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02003465 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04003466 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003467 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04003468 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02003469 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003470 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003472 if (iif) {
3473#ifdef CONFIG_IPV6_MROUTE
3474 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08003475 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02003476
David Ahernfd61c6b2017-01-17 15:51:07 -08003477 if (err == 0)
3478 return 0;
3479 if (err < 0)
3480 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003481 } else
3482#endif
David S. Millerc78679e2012-04-01 20:27:33 -04003483 if (nla_put_u32(skb, RTA_IIF, iif))
3484 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003485 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04003487 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02003488 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003489 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003491
Daniel Walterc3968a82011-04-13 21:10:57 +00003492 if (rt->rt6i_prefsrc.plen) {
3493 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003494 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02003495 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003496 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00003497 }
3498
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003499 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
3500 if (rt->rt6i_pmtu)
3501 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
3502 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07003503 goto nla_put_failure;
3504
David S. Millerc78679e2012-04-01 20:27:33 -04003505 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
3506 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00003507
David Ahernbeb1afac52017-02-02 12:37:09 -08003508 /* For multipath routes, walk the siblings list and add
3509 * each as a nexthop within RTA_MULTIPATH.
3510 */
3511 if (rt->rt6i_nsiblings) {
3512 struct rt6_info *sibling, *next_sibling;
3513 struct nlattr *mp;
3514
3515 mp = nla_nest_start(skb, RTA_MULTIPATH);
3516 if (!mp)
3517 goto nla_put_failure;
3518
3519 if (rt6_add_nexthop(skb, rt) < 0)
3520 goto nla_put_failure;
3521
3522 list_for_each_entry_safe(sibling, next_sibling,
3523 &rt->rt6i_siblings, rt6i_siblings) {
3524 if (rt6_add_nexthop(skb, sibling) < 0)
3525 goto nla_put_failure;
3526 }
3527
3528 nla_nest_end(skb, mp);
3529 } else {
David Ahern5be083c2017-03-06 15:57:31 -08003530 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003531 goto nla_put_failure;
3532 }
3533
Li Wei82539472012-07-29 16:01:30 +00003534 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07003535
David S. Miller87a50692012-07-10 05:06:14 -07003536 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08003537 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003539 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3540 goto nla_put_failure;
3541
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003542
Johannes Berg053c0952015-01-16 22:09:00 +01003543 nlmsg_end(skb, nlh);
3544 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003545
3546nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08003547 nlmsg_cancel(skb, nlh);
3548 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549}
3550
Patrick McHardy1b43af52006-08-10 23:11:17 -07003551int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552{
3553 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08003554 struct net *net = arg->net;
3555
3556 if (rt == net->ipv6.ip6_null_entry)
3557 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
Thomas Graf2d7202b2006-08-22 00:01:27 -07003559 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
3560 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08003561
3562 /* user wants prefix routes only */
3563 if (rtm->rtm_flags & RTM_F_PREFIX &&
3564 !(rt->rt6i_flags & RTF_PREFIX_RT)) {
3565 /* success since this is not a prefix route */
3566 return 1;
3567 }
3568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
David Ahern1f17e2f2017-01-26 13:54:08 -08003570 return rt6_fill_node(net,
Brian Haley191cd582008-08-14 15:33:21 -07003571 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003572 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003573 NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574}
3575
David Ahernc21ef3e2017-04-16 09:48:24 -07003576static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
3577 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003579 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003580 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003581 int err, iif = 0, oif = 0;
3582 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003584 struct sk_buff *skb;
3585 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003586 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003587 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07003588
Johannes Bergfceb6432017-04-12 14:34:07 +02003589 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07003590 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07003591 if (err < 0)
3592 goto errout;
3593
3594 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003595 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02003596 rtm = nlmsg_data(nlh);
3597 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003598 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07003599
3600 if (tb[RTA_SRC]) {
3601 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3602 goto errout;
3603
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003604 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003605 }
3606
3607 if (tb[RTA_DST]) {
3608 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3609 goto errout;
3610
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003611 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003612 }
3613
3614 if (tb[RTA_IIF])
3615 iif = nla_get_u32(tb[RTA_IIF]);
3616
3617 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003618 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003619
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003620 if (tb[RTA_MARK])
3621 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3622
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09003623 if (tb[RTA_UID])
3624 fl6.flowi6_uid = make_kuid(current_user_ns(),
3625 nla_get_u32(tb[RTA_UID]));
3626 else
3627 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
3628
Thomas Grafab364a62006-08-22 00:01:47 -07003629 if (iif) {
3630 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003631 int flags = 0;
3632
Florian Westphal121622d2017-08-15 16:34:42 +02003633 rcu_read_lock();
3634
3635 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003636 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02003637 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07003638 err = -ENODEV;
3639 goto errout;
3640 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003641
3642 fl6.flowi6_iif = iif;
3643
3644 if (!ipv6_addr_any(&fl6.saddr))
3645 flags |= RT6_LOOKUP_F_HAS_SADDR;
3646
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003647 if (!fibmatch)
3648 dst = ip6_route_input_lookup(net, dev, &fl6, flags);
Arnd Bergmann401481e2017-08-18 13:34:22 +02003649 else
3650 dst = ip6_route_lookup(net, &fl6, 0);
Florian Westphal121622d2017-08-15 16:34:42 +02003651
3652 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003653 } else {
3654 fl6.flowi6_oif = oif;
3655
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003656 if (!fibmatch)
3657 dst = ip6_route_output(net, NULL, &fl6);
Arnd Bergmann401481e2017-08-18 13:34:22 +02003658 else
3659 dst = ip6_route_lookup(net, &fl6, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003660 }
3661
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003662
3663 rt = container_of(dst, struct rt6_info, dst);
3664 if (rt->dst.error) {
3665 err = rt->dst.error;
3666 ip6_rt_put(rt);
3667 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07003668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
WANG Cong9d6acb32017-03-01 20:48:39 -08003670 if (rt == net->ipv6.ip6_null_entry) {
3671 err = rt->dst.error;
3672 ip6_rt_put(rt);
3673 goto errout;
3674 }
3675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003677 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003678 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003679 err = -ENOBUFS;
3680 goto errout;
3681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682
Changli Gaod8d1f302010-06-10 23:31:35 -07003683 skb_dst_set(skb, &rt->dst);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003684 if (fibmatch)
3685 err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
3686 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3687 nlh->nlmsg_seq, 0);
3688 else
3689 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
3690 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3691 nlh->nlmsg_seq, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003693 kfree_skb(skb);
3694 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 }
3696
Eric W. Biederman15e47302012-09-07 20:12:54 +00003697 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003698errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700}
3701
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003702void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
3703 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704{
3705 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003706 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003707 u32 seq;
3708 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003710 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003711 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003712
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003713 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003714 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003715 goto errout;
3716
Brian Haley191cd582008-08-14 15:33:21 -07003717 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003718 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003719 if (err < 0) {
3720 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3721 WARN_ON(err == -EMSGSIZE);
3722 kfree_skb(skb);
3723 goto errout;
3724 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003725 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003726 info->nlh, gfp_any());
3727 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003728errout:
3729 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003730 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731}
3732
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003733static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003734 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003735{
Jiri Pirko351638e2013-05-28 01:30:21 +00003736 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003737 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003738
WANG Cong242d3a42017-05-08 10:12:13 -07003739 if (!(dev->flags & IFF_LOOPBACK))
3740 return NOTIFY_OK;
3741
3742 if (event == NETDEV_REGISTER) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003743 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003744 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3745#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003746 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003747 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003748 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003749 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3750#endif
WANG Cong76da0702017-06-20 11:42:27 -07003751 } else if (event == NETDEV_UNREGISTER &&
3752 dev->reg_state != NETREG_UNREGISTERED) {
3753 /* NETDEV_UNREGISTER could be fired for multiple times by
3754 * netdev_wait_allrefs(). Make sure we only call this once.
3755 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07003756 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07003757#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07003758 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
3759 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07003760#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003761 }
3762
3763 return NOTIFY_OK;
3764}
3765
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766/*
3767 * /proc
3768 */
3769
3770#ifdef CONFIG_PROC_FS
3771
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003772static const struct file_operations ipv6_route_proc_fops = {
3773 .owner = THIS_MODULE,
3774 .open = ipv6_route_open,
3775 .read = seq_read,
3776 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003777 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003778};
3779
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3781{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003782 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003784 net->ipv6.rt6_stats->fib_nodes,
3785 net->ipv6.rt6_stats->fib_route_nodes,
3786 net->ipv6.rt6_stats->fib_rt_alloc,
3787 net->ipv6.rt6_stats->fib_rt_entries,
3788 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003789 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003790 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
3792 return 0;
3793}
3794
3795static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3796{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003797 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003798}
3799
Arjan van de Ven9a321442007-02-12 00:55:35 -08003800static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 .owner = THIS_MODULE,
3802 .open = rt6_stats_seq_open,
3803 .read = seq_read,
3804 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003805 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806};
3807#endif /* CONFIG_PROC_FS */
3808
3809#ifdef CONFIG_SYSCTL
3810
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003812int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 void __user *buffer, size_t *lenp, loff_t *ppos)
3814{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003815 struct net *net;
3816 int delay;
3817 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003819
3820 net = (struct net *)ctl->extra1;
3821 delay = net->ipv6.sysctl.flush_delay;
3822 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003823 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003824 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825}
3826
Joe Perchesfe2c6332013-06-11 23:04:25 -07003827struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003828 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003830 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003832 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003833 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 },
3835 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003837 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 .maxlen = sizeof(int),
3839 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003840 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 },
3842 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003844 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 .maxlen = sizeof(int),
3846 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003847 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 },
3849 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003851 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 .maxlen = sizeof(int),
3853 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003854 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 },
3856 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003858 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 .maxlen = sizeof(int),
3860 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003861 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 },
3863 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003865 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 .maxlen = sizeof(int),
3867 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003868 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 },
3870 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003872 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 .maxlen = sizeof(int),
3874 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003875 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 },
3877 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003879 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 .maxlen = sizeof(int),
3881 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003882 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 },
3884 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003886 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 .maxlen = sizeof(int),
3888 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003889 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 },
3891 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003893 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 .maxlen = sizeof(int),
3895 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003896 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003898 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899};
3900
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003901struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003902{
3903 struct ctl_table *table;
3904
3905 table = kmemdup(ipv6_route_table_template,
3906 sizeof(ipv6_route_table_template),
3907 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003908
3909 if (table) {
3910 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003911 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003912 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003913 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3914 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3915 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3916 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3917 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3918 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3919 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003920 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003921
3922 /* Don't export sysctls to unprivileged users */
3923 if (net->user_ns != &init_user_ns)
3924 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003925 }
3926
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003927 return table;
3928}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929#endif
3930
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003931static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003932{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003933 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003934
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003935 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3936 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003937
Eric Dumazetfc66f952010-10-08 06:37:34 +00003938 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3939 goto out_ip6_dst_ops;
3940
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003941 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3942 sizeof(*net->ipv6.ip6_null_entry),
3943 GFP_KERNEL);
3944 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003945 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003946 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003947 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003948 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003949 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3950 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003951
3952#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02003953 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003954 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3955 sizeof(*net->ipv6.ip6_prohibit_entry),
3956 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003957 if (!net->ipv6.ip6_prohibit_entry)
3958 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003959 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003960 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003961 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003962 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3963 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003964
3965 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3966 sizeof(*net->ipv6.ip6_blk_hole_entry),
3967 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003968 if (!net->ipv6.ip6_blk_hole_entry)
3969 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003970 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003971 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003972 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003973 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3974 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003975#endif
3976
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003977 net->ipv6.sysctl.flush_delay = 0;
3978 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3979 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3980 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3981 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3982 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3983 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3984 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3985
Benjamin Thery6891a342008-03-04 13:49:47 -08003986 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3987
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003988 ret = 0;
3989out:
3990 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003991
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003992#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3993out_ip6_prohibit_entry:
3994 kfree(net->ipv6.ip6_prohibit_entry);
3995out_ip6_null_entry:
3996 kfree(net->ipv6.ip6_null_entry);
3997#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003998out_ip6_dst_entries:
3999 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004000out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004001 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004002}
4003
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004004static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004005{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004006 kfree(net->ipv6.ip6_null_entry);
4007#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4008 kfree(net->ipv6.ip6_prohibit_entry);
4009 kfree(net->ipv6.ip6_blk_hole_entry);
4010#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004011 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004012}
4013
Thomas Grafd1896342012-06-18 12:08:33 +00004014static int __net_init ip6_route_net_init_late(struct net *net)
4015{
4016#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00004017 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
4018 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00004019#endif
4020 return 0;
4021}
4022
4023static void __net_exit ip6_route_net_exit_late(struct net *net)
4024{
4025#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00004026 remove_proc_entry("ipv6_route", net->proc_net);
4027 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00004028#endif
4029}
4030
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004031static struct pernet_operations ip6_route_net_ops = {
4032 .init = ip6_route_net_init,
4033 .exit = ip6_route_net_exit,
4034};
4035
David S. Millerc3426b42012-06-09 16:27:05 -07004036static int __net_init ipv6_inetpeer_init(struct net *net)
4037{
4038 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
4039
4040 if (!bp)
4041 return -ENOMEM;
4042 inet_peer_base_init(bp);
4043 net->ipv6.peers = bp;
4044 return 0;
4045}
4046
4047static void __net_exit ipv6_inetpeer_exit(struct net *net)
4048{
4049 struct inet_peer_base *bp = net->ipv6.peers;
4050
4051 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07004052 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07004053 kfree(bp);
4054}
4055
David S. Miller2b823f72012-06-09 19:00:16 -07004056static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07004057 .init = ipv6_inetpeer_init,
4058 .exit = ipv6_inetpeer_exit,
4059};
4060
Thomas Grafd1896342012-06-18 12:08:33 +00004061static struct pernet_operations ip6_route_net_late_ops = {
4062 .init = ip6_route_net_init_late,
4063 .exit = ip6_route_net_exit_late,
4064};
4065
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004066static struct notifier_block ip6_route_dev_notifier = {
4067 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07004068 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004069};
4070
WANG Cong2f460932017-05-03 22:07:31 -07004071void __init ip6_route_init_special_entries(void)
4072{
4073 /* Registering of the loopback is done before this portion of code,
4074 * the loopback reference in rt6_info will not be taken, do it
4075 * manually for init_net */
4076 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
4077 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4078 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
4079 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
4080 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4081 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
4082 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4083 #endif
4084}
4085
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004086int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004088 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004089 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004090
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004091 ret = -ENOMEM;
4092 ip6_dst_ops_template.kmem_cachep =
4093 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
4094 SLAB_HWCACHE_ALIGN, NULL);
4095 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08004096 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07004097
Eric Dumazetfc66f952010-10-08 06:37:34 +00004098 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004099 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004100 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004101
David S. Millerc3426b42012-06-09 16:27:05 -07004102 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
4103 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004104 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00004105
David S. Miller7e52b332012-06-15 15:51:55 -07004106 ret = register_pernet_subsys(&ip6_route_net_ops);
4107 if (ret)
4108 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07004109
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07004110 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
4111
David S. Millere8803b62012-06-16 01:12:19 -07004112 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004113 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004114 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004115
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004116 ret = xfrm6_init();
4117 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004118 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08004119
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004120 ret = fib6_rules_init();
4121 if (ret)
4122 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08004123
Thomas Grafd1896342012-06-18 12:08:33 +00004124 ret = register_pernet_subsys(&ip6_route_net_late_ops);
4125 if (ret)
4126 goto fib6_rules_init;
4127
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004128 ret = -ENOBUFS;
Florian Westphalb97bac62017-08-09 20:41:48 +02004129 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, 0) ||
4130 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, 0) ||
Florian Westphale3a22b72017-08-15 16:34:43 +02004131 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL,
4132 RTNL_FLAG_DOIT_UNLOCKED))
Thomas Grafd1896342012-06-18 12:08:33 +00004133 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004134
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004135 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004136 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00004137 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004138
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004139 for_each_possible_cpu(cpu) {
4140 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
4141
4142 INIT_LIST_HEAD(&ul->head);
4143 spin_lock_init(&ul->lock);
4144 }
4145
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004146out:
4147 return ret;
4148
Thomas Grafd1896342012-06-18 12:08:33 +00004149out_register_late_subsys:
4150 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004151fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004152 fib6_rules_cleanup();
4153xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004154 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00004155out_fib6_init:
4156 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004157out_register_subsys:
4158 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07004159out_register_inetpeer:
4160 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00004161out_dst_entries:
4162 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004163out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004164 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004165 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166}
4167
4168void ip6_route_cleanup(void)
4169{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004170 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00004171 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07004172 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07004175 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004176 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004177 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004178 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179}