blob: 6c4dd5796a3126b1391cfe53c976e973742512f2 [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
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001217static void ip6_multipath_l3_keys(const struct sk_buff *skb,
1218 struct flow_keys *keys)
1219{
1220 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1221 const struct ipv6hdr *key_iph = outer_iph;
1222 const struct ipv6hdr *inner_iph;
1223 const struct icmp6hdr *icmph;
1224 struct ipv6hdr _inner_iph;
1225
1226 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1227 goto out;
1228
1229 icmph = icmp6_hdr(skb);
1230 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1231 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1232 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1233 icmph->icmp6_type != ICMPV6_PARAMPROB)
1234 goto out;
1235
1236 inner_iph = skb_header_pointer(skb,
1237 skb_transport_offset(skb) + sizeof(*icmph),
1238 sizeof(_inner_iph), &_inner_iph);
1239 if (!inner_iph)
1240 goto out;
1241
1242 key_iph = inner_iph;
1243out:
1244 memset(keys, 0, sizeof(*keys));
1245 keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1246 keys->addrs.v6addrs.src = key_iph->saddr;
1247 keys->addrs.v6addrs.dst = key_iph->daddr;
1248 keys->tags.flow_label = ip6_flowinfo(key_iph);
1249 keys->basic.ip_proto = key_iph->nexthdr;
1250}
1251
1252/* if skb is set it will be used and fl6 can be NULL */
1253u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb)
1254{
1255 struct flow_keys hash_keys;
1256
1257 if (skb) {
1258 ip6_multipath_l3_keys(skb, &hash_keys);
1259 return flow_hash_from_keys(&hash_keys);
1260 }
1261
1262 return get_hash_from_flowi6(fl6);
1263}
1264
Thomas Grafc71099a2006-08-04 23:20:06 -07001265void ip6_route_input(struct sk_buff *skb)
1266{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001267 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001268 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001269 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001270 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001271 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07001272 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05001273 .daddr = iph->daddr,
1274 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001275 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001276 .flowi6_mark = skb->mark,
1277 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001278 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001279
Jiri Benc904af042015-08-20 13:56:31 +02001280 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001281 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001282 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001283 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
1284 fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
Jiri Benc06e9d042015-08-20 13:56:26 +02001285 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001286 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001287}
1288
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001289static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001290 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001291{
David S. Miller4c9483b2011-03-12 16:22:43 -05001292 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001293}
1294
Paolo Abeni6f21c962016-01-29 12:30:19 +01001295struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
1296 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001297{
David Ahernd46a9d62015-10-21 08:42:22 -07001298 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07001299
David Ahern4c1feac2016-09-10 12:09:56 -07001300 if (rt6_need_strict(&fl6->daddr)) {
1301 struct dst_entry *dst;
1302
1303 dst = l3mdev_link_scope_lookup(net, fl6);
1304 if (dst)
1305 return dst;
1306 }
David Ahernca254492015-10-12 11:47:10 -07001307
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001308 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001309
David Ahernd46a9d62015-10-21 08:42:22 -07001310 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07001311 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07001312 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001313 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001314
David Ahernd46a9d62015-10-21 08:42:22 -07001315 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07001316 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001317 else if (sk)
1318 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001319
David S. Miller4c9483b2011-03-12 16:22:43 -05001320 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321}
Paolo Abeni6f21c962016-01-29 12:30:19 +01001322EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
David S. Miller2774c132011-03-01 14:59:04 -08001324struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001325{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001326 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07001327 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07001328 struct dst_entry *new = NULL;
1329
Wei Wang1dbe32522017-06-17 10:42:26 -07001330 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Wei Wangb2a9c0e2017-06-17 10:42:41 -07001331 DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001332 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001333 rt6_info_init(rt);
1334
Changli Gaod8d1f302010-06-10 23:31:35 -07001335 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001336 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001337 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001338 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07001339
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001340 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001341
Wei Wang1dbe32522017-06-17 10:42:26 -07001342 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001343 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001344 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07001345 rt->rt6i_metric = 0;
1346
1347 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1348#ifdef CONFIG_IPV6_SUBTREES
1349 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1350#endif
David S. Miller14e50e52007-05-24 18:17:54 -07001351 }
1352
David S. Miller69ead7a2011-03-01 14:45:33 -08001353 dst_release(dst_orig);
1354 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001355}
David S. Miller14e50e52007-05-24 18:17:54 -07001356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357/*
1358 * Destination cache support functions
1359 */
1360
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001361static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1362{
1363 if (rt->dst.from &&
1364 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1365 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1366}
1367
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001368static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1369{
1370 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1371 return NULL;
1372
1373 if (rt6_check_expired(rt))
1374 return NULL;
1375
1376 return &rt->dst;
1377}
1378
1379static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1380{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08001381 if (!__rt6_check_expired(rt) &&
1382 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001383 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1384 return &rt->dst;
1385 else
1386 return NULL;
1387}
1388
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1390{
1391 struct rt6_info *rt;
1392
1393 rt = (struct rt6_info *) dst;
1394
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001395 /* All IPV6 dsts are created with ->obsolete set to the value
1396 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1397 * into this function always.
1398 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001399
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001400 rt6_dst_from_metrics_check(rt);
1401
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08001402 if (rt->rt6i_flags & RTF_PCPU ||
Wei Wanga4c2fd72017-06-17 10:42:42 -07001403 (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001404 return rt6_dst_from_check(rt, cookie);
1405 else
1406 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407}
1408
1409static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1410{
1411 struct rt6_info *rt = (struct rt6_info *) dst;
1412
1413 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001414 if (rt->rt6i_flags & RTF_CACHE) {
1415 if (rt6_check_expired(rt)) {
1416 ip6_del_rt(rt);
1417 dst = NULL;
1418 }
1419 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001421 dst = NULL;
1422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001424 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
1427static void ip6_link_failure(struct sk_buff *skb)
1428{
1429 struct rt6_info *rt;
1430
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001431 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
Eric Dumazetadf30902009-06-02 05:19:30 +00001433 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001435 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07001436 if (dst_hold_safe(&rt->dst))
1437 ip6_del_rt(rt);
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001438 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 }
1442}
1443
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001444static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1445{
1446 struct net *net = dev_net(rt->dst.dev);
1447
1448 rt->rt6i_flags |= RTF_MODIFIED;
1449 rt->rt6i_pmtu = mtu;
1450 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1451}
1452
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001453static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
1454{
1455 return !(rt->rt6i_flags & RTF_CACHE) &&
1456 (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
1457}
1458
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001459static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1460 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Julian Anastasov0dec8792017-02-06 23:14:16 +02001462 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001463 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001465 if (rt6->rt6i_flags & RTF_LOCAL)
1466 return;
1467
Xin Long19bda362016-10-28 18:18:01 +08001468 if (dst_metric_locked(dst, RTAX_MTU))
1469 return;
1470
Julian Anastasov0dec8792017-02-06 23:14:16 +02001471 if (iph) {
1472 daddr = &iph->daddr;
1473 saddr = &iph->saddr;
1474 } else if (sk) {
1475 daddr = &sk->sk_v6_daddr;
1476 saddr = &inet6_sk(sk)->saddr;
1477 } else {
1478 daddr = NULL;
1479 saddr = NULL;
1480 }
1481 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001482 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1483 if (mtu >= dst_mtu(dst))
1484 return;
David S. Miller81aded22012-06-15 14:54:11 -07001485
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001486 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001487 rt6_do_update_pmtu(rt6, mtu);
Julian Anastasov0dec8792017-02-06 23:14:16 +02001488 } else if (daddr) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001489 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001490
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001491 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1492 if (nrt6) {
1493 rt6_do_update_pmtu(nrt6, mtu);
1494
1495 /* ip6_ins_rt(nrt6) will bump the
1496 * rt6->rt6i_node->fn_sernum
1497 * which will fail the next rt6_check() and
1498 * invalidate the sk->sk_dst_cache.
1499 */
1500 ip6_ins_rt(nrt6);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001501 /* Release the reference taken in
1502 * ip6_rt_cache_alloc()
1503 */
1504 dst_release(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 }
1507}
1508
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001509static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1510 struct sk_buff *skb, u32 mtu)
1511{
1512 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1513}
1514
David S. Miller42ae66c2012-06-15 20:01:57 -07001515void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001516 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07001517{
1518 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1519 struct dst_entry *dst;
1520 struct flowi6 fl6;
1521
1522 memset(&fl6, 0, sizeof(fl6));
1523 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001524 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001525 fl6.daddr = iph->daddr;
1526 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001527 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001528 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07001529
1530 dst = ip6_route_output(net, NULL, &fl6);
1531 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001532 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001533 dst_release(dst);
1534}
1535EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1536
1537void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1538{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001539 struct dst_entry *dst;
1540
David S. Miller81aded22012-06-15 14:54:11 -07001541 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001542 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001543
1544 dst = __sk_dst_get(sk);
1545 if (!dst || !dst->obsolete ||
1546 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
1547 return;
1548
1549 bh_lock_sock(sk);
1550 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
1551 ip6_datagram_dst_update(sk, false);
1552 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07001553}
1554EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1555
Duan Jiongb55b76b2013-09-04 19:44:21 +08001556/* Handle redirects */
1557struct ip6rd_flowi {
1558 struct flowi6 fl6;
1559 struct in6_addr gateway;
1560};
1561
1562static struct rt6_info *__ip6_route_redirect(struct net *net,
1563 struct fib6_table *table,
1564 struct flowi6 *fl6,
1565 int flags)
1566{
1567 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1568 struct rt6_info *rt;
1569 struct fib6_node *fn;
1570
1571 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01001572 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08001573 *
1574 * RFC 4861 specifies that redirects should only be
1575 * accepted if they come from the nexthop to the target.
1576 * Due to the way the routes are chosen, this notion
1577 * is a bit fuzzy and one might need to check all possible
1578 * routes.
1579 */
1580
1581 read_lock_bh(&table->tb6_lock);
1582 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1583restart:
1584 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1585 if (rt6_check_expired(rt))
1586 continue;
1587 if (rt->dst.error)
1588 break;
1589 if (!(rt->rt6i_flags & RTF_GATEWAY))
1590 continue;
1591 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1592 continue;
1593 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1594 continue;
1595 break;
1596 }
1597
1598 if (!rt)
1599 rt = net->ipv6.ip6_null_entry;
1600 else if (rt->dst.error) {
1601 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001602 goto out;
1603 }
1604
1605 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001606 fn = fib6_backtrack(fn, &fl6->saddr);
1607 if (fn)
1608 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001609 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001610
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001611out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001612 dst_hold(&rt->dst);
1613
1614 read_unlock_bh(&table->tb6_lock);
1615
David Ahernb8115802015-11-19 12:24:22 -08001616 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Duan Jiongb55b76b2013-09-04 19:44:21 +08001617 return rt;
1618};
1619
1620static struct dst_entry *ip6_route_redirect(struct net *net,
1621 const struct flowi6 *fl6,
1622 const struct in6_addr *gateway)
1623{
1624 int flags = RT6_LOOKUP_F_HAS_SADDR;
1625 struct ip6rd_flowi rdfl;
1626
1627 rdfl.fl6 = *fl6;
1628 rdfl.gateway = *gateway;
1629
1630 return fib6_rule_lookup(net, &rdfl.fl6,
1631 flags, __ip6_route_redirect);
1632}
1633
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001634void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
1635 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001636{
1637 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1638 struct dst_entry *dst;
1639 struct flowi6 fl6;
1640
1641 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001642 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001643 fl6.flowi6_oif = oif;
1644 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001645 fl6.daddr = iph->daddr;
1646 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001647 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001648 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001649
Duan Jiongb55b76b2013-09-04 19:44:21 +08001650 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1651 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001652 dst_release(dst);
1653}
1654EXPORT_SYMBOL_GPL(ip6_redirect);
1655
Duan Jiongc92a59e2013-08-22 12:07:35 +08001656void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1657 u32 mark)
1658{
1659 const struct ipv6hdr *iph = ipv6_hdr(skb);
1660 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1661 struct dst_entry *dst;
1662 struct flowi6 fl6;
1663
1664 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001665 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001666 fl6.flowi6_oif = oif;
1667 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001668 fl6.daddr = msg->dest;
1669 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001670 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001671
Duan Jiongb55b76b2013-09-04 19:44:21 +08001672 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1673 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001674 dst_release(dst);
1675}
1676
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001677void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1678{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001679 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
1680 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001681}
1682EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1683
David S. Miller0dbaee32010-12-13 12:52:14 -08001684static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685{
David S. Miller0dbaee32010-12-13 12:52:14 -08001686 struct net_device *dev = dst->dev;
1687 unsigned int mtu = dst_mtu(dst);
1688 struct net *net = dev_net(dev);
1689
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1691
Daniel Lezcano55786892008-03-04 13:47:47 -08001692 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1693 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
1695 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001696 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1697 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1698 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 * rely only on pmtu discovery"
1700 */
1701 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1702 mtu = IPV6_MAXPLEN;
1703 return mtu;
1704}
1705
Steffen Klassertebb762f2011-11-23 02:12:51 +00001706static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001707{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001708 const struct rt6_info *rt = (const struct rt6_info *)dst;
1709 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001710 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001711
1712 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001713 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001714
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001715 mtu = dst_metric_raw(dst, RTAX_MTU);
1716 if (mtu)
1717 goto out;
1718
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001719 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001720
1721 rcu_read_lock();
1722 idev = __in6_dev_get(dst->dev);
1723 if (idev)
1724 mtu = idev->cnf.mtu6;
1725 rcu_read_unlock();
1726
Eric Dumazet30f78d82014-04-10 21:23:36 -07001727out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07001728 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1729
1730 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08001731}
1732
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001733struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001734 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
David S. Miller87a11572011-12-06 17:04:13 -05001736 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 struct rt6_info *rt;
1738 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001739 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
David S. Miller38308472011-12-03 18:02:47 -05001741 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001742 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Martin KaFai Lauad706862015-08-14 11:05:52 -07001744 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001745 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001747 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 goto out;
1749 }
1750
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001751 rt->dst.flags |= DST_HOST;
1752 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03001753 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001754 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001755 rt->rt6i_dst.plen = 128;
1756 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001757 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
Wei Wang587fea72017-06-17 10:42:36 -07001759 /* Add this dst into uncached_list so that rt6_ifdown() can
1760 * do proper release of the net_device
1761 */
1762 rt6_uncached_list_add(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
David S. Miller87a11572011-12-06 17:04:13 -05001764 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766out:
David S. Miller87a11572011-12-06 17:04:13 -05001767 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768}
1769
Daniel Lezcano569d3642008-01-18 03:56:57 -08001770static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001772 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001773 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1774 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1775 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1776 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1777 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001778 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Eric Dumazetfc66f952010-10-08 06:37:34 +00001780 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001781 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001782 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 goto out;
1784
Benjamin Thery6891a342008-03-04 13:49:47 -08001785 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001786 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001787 entries = dst_entries_get_slow(ops);
1788 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001789 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001791 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001792 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793}
1794
Florian Westphale715b6d2015-01-05 23:57:44 +01001795static int ip6_convert_metrics(struct mx6_config *mxc,
1796 const struct fib6_config *cfg)
1797{
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001798 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01001799 struct nlattr *nla;
1800 int remaining;
1801 u32 *mp;
1802
Ian Morris63159f22015-03-29 14:00:04 +01001803 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001804 return 0;
1805
1806 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1807 if (unlikely(!mp))
1808 return -ENOMEM;
1809
1810 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1811 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001812 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001813
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001814 if (!type)
1815 continue;
1816 if (unlikely(type > RTAX_MAX))
1817 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001818
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001819 if (type == RTAX_CC_ALGO) {
1820 char tmp[TCP_CA_NAME_MAX];
1821
1822 nla_strlcpy(tmp, nla, sizeof(tmp));
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001823 val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001824 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01001825 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001826 } else {
1827 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01001828 }
Paolo Abeni626abd52016-05-13 18:33:41 +02001829 if (type == RTAX_HOPLIMIT && val > 255)
1830 val = 255;
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02001831 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
1832 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001833
1834 mp[type - 1] = val;
1835 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01001836 }
1837
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001838 if (ecn_ca) {
1839 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
1840 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
1841 }
Florian Westphale715b6d2015-01-05 23:57:44 +01001842
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001843 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01001844 return 0;
1845 err:
1846 kfree(mp);
1847 return -EINVAL;
1848}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
David Ahern8c145862016-04-24 21:26:04 -07001850static struct rt6_info *ip6_nh_lookup_table(struct net *net,
1851 struct fib6_config *cfg,
1852 const struct in6_addr *gw_addr)
1853{
1854 struct flowi6 fl6 = {
1855 .flowi6_oif = cfg->fc_ifindex,
1856 .daddr = *gw_addr,
1857 .saddr = cfg->fc_prefsrc,
1858 };
1859 struct fib6_table *table;
1860 struct rt6_info *rt;
David Ahernd5d32e42016-10-24 12:27:23 -07001861 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahern8c145862016-04-24 21:26:04 -07001862
1863 table = fib6_get_table(net, cfg->fc_table);
1864 if (!table)
1865 return NULL;
1866
1867 if (!ipv6_addr_any(&cfg->fc_prefsrc))
1868 flags |= RT6_LOOKUP_F_HAS_SADDR;
1869
1870 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
1871
1872 /* if table lookup failed, fall back to full lookup */
1873 if (rt == net->ipv6.ip6_null_entry) {
1874 ip6_rt_put(rt);
1875 rt = NULL;
1876 }
1877
1878 return rt;
1879}
1880
David Ahern333c4302017-05-21 10:12:04 -06001881static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
1882 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883{
Daniel Lezcano55786892008-03-04 13:47:47 -08001884 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 struct rt6_info *rt = NULL;
1886 struct net_device *dev = NULL;
1887 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001888 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001890 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
David Ahern557c44b2017-04-19 14:19:43 -07001892 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06001893 if (cfg->fc_flags & RTF_PCPU) {
1894 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07001895 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001896 }
David Ahern557c44b2017-04-19 14:19:43 -07001897
David Ahernd5d531c2017-05-21 10:12:05 -06001898 if (cfg->fc_dst_len > 128) {
1899 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001900 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001901 }
1902 if (cfg->fc_src_len > 128) {
1903 NL_SET_ERR_MSG(extack, "Invalid source address length");
1904 goto out;
1905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06001907 if (cfg->fc_src_len) {
1908 NL_SET_ERR_MSG(extack,
1909 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001910 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001913 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001915 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (!dev)
1917 goto out;
1918 idev = in6_dev_get(dev);
1919 if (!idev)
1920 goto out;
1921 }
1922
Thomas Graf86872cb2006-08-22 00:01:08 -07001923 if (cfg->fc_metric == 0)
1924 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
Matti Vaittinend71314b2011-11-14 00:14:49 +00001926 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001927 if (cfg->fc_nlinfo.nlh &&
1928 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001929 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001930 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001931 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001932 table = fib6_new_table(net, cfg->fc_table);
1933 }
1934 } else {
1935 table = fib6_new_table(net, cfg->fc_table);
1936 }
David S. Miller38308472011-12-03 18:02:47 -05001937
1938 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001939 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001940
Martin KaFai Lauad706862015-08-14 11:05:52 -07001941 rt = ip6_dst_alloc(net, NULL,
1942 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
David S. Miller38308472011-12-03 18:02:47 -05001944 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 err = -ENOMEM;
1946 goto out;
1947 }
1948
Gao feng1716a962012-04-06 00:13:10 +00001949 if (cfg->fc_flags & RTF_EXPIRES)
1950 rt6_set_expires(rt, jiffies +
1951 clock_t_to_jiffies(cfg->fc_expires));
1952 else
1953 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954
Thomas Graf86872cb2006-08-22 00:01:08 -07001955 if (cfg->fc_protocol == RTPROT_UNSPEC)
1956 cfg->fc_protocol = RTPROT_BOOT;
1957 rt->rt6i_protocol = cfg->fc_protocol;
1958
1959 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
1961 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001962 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001963 else if (cfg->fc_flags & RTF_LOCAL)
1964 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001966 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Changli Gaod8d1f302010-06-10 23:31:35 -07001968 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001970 if (cfg->fc_encap) {
1971 struct lwtunnel_state *lwtstate;
1972
David Ahern30357d72017-01-30 12:07:37 -08001973 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07001974 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06001975 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001976 if (err)
1977 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02001978 rt->dst.lwtstate = lwtstate_get(lwtstate);
1979 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
1980 rt->dst.lwtstate->orig_output = rt->dst.output;
1981 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07001982 }
Jiri Benc61adedf2015-08-20 13:56:25 +02001983 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
1984 rt->dst.lwtstate->orig_input = rt->dst.input;
1985 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07001986 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001987 }
1988
Thomas Graf86872cb2006-08-22 00:01:08 -07001989 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1990 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001991 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001992 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001993
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001995 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1996 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997#endif
1998
Thomas Graf86872cb2006-08-22 00:01:08 -07001999 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
2001 /* We cannot add true routes via loopback here,
2002 they would result in kernel looping; promote them to reject routes
2003 */
Thomas Graf86872cb2006-08-22 00:01:08 -07002004 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05002005 (dev && (dev->flags & IFF_LOOPBACK) &&
2006 !(addr_type & IPV6_ADDR_LOOPBACK) &&
2007 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08002009 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (dev) {
2011 dev_put(dev);
2012 in6_dev_put(idev);
2013 }
Daniel Lezcano55786892008-03-04 13:47:47 -08002014 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 dev_hold(dev);
2016 idev = in6_dev_get(dev);
2017 if (!idev) {
2018 err = -ENODEV;
2019 goto out;
2020 }
2021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002023 switch (cfg->fc_type) {
2024 case RTN_BLACKHOLE:
2025 rt->dst.error = -EINVAL;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002026 rt->dst.output = dst_discard_out;
Kamala R7150aed2013-12-02 19:55:21 +05302027 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002028 break;
2029 case RTN_PROHIBIT:
2030 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05302031 rt->dst.output = ip6_pkt_prohibit_out;
2032 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002033 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002034 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02002035 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002036 default:
Kamala R7150aed2013-12-02 19:55:21 +05302037 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02002038 : (cfg->fc_type == RTN_UNREACHABLE)
2039 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05302040 rt->dst.output = ip6_pkt_discard_out;
2041 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002042 break;
2043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 goto install_route;
2045 }
2046
Thomas Graf86872cb2006-08-22 00:01:08 -07002047 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002048 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 int gwa_type;
2050
Thomas Graf86872cb2006-08-22 00:01:08 -07002051 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02002052 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02002053
2054 /* if gw_addr is local we will fail to detect this in case
2055 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2056 * will return already-added prefix route via interface that
2057 * prefix route was assigned to, which might be non-loopback.
2058 */
2059 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02002060 if (ipv6_chk_addr_and_flags(net, gw_addr,
2061 gwa_type & IPV6_ADDR_LINKLOCAL ?
David Ahernd5d531c2017-05-21 10:12:05 -06002062 dev : NULL, 0, 0)) {
2063 NL_SET_ERR_MSG(extack, "Invalid gateway address");
Florian Westphal48ed7b22015-05-21 00:25:41 +02002064 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002065 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002066 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
2068 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
David Ahern8c145862016-04-24 21:26:04 -07002069 struct rt6_info *grt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
2071 /* IPv6 strictly inhibits using not link-local
2072 addresses as nexthop address.
2073 Otherwise, router will not able to send redirects.
2074 It is very good, but in some (rare!) circumstances
2075 (SIT, PtP, NBMA NOARP links) it is handy to allow
2076 some exceptions. --ANK
Erik Nordmark96d58222016-12-03 20:57:09 -08002077 We allow IPv4-mapped nexthops to support RFC4798-type
2078 addressing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 */
Erik Nordmark96d58222016-12-03 20:57:09 -08002080 if (!(gwa_type & (IPV6_ADDR_UNICAST |
David Ahernd5d531c2017-05-21 10:12:05 -06002081 IPV6_ADDR_MAPPED))) {
2082 NL_SET_ERR_MSG(extack,
2083 "Invalid gateway address");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Vincent Bernata435a072016-09-18 17:46:07 +02002087 if (cfg->fc_table) {
David Ahern8c145862016-04-24 21:26:04 -07002088 grt = ip6_nh_lookup_table(net, cfg, gw_addr);
2089
Vincent Bernata435a072016-09-18 17:46:07 +02002090 if (grt) {
2091 if (grt->rt6i_flags & RTF_GATEWAY ||
2092 (dev && dev != grt->dst.dev)) {
2093 ip6_rt_put(grt);
2094 grt = NULL;
2095 }
2096 }
2097 }
2098
David Ahern8c145862016-04-24 21:26:04 -07002099 if (!grt)
2100 grt = rt6_lookup(net, gw_addr, NULL,
2101 cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
2103 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05002104 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 goto out;
2106 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05002107 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002108 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 goto out;
2110 }
2111 } else {
David S. Millerd1918542011-12-28 20:19:20 -05002112 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 idev = grt->rt6i_idev;
2114 dev_hold(dev);
2115 in6_dev_hold(grt->rt6i_idev);
2116 }
David S. Miller38308472011-12-03 18:02:47 -05002117 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00002119 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
2121 if (err)
2122 goto out;
2123 }
2124 err = -EINVAL;
David Ahernd5d531c2017-05-21 10:12:05 -06002125 if (!dev) {
2126 NL_SET_ERR_MSG(extack, "Egress device not specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002128 } else if (dev->flags & IFF_LOOPBACK) {
2129 NL_SET_ERR_MSG(extack,
2130 "Egress device can not be loopback device for this route");
2131 goto out;
2132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 }
2134
2135 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002136 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 goto out;
2138
Daniel Walterc3968a82011-04-13 21:10:57 +00002139 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2140 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06002141 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00002142 err = -EINVAL;
2143 goto out;
2144 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002145 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00002146 rt->rt6i_prefsrc.plen = 128;
2147 } else
2148 rt->rt6i_prefsrc.plen = 0;
2149
Thomas Graf86872cb2006-08-22 00:01:08 -07002150 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151
2152install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07002153 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07002155 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002156
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002157 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002158
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002159 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160out:
2161 if (dev)
2162 dev_put(dev);
2163 if (idev)
2164 in6_dev_put(idev);
Wei Wang587fea72017-06-17 10:42:36 -07002165 if (rt)
2166 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002167
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002168 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002169}
2170
David Ahern333c4302017-05-21 10:12:04 -06002171int ip6_route_add(struct fib6_config *cfg,
2172 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002173{
2174 struct mx6_config mxc = { .mx = NULL, };
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002175 struct rt6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002176 int err;
2177
David Ahern333c4302017-05-21 10:12:04 -06002178 rt = ip6_route_info_create(cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002179 if (IS_ERR(rt)) {
2180 err = PTR_ERR(rt);
2181 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002182 goto out;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002183 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002184
2185 err = ip6_convert_metrics(&mxc, cfg);
2186 if (err)
2187 goto out;
2188
David Ahern333c4302017-05-21 10:12:04 -06002189 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002190
2191 kfree(mxc.mx);
2192
2193 return err;
2194out:
Wei Wang587fea72017-06-17 10:42:36 -07002195 if (rt)
2196 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 return err;
2199}
2200
Thomas Graf86872cb2006-08-22 00:01:08 -07002201static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202{
2203 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002204 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002205 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Wei Wanga4c2fd72017-06-17 10:42:42 -07002207 if (rt == net->ipv6.ip6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00002208 err = -ENOENT;
2209 goto out;
2210 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002211
Thomas Grafc71099a2006-08-04 23:20:06 -07002212 table = rt->rt6i_table;
2213 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002214 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07002215 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
Gao feng6825a262012-09-19 19:25:34 +00002217out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002218 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return err;
2220}
2221
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002222int ip6_del_rt(struct rt6_info *rt)
2223{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002224 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002225 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002226 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002227 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002228}
2229
David Ahern0ae81332017-02-02 12:37:08 -08002230static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
2231{
2232 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08002233 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08002234 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08002235 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08002236 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08002237
WANG Conge3330032017-02-27 16:07:43 -08002238 if (rt == net->ipv6.ip6_null_entry)
2239 goto out_put;
David Ahern0ae81332017-02-02 12:37:08 -08002240 table = rt->rt6i_table;
2241 write_lock_bh(&table->tb6_lock);
2242
2243 if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
2244 struct rt6_info *sibling, *next_sibling;
2245
David Ahern16a16cd2017-02-02 12:37:11 -08002246 /* prefer to send a single notification with all hops */
2247 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
2248 if (skb) {
2249 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
2250
WANG Conge3330032017-02-27 16:07:43 -08002251 if (rt6_fill_node(net, skb, rt,
David Ahern16a16cd2017-02-02 12:37:11 -08002252 NULL, NULL, 0, RTM_DELROUTE,
2253 info->portid, seq, 0) < 0) {
2254 kfree_skb(skb);
2255 skb = NULL;
2256 } else
2257 info->skip_notify = 1;
2258 }
2259
David Ahern0ae81332017-02-02 12:37:08 -08002260 list_for_each_entry_safe(sibling, next_sibling,
2261 &rt->rt6i_siblings,
2262 rt6i_siblings) {
2263 err = fib6_del(sibling, info);
2264 if (err)
WANG Conge3330032017-02-27 16:07:43 -08002265 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08002266 }
2267 }
2268
2269 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08002270out_unlock:
David Ahern0ae81332017-02-02 12:37:08 -08002271 write_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08002272out_put:
David Ahern0ae81332017-02-02 12:37:08 -08002273 ip6_rt_put(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08002274
2275 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08002276 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08002277 info->nlh, gfp_any());
2278 }
David Ahern0ae81332017-02-02 12:37:08 -08002279 return err;
2280}
2281
David Ahern333c4302017-05-21 10:12:04 -06002282static int ip6_route_del(struct fib6_config *cfg,
2283 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
Thomas Grafc71099a2006-08-04 23:20:06 -07002285 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 struct fib6_node *fn;
2287 struct rt6_info *rt;
2288 int err = -ESRCH;
2289
Daniel Lezcano55786892008-03-04 13:47:47 -08002290 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06002291 if (!table) {
2292 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07002293 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06002294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
Thomas Grafc71099a2006-08-04 23:20:06 -07002296 read_lock_bh(&table->tb6_lock);
2297
2298 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002299 &cfg->fc_dst, cfg->fc_dst_len,
2300 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002301
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002303 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002304 if ((rt->rt6i_flags & RTF_CACHE) &&
2305 !(cfg->fc_flags & RTF_CACHE))
2306 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002307 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002308 (!rt->dst.dev ||
2309 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002311 if (cfg->fc_flags & RTF_GATEWAY &&
2312 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002314 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 continue;
Mantas Mc2ed1882016-12-16 10:30:59 +02002316 if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
2317 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002318 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002319 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
David Ahern0ae81332017-02-02 12:37:08 -08002321 /* if gateway was specified only delete the one hop */
2322 if (cfg->fc_flags & RTF_GATEWAY)
2323 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
2324
2325 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 }
2327 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002328 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
2330 return err;
2331}
2332
David S. Miller6700c272012-07-17 03:29:28 -07002333static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002334{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002335 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002336 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002337 struct ndisc_options ndopts;
2338 struct inet6_dev *in6_dev;
2339 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002340 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002341 int optlen, on_link;
2342 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002343
Simon Horman29a3cad2013-05-28 20:34:26 +00002344 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002345 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002346
2347 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002348 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002349 return;
2350 }
2351
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002352 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002353
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002354 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002355 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002356 return;
2357 }
2358
David S. Miller6e157b62012-07-12 00:05:02 -07002359 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002360 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002361 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002362 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002363 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002364 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002365 return;
2366 }
2367
2368 in6_dev = __in6_dev_get(skb->dev);
2369 if (!in6_dev)
2370 return;
2371 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2372 return;
2373
2374 /* RFC2461 8.1:
2375 * The IP source address of the Redirect MUST be the same as the current
2376 * first-hop router for the specified ICMP Destination Address.
2377 */
2378
Alexander Aringf997c552016-06-15 21:20:23 +02002379 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002380 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2381 return;
2382 }
David S. Miller6e157b62012-07-12 00:05:02 -07002383
2384 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002385 if (ndopts.nd_opts_tgt_lladdr) {
2386 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2387 skb->dev);
2388 if (!lladdr) {
2389 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2390 return;
2391 }
2392 }
2393
David S. Miller6e157b62012-07-12 00:05:02 -07002394 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01002395 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07002396 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2397 return;
2398 }
2399
2400 /* Redirect received -> path was valid.
2401 * Look, redirects are sent only in response to data packets,
2402 * so that this nexthop apparently is reachable. --ANK
2403 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02002404 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07002405
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002406 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002407 if (!neigh)
2408 return;
2409
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 /*
2411 * We have finally decided to accept it.
2412 */
2413
Alexander Aringf997c552016-06-15 21:20:23 +02002414 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2416 NEIGH_UPDATE_F_OVERRIDE|
2417 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02002418 NEIGH_UPDATE_F_ISROUTER)),
2419 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002421 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002422 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 goto out;
2424
2425 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2426 if (on_link)
2427 nrt->rt6i_flags &= ~RTF_GATEWAY;
2428
Xin Longb91d5322017-08-03 14:13:46 +08002429 nrt->rt6i_protocol = RTPROT_REDIRECT;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002430 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
Thomas Graf40e22e82006-08-22 00:00:45 -07002432 if (ip6_ins_rt(nrt))
Wei Wang1cfb71e2017-06-17 10:42:33 -07002433 goto out_release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Changli Gaod8d1f302010-06-10 23:31:35 -07002435 netevent.old = &rt->dst;
2436 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002437 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002438 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002439 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2440
David S. Miller38308472011-12-03 18:02:47 -05002441 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002442 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002443 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 }
2445
Wei Wang1cfb71e2017-06-17 10:42:33 -07002446out_release:
2447 /* Release the reference taken in
2448 * ip6_rt_cache_alloc()
2449 */
2450 dst_release(&nrt->dst);
2451
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452out:
David S. Millere8599ff2012-07-11 23:43:53 -07002453 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002454}
2455
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 * Misc support functions
2458 */
2459
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002460static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2461{
2462 BUG_ON(from->dst.from);
2463
2464 rt->rt6i_flags &= ~RTF_EXPIRES;
2465 dst_hold(&from->dst);
2466 rt->dst.from = &from->dst;
2467 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2468}
2469
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002470static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002472 rt->dst.input = ort->dst.input;
2473 rt->dst.output = ort->dst.output;
2474 rt->rt6i_dst = ort->rt6i_dst;
2475 rt->dst.error = ort->dst.error;
2476 rt->rt6i_idev = ort->rt6i_idev;
2477 if (rt->rt6i_idev)
2478 in6_dev_hold(rt->rt6i_idev);
2479 rt->dst.lastuse = jiffies;
2480 rt->rt6i_gateway = ort->rt6i_gateway;
2481 rt->rt6i_flags = ort->rt6i_flags;
2482 rt6_set_from(rt, ort);
2483 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002485 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002487 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2488 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02002489 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490}
2491
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002492#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002493static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002494 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002495 const struct in6_addr *gwaddr,
2496 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002497{
David Ahern830218c2016-10-24 10:52:35 -07002498 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
2499 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002500 struct fib6_node *fn;
2501 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002502 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002503
David Ahern830218c2016-10-24 10:52:35 -07002504 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002505 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002506 return NULL;
2507
Li RongQing5744dd92012-09-11 21:59:01 +00002508 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002509 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002510 if (!fn)
2511 goto out;
2512
Changli Gaod8d1f302010-06-10 23:31:35 -07002513 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002514 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002515 continue;
2516 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2517 continue;
2518 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2519 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002520 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002521 break;
2522 }
2523out:
Li RongQing5744dd92012-09-11 21:59:01 +00002524 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002525 return rt;
2526}
2527
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002528static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002529 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002530 const struct in6_addr *gwaddr,
2531 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00002532 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002533{
Thomas Graf86872cb2006-08-22 00:01:08 -07002534 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08002535 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07002536 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07002537 .fc_dst_len = prefixlen,
2538 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2539 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08002540 .fc_protocol = RTPROT_RA,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002541 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002542 .fc_nlinfo.nlh = NULL,
2543 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002544 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002545
David Ahern830218c2016-10-24 10:52:35 -07002546 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002547 cfg.fc_dst = *prefix;
2548 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002549
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002550 /* We should treat it as a default route if prefix length is 0. */
2551 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002552 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002553
David Ahern333c4302017-05-21 10:12:04 -06002554 ip6_route_add(&cfg, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002555
David Ahern830218c2016-10-24 10:52:35 -07002556 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002557}
2558#endif
2559
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002560struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002561{
David Ahern830218c2016-10-24 10:52:35 -07002562 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002564 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
David Ahern830218c2016-10-24 10:52:35 -07002566 table = fib6_get_table(dev_net(dev), tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002567 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002568 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
Li RongQing5744dd92012-09-11 21:59:01 +00002570 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002571 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002572 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002573 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2575 break;
2576 }
2577 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002578 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002579 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 return rt;
2581}
2582
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002583struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002584 struct net_device *dev,
2585 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586{
Thomas Graf86872cb2006-08-22 00:01:08 -07002587 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07002588 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002589 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002590 .fc_ifindex = dev->ifindex,
2591 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2592 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08002593 .fc_protocol = RTPROT_RA,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002594 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002595 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002596 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002597 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002599 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
David Ahern333c4302017-05-21 10:12:04 -06002601 if (!ip6_route_add(&cfg, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07002602 struct fib6_table *table;
2603
2604 table = fib6_get_table(dev_net(dev), cfg.fc_table);
2605 if (table)
2606 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
2607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 return rt6_get_dflt_router(gwaddr, dev);
2610}
2611
David Ahern830218c2016-10-24 10:52:35 -07002612static void __rt6_purge_dflt_routers(struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613{
2614 struct rt6_info *rt;
2615
2616restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002617 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002618 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002619 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2620 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002621 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002622 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002623 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 goto restart;
2625 }
2626 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002627 read_unlock_bh(&table->tb6_lock);
David Ahern830218c2016-10-24 10:52:35 -07002628
2629 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
2630}
2631
2632void rt6_purge_dflt_routers(struct net *net)
2633{
2634 struct fib6_table *table;
2635 struct hlist_head *head;
2636 unsigned int h;
2637
2638 rcu_read_lock();
2639
2640 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
2641 head = &net->ipv6.fib_table_hash[h];
2642 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
2643 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
2644 __rt6_purge_dflt_routers(table);
2645 }
2646 }
2647
2648 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649}
2650
Daniel Lezcano55786892008-03-04 13:47:47 -08002651static void rtmsg_to_fib6_config(struct net *net,
2652 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002653 struct fib6_config *cfg)
2654{
2655 memset(cfg, 0, sizeof(*cfg));
2656
David Ahernca254492015-10-12 11:47:10 -07002657 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
2658 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07002659 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2660 cfg->fc_metric = rtmsg->rtmsg_metric;
2661 cfg->fc_expires = rtmsg->rtmsg_info;
2662 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2663 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2664 cfg->fc_flags = rtmsg->rtmsg_flags;
2665
Daniel Lezcano55786892008-03-04 13:47:47 -08002666 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002667
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002668 cfg->fc_dst = rtmsg->rtmsg_dst;
2669 cfg->fc_src = rtmsg->rtmsg_src;
2670 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002671}
2672
Daniel Lezcano55786892008-03-04 13:47:47 -08002673int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674{
Thomas Graf86872cb2006-08-22 00:01:08 -07002675 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 struct in6_rtmsg rtmsg;
2677 int err;
2678
Ian Morris67ba4152014-08-24 21:53:10 +01002679 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 case SIOCADDRT: /* Add a route */
2681 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002682 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 return -EPERM;
2684 err = copy_from_user(&rtmsg, arg,
2685 sizeof(struct in6_rtmsg));
2686 if (err)
2687 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002688
Daniel Lezcano55786892008-03-04 13:47:47 -08002689 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 rtnl_lock();
2692 switch (cmd) {
2693 case SIOCADDRT:
David Ahern333c4302017-05-21 10:12:04 -06002694 err = ip6_route_add(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 break;
2696 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06002697 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 break;
2699 default:
2700 err = -EINVAL;
2701 }
2702 rtnl_unlock();
2703
2704 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
2707 return -EINVAL;
2708}
2709
2710/*
2711 * Drop the packet on the floor
2712 */
2713
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002714static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002716 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002717 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002718 switch (ipstats_mib_noroutes) {
2719 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002720 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002721 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002722 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2723 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002724 break;
2725 }
2726 /* FALLTHROUGH */
2727 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002728 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2729 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002730 break;
2731 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002732 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 kfree_skb(skb);
2734 return 0;
2735}
2736
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002737static int ip6_pkt_discard(struct sk_buff *skb)
2738{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002739 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002740}
2741
Eric W. Biedermanede20592015-10-07 16:48:47 -05002742static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743{
Eric Dumazetadf30902009-06-02 05:19:30 +00002744 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002745 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746}
2747
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002748static int ip6_pkt_prohibit(struct sk_buff *skb)
2749{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002750 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002751}
2752
Eric W. Biedermanede20592015-10-07 16:48:47 -05002753static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002754{
Eric Dumazetadf30902009-06-02 05:19:30 +00002755 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002756 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002757}
2758
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759/*
2760 * Allocate a dst for local (unicast / anycast) address.
2761 */
2762
2763struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2764 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002765 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766{
David Ahernca254492015-10-12 11:47:10 -07002767 u32 tb_id;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002768 struct net *net = dev_net(idev->dev);
David Ahern4832c302017-08-17 12:17:20 -07002769 struct net_device *dev = idev->dev;
David Ahern5f02ce242016-09-10 12:09:54 -07002770 struct rt6_info *rt;
2771
David Ahern5f02ce242016-09-10 12:09:54 -07002772 rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002773 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return ERR_PTR(-ENOMEM);
2775
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 in6_dev_hold(idev);
2777
David S. Miller11d53b42011-06-24 15:23:34 -07002778 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002779 rt->dst.input = ip6_input;
2780 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
David Ahern94b5e0f2017-02-02 08:52:21 -08002783 rt->rt6i_protocol = RTPROT_KERNEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002785 if (anycast)
2786 rt->rt6i_flags |= RTF_ANYCAST;
2787 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Julian Anastasov550bab42013-10-20 15:43:04 +03002790 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002791 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 rt->rt6i_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07002793 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
2794 rt->rt6i_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 return rt;
2797}
2798
Daniel Walterc3968a82011-04-13 21:10:57 +00002799/* remove deleted ip from prefsrc entries */
2800struct arg_dev_net_ip {
2801 struct net_device *dev;
2802 struct net *net;
2803 struct in6_addr *addr;
2804};
2805
2806static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2807{
2808 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2809 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2810 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2811
David S. Millerd1918542011-12-28 20:19:20 -05002812 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002813 rt != net->ipv6.ip6_null_entry &&
2814 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2815 /* remove prefsrc entry */
2816 rt->rt6i_prefsrc.plen = 0;
2817 }
2818 return 0;
2819}
2820
2821void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2822{
2823 struct net *net = dev_net(ifp->idev->dev);
2824 struct arg_dev_net_ip adni = {
2825 .dev = ifp->idev->dev,
2826 .net = net,
2827 .addr = &ifp->addr,
2828 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002829 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002830}
2831
Duan Jiongbe7a0102014-05-15 15:56:14 +08002832#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2833#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2834
2835/* Remove routers and update dst entries when gateway turn into host. */
2836static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2837{
2838 struct in6_addr *gateway = (struct in6_addr *)arg;
2839
2840 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2841 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2842 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2843 return -1;
2844 }
2845 return 0;
2846}
2847
2848void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2849{
2850 fib6_clean_all(net, fib6_clean_tohost, gateway);
2851}
2852
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002853struct arg_dev_net {
2854 struct net_device *dev;
2855 struct net *net;
2856};
2857
David Aherna1a22c12017-01-18 07:40:36 -08002858/* called with write lock held for table with rt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859static int fib6_ifdown(struct rt6_info *rt, void *arg)
2860{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002861 const struct arg_dev_net *adn = arg;
2862 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002863
David S. Millerd1918542011-12-28 20:19:20 -05002864 if ((rt->dst.dev == dev || !dev) &&
David Aherna1a22c12017-01-18 07:40:36 -08002865 rt != adn->net->ipv6.ip6_null_entry &&
2866 (rt->rt6i_nsiblings == 0 ||
David Ahern8397ed32017-06-07 12:26:23 -06002867 (dev && netdev_unregistering(dev)) ||
David Aherna1a22c12017-01-18 07:40:36 -08002868 !rt->rt6i_idev->cnf.ignore_routes_with_linkdown))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002870
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 return 0;
2872}
2873
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002874void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002876 struct arg_dev_net adn = {
2877 .dev = dev,
2878 .net = net,
2879 };
2880
Li RongQing0c3584d2013-12-27 16:32:38 +08002881 fib6_clean_all(net, fib6_ifdown, &adn);
Eric W. Biedermane332bc62015-10-12 11:02:08 -05002882 if (dev)
2883 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884}
2885
Eric Dumazet95c96172012-04-15 05:58:06 +00002886struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002888 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889};
2890
2891static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2892{
2893 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2894 struct inet6_dev *idev;
2895
2896 /* In IPv6 pmtu discovery is not optional,
2897 so that RTAX_MTU lock cannot disable it.
2898 We still use this lock to block changes
2899 caused by addrconf/ndisc.
2900 */
2901
2902 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002903 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 return 0;
2905
2906 /* For administrative MTU increase, there is no way to discover
2907 IPv6 PMTU increase, so PMTU increase should be updated here.
2908 Since RFC 1981 doesn't include administrative MTU increase
2909 update PMTU increase is a MUST. (i.e. jumbo frame)
2910 */
2911 /*
2912 If new MTU is less than route PMTU, this new MTU will be the
2913 lowest MTU in the path, update the route PMTU to reflect PMTU
2914 decreases; if new MTU is greater than route PMTU, and the
2915 old MTU is the lowest MTU in the path, update the route PMTU
2916 to reflect the increase. In this case if the other nodes' MTU
2917 also have the lowest MTU, TOO BIG MESSAGE will be lead to
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002918 PMTU discovery.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 */
David S. Millerd1918542011-12-28 20:19:20 -05002920 if (rt->dst.dev == arg->dev &&
Maciej Żenczykowskifb56be82016-11-04 14:51:54 -07002921 dst_metric_raw(&rt->dst, RTAX_MTU) &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002922 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2923 if (rt->rt6i_flags & RTF_CACHE) {
2924 /* For RTF_CACHE with rt6i_pmtu == 0
2925 * (i.e. a redirected route),
2926 * the metrics of its rt->dst.from has already
2927 * been updated.
2928 */
2929 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2930 rt->rt6i_pmtu = arg->mtu;
2931 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2932 (dst_mtu(&rt->dst) < arg->mtu &&
2933 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2934 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2935 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 return 0;
2938}
2939
Eric Dumazet95c96172012-04-15 05:58:06 +00002940void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941{
Thomas Grafc71099a2006-08-04 23:20:06 -07002942 struct rt6_mtu_change_arg arg = {
2943 .dev = dev,
2944 .mtu = mtu,
2945 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
Li RongQing0c3584d2013-12-27 16:32:38 +08002947 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948}
2949
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002950static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002951 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002952 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002953 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002954 [RTA_PRIORITY] = { .type = NLA_U32 },
2955 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002956 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002957 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002958 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2959 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08002960 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09002961 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08002962 [RTA_MARK] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002963};
2964
2965static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06002966 struct fib6_config *cfg,
2967 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
Thomas Graf86872cb2006-08-22 00:01:08 -07002969 struct rtmsg *rtm;
2970 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002971 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002972 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Johannes Bergfceb6432017-04-12 14:34:07 +02002974 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
2975 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07002976 if (err < 0)
2977 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
Thomas Graf86872cb2006-08-22 00:01:08 -07002979 err = -EINVAL;
2980 rtm = nlmsg_data(nlh);
2981 memset(cfg, 0, sizeof(*cfg));
2982
2983 cfg->fc_table = rtm->rtm_table;
2984 cfg->fc_dst_len = rtm->rtm_dst_len;
2985 cfg->fc_src_len = rtm->rtm_src_len;
2986 cfg->fc_flags = RTF_UP;
2987 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002988 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002989
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002990 if (rtm->rtm_type == RTN_UNREACHABLE ||
2991 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002992 rtm->rtm_type == RTN_PROHIBIT ||
2993 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002994 cfg->fc_flags |= RTF_REJECT;
2995
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002996 if (rtm->rtm_type == RTN_LOCAL)
2997 cfg->fc_flags |= RTF_LOCAL;
2998
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002999 if (rtm->rtm_flags & RTM_F_CLONED)
3000 cfg->fc_flags |= RTF_CACHE;
3001
Eric W. Biederman15e47302012-09-07 20:12:54 +00003002 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07003003 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003004 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07003005
3006 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003007 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07003008 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003010
3011 if (tb[RTA_DST]) {
3012 int plen = (rtm->rtm_dst_len + 7) >> 3;
3013
3014 if (nla_len(tb[RTA_DST]) < plen)
3015 goto errout;
3016
3017 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003019
3020 if (tb[RTA_SRC]) {
3021 int plen = (rtm->rtm_src_len + 7) >> 3;
3022
3023 if (nla_len(tb[RTA_SRC]) < plen)
3024 goto errout;
3025
3026 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003028
Daniel Walterc3968a82011-04-13 21:10:57 +00003029 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02003030 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00003031
Thomas Graf86872cb2006-08-22 00:01:08 -07003032 if (tb[RTA_OIF])
3033 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
3034
3035 if (tb[RTA_PRIORITY])
3036 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
3037
3038 if (tb[RTA_METRICS]) {
3039 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
3040 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003042
3043 if (tb[RTA_TABLE])
3044 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
3045
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003046 if (tb[RTA_MULTIPATH]) {
3047 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
3048 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08003049
3050 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06003051 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003052 if (err < 0)
3053 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003054 }
3055
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003056 if (tb[RTA_PREF]) {
3057 pref = nla_get_u8(tb[RTA_PREF]);
3058 if (pref != ICMPV6_ROUTER_PREF_LOW &&
3059 pref != ICMPV6_ROUTER_PREF_HIGH)
3060 pref = ICMPV6_ROUTER_PREF_MEDIUM;
3061 cfg->fc_flags |= RTF_PREF(pref);
3062 }
3063
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003064 if (tb[RTA_ENCAP])
3065 cfg->fc_encap = tb[RTA_ENCAP];
3066
David Ahern9ed59592017-01-17 14:57:36 -08003067 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003068 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
3069
David Ahernc255bd62017-05-27 16:19:27 -06003070 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003071 if (err < 0)
3072 goto errout;
3073 }
3074
Xin Long32bc2012015-12-16 17:50:11 +08003075 if (tb[RTA_EXPIRES]) {
3076 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
3077
3078 if (addrconf_finite_timeout(timeout)) {
3079 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
3080 cfg->fc_flags |= RTF_EXPIRES;
3081 }
3082 }
3083
Thomas Graf86872cb2006-08-22 00:01:08 -07003084 err = 0;
3085errout:
3086 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087}
3088
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003089struct rt6_nh {
3090 struct rt6_info *rt6_info;
3091 struct fib6_config r_cfg;
3092 struct mx6_config mxc;
3093 struct list_head next;
3094};
3095
3096static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
3097{
3098 struct rt6_nh *nh;
3099
3100 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08003101 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 -07003102 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
3103 nh->r_cfg.fc_ifindex);
3104 }
3105}
3106
3107static int ip6_route_info_append(struct list_head *rt6_nh_list,
3108 struct rt6_info *rt, struct fib6_config *r_cfg)
3109{
3110 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003111 int err = -EEXIST;
3112
3113 list_for_each_entry(nh, rt6_nh_list, next) {
3114 /* check if rt6_info already exists */
David Ahernf06b7542017-07-05 14:41:46 -06003115 if (rt6_duplicate_nexthop(nh->rt6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003116 return err;
3117 }
3118
3119 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
3120 if (!nh)
3121 return -ENOMEM;
3122 nh->rt6_info = rt;
3123 err = ip6_convert_metrics(&nh->mxc, r_cfg);
3124 if (err) {
3125 kfree(nh);
3126 return err;
3127 }
3128 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
3129 list_add_tail(&nh->next, rt6_nh_list);
3130
3131 return 0;
3132}
3133
David Ahern3b1137f2017-02-02 12:37:10 -08003134static void ip6_route_mpath_notify(struct rt6_info *rt,
3135 struct rt6_info *rt_last,
3136 struct nl_info *info,
3137 __u16 nlflags)
3138{
3139 /* if this is an APPEND route, then rt points to the first route
3140 * inserted and rt_last points to last route inserted. Userspace
3141 * wants a consistent dump of the route which starts at the first
3142 * nexthop. Since sibling routes are always added at the end of
3143 * the list, find the first sibling of the last route appended
3144 */
3145 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
3146 rt = list_first_entry(&rt_last->rt6i_siblings,
3147 struct rt6_info,
3148 rt6i_siblings);
3149 }
3150
3151 if (rt)
3152 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
3153}
3154
David Ahern333c4302017-05-21 10:12:04 -06003155static int ip6_route_multipath_add(struct fib6_config *cfg,
3156 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003157{
David Ahern3b1137f2017-02-02 12:37:10 -08003158 struct rt6_info *rt_notif = NULL, *rt_last = NULL;
3159 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003160 struct fib6_config r_cfg;
3161 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003162 struct rt6_info *rt;
3163 struct rt6_nh *err_nh;
3164 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08003165 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003166 int remaining;
3167 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003168 int err = 1;
3169 int nhn = 0;
3170 int replace = (cfg->fc_nlinfo.nlh &&
3171 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
3172 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003173
David Ahern3b1137f2017-02-02 12:37:10 -08003174 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
3175 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
3176 nlflags |= NLM_F_APPEND;
3177
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02003178 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003179 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003180
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003181 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
3182 * rt6_info structs per nexthop
3183 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003184 while (rtnh_ok(rtnh, remaining)) {
3185 memcpy(&r_cfg, cfg, sizeof(*cfg));
3186 if (rtnh->rtnh_ifindex)
3187 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3188
3189 attrlen = rtnh_attrlen(rtnh);
3190 if (attrlen > 0) {
3191 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3192
3193 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3194 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003195 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003196 r_cfg.fc_flags |= RTF_GATEWAY;
3197 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003198 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
3199 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
3200 if (nla)
3201 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003202 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003203
David Ahern333c4302017-05-21 10:12:04 -06003204 rt = ip6_route_info_create(&r_cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003205 if (IS_ERR(rt)) {
3206 err = PTR_ERR(rt);
3207 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003208 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003209 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003210
3211 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003212 if (err) {
Wei Wang587fea72017-06-17 10:42:36 -07003213 dst_release_immediate(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003214 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003215 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003216
3217 rtnh = rtnh_next(rtnh, &remaining);
3218 }
3219
David Ahern3b1137f2017-02-02 12:37:10 -08003220 /* for add and replace send one notification with all nexthops.
3221 * Skip the notification in fib6_add_rt2node and send one with
3222 * the full route when done
3223 */
3224 info->skip_notify = 1;
3225
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003226 err_nh = NULL;
3227 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern3b1137f2017-02-02 12:37:10 -08003228 rt_last = nh->rt6_info;
David Ahern333c4302017-05-21 10:12:04 -06003229 err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
David Ahern3b1137f2017-02-02 12:37:10 -08003230 /* save reference to first route for notification */
3231 if (!rt_notif && !err)
3232 rt_notif = nh->rt6_info;
3233
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003234 /* nh->rt6_info is used or freed at this point, reset to NULL*/
3235 nh->rt6_info = NULL;
3236 if (err) {
3237 if (replace && nhn)
3238 ip6_print_replace_route_err(&rt6_nh_list);
3239 err_nh = nh;
3240 goto add_errout;
3241 }
3242
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003243 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02003244 * these flags after the first nexthop: if there is a collision,
3245 * we have already failed to add the first nexthop:
3246 * fib6_add_rt2node() has rejected it; when replacing, old
3247 * nexthops have been replaced by first new, the rest should
3248 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003249 */
Michal Kubeček27596472015-05-18 20:54:00 +02003250 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
3251 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003252 nhn++;
3253 }
3254
David Ahern3b1137f2017-02-02 12:37:10 -08003255 /* success ... tell user about new route */
3256 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003257 goto cleanup;
3258
3259add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08003260 /* send notification for routes that were added so that
3261 * the delete notifications sent by ip6_route_del are
3262 * coherent
3263 */
3264 if (rt_notif)
3265 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
3266
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003267 /* Delete routes that were already added */
3268 list_for_each_entry(nh, &rt6_nh_list, next) {
3269 if (err_nh == nh)
3270 break;
David Ahern333c4302017-05-21 10:12:04 -06003271 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003272 }
3273
3274cleanup:
3275 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
Wei Wang587fea72017-06-17 10:42:36 -07003276 if (nh->rt6_info)
3277 dst_release_immediate(&nh->rt6_info->dst);
Wu Fengguang52fe51f2015-09-10 06:57:12 +08003278 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003279 list_del(&nh->next);
3280 kfree(nh);
3281 }
3282
3283 return err;
3284}
3285
David Ahern333c4302017-05-21 10:12:04 -06003286static int ip6_route_multipath_del(struct fib6_config *cfg,
3287 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003288{
3289 struct fib6_config r_cfg;
3290 struct rtnexthop *rtnh;
3291 int remaining;
3292 int attrlen;
3293 int err = 1, last_err = 0;
3294
3295 remaining = cfg->fc_mp_len;
3296 rtnh = (struct rtnexthop *)cfg->fc_mp;
3297
3298 /* Parse a Multipath Entry */
3299 while (rtnh_ok(rtnh, remaining)) {
3300 memcpy(&r_cfg, cfg, sizeof(*cfg));
3301 if (rtnh->rtnh_ifindex)
3302 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3303
3304 attrlen = rtnh_attrlen(rtnh);
3305 if (attrlen > 0) {
3306 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3307
3308 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3309 if (nla) {
3310 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
3311 r_cfg.fc_flags |= RTF_GATEWAY;
3312 }
3313 }
David Ahern333c4302017-05-21 10:12:04 -06003314 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003315 if (err)
3316 last_err = err;
3317
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003318 rtnh = rtnh_next(rtnh, &remaining);
3319 }
3320
3321 return last_err;
3322}
3323
David Ahernc21ef3e2017-04-16 09:48:24 -07003324static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3325 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326{
Thomas Graf86872cb2006-08-22 00:01:08 -07003327 struct fib6_config cfg;
3328 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
David Ahern333c4302017-05-21 10:12:04 -06003330 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003331 if (err < 0)
3332 return err;
3333
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003334 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003335 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003336 else {
3337 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06003338 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340}
3341
David Ahernc21ef3e2017-04-16 09:48:24 -07003342static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3343 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344{
Thomas Graf86872cb2006-08-22 00:01:08 -07003345 struct fib6_config cfg;
3346 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
David Ahern333c4302017-05-21 10:12:04 -06003348 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003349 if (err < 0)
3350 return err;
3351
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003352 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003353 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003354 else
David Ahern333c4302017-05-21 10:12:04 -06003355 return ip6_route_add(&cfg, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356}
3357
David Ahernbeb1afac52017-02-02 12:37:09 -08003358static size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08003359{
David Ahernbeb1afac52017-02-02 12:37:09 -08003360 int nexthop_len = 0;
3361
3362 if (rt->rt6i_nsiblings) {
3363 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
3364 + NLA_ALIGN(sizeof(struct rtnexthop))
3365 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernbeb1afac52017-02-02 12:37:09 -08003366 + lwtunnel_get_encap_size(rt->dst.lwtstate);
3367
3368 nexthop_len *= rt->rt6i_nsiblings;
3369 }
3370
Thomas Graf339bf982006-11-10 14:10:15 -08003371 return NLMSG_ALIGN(sizeof(struct rtmsg))
3372 + nla_total_size(16) /* RTA_SRC */
3373 + nla_total_size(16) /* RTA_DST */
3374 + nla_total_size(16) /* RTA_GATEWAY */
3375 + nla_total_size(16) /* RTA_PREFSRC */
3376 + nla_total_size(4) /* RTA_TABLE */
3377 + nla_total_size(4) /* RTA_IIF */
3378 + nla_total_size(4) /* RTA_OIF */
3379 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08003380 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01003381 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003382 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003383 + nla_total_size(1) /* RTA_PREF */
David Ahernbeb1afac52017-02-02 12:37:09 -08003384 + lwtunnel_get_encap_size(rt->dst.lwtstate)
3385 + nexthop_len;
3386}
3387
3388static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08003389 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08003390{
3391 if (!netif_running(rt->dst.dev) || !netif_carrier_ok(rt->dst.dev)) {
3392 *flags |= RTNH_F_LINKDOWN;
3393 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3394 *flags |= RTNH_F_DEAD;
3395 }
3396
3397 if (rt->rt6i_flags & RTF_GATEWAY) {
3398 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
3399 goto nla_put_failure;
3400 }
3401
Ido Schimmelfe400792017-08-15 09:09:49 +02003402 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02003403 *flags |= RTNH_F_OFFLOAD;
3404
David Ahern5be083c2017-03-06 15:57:31 -08003405 /* not needed for multipath encoding b/c it has a rtnexthop struct */
3406 if (!skip_oif && rt->dst.dev &&
David Ahernbeb1afac52017-02-02 12:37:09 -08003407 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
3408 goto nla_put_failure;
3409
3410 if (rt->dst.lwtstate &&
3411 lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
3412 goto nla_put_failure;
3413
3414 return 0;
3415
3416nla_put_failure:
3417 return -EMSGSIZE;
3418}
3419
David Ahern5be083c2017-03-06 15:57:31 -08003420/* add multipath next hop */
David Ahernbeb1afac52017-02-02 12:37:09 -08003421static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
3422{
3423 struct rtnexthop *rtnh;
3424 unsigned int flags = 0;
3425
3426 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
3427 if (!rtnh)
3428 goto nla_put_failure;
3429
3430 rtnh->rtnh_hops = 0;
3431 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
3432
David Ahern5be083c2017-03-06 15:57:31 -08003433 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003434 goto nla_put_failure;
3435
3436 rtnh->rtnh_flags = flags;
3437
3438 /* length of rtnetlink header + attributes */
3439 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
3440
3441 return 0;
3442
3443nla_put_failure:
3444 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08003445}
3446
Brian Haley191cd582008-08-14 15:33:21 -07003447static int rt6_fill_node(struct net *net,
3448 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07003449 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003450 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003451 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003453 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003455 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08003456 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07003457 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
Eric W. Biederman15e47302012-09-07 20:12:54 +00003459 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05003460 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08003461 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003462
3463 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 rtm->rtm_family = AF_INET6;
3465 rtm->rtm_dst_len = rt->rt6i_dst.plen;
3466 rtm->rtm_src_len = rt->rt6i_src.plen;
3467 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07003468 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07003469 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07003470 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07003471 table = RT6_TABLE_UNSPEC;
3472 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04003473 if (nla_put_u32(skb, RTA_TABLE, table))
3474 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003475 if (rt->rt6i_flags & RTF_REJECT) {
3476 switch (rt->dst.error) {
3477 case -EINVAL:
3478 rtm->rtm_type = RTN_BLACKHOLE;
3479 break;
3480 case -EACCES:
3481 rtm->rtm_type = RTN_PROHIBIT;
3482 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003483 case -EAGAIN:
3484 rtm->rtm_type = RTN_THROW;
3485 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003486 default:
3487 rtm->rtm_type = RTN_UNREACHABLE;
3488 break;
3489 }
3490 }
David S. Miller38308472011-12-03 18:02:47 -05003491 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003492 rtm->rtm_type = RTN_LOCAL;
David Ahern4ee39732017-03-15 18:14:33 -07003493 else if (rt->rt6i_flags & RTF_ANYCAST)
3494 rtm->rtm_type = RTN_ANYCAST;
David S. Millerd1918542011-12-28 20:19:20 -05003495 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 rtm->rtm_type = RTN_LOCAL;
3497 else
3498 rtm->rtm_type = RTN_UNICAST;
3499 rtm->rtm_flags = 0;
3500 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
3501 rtm->rtm_protocol = rt->rt6i_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
David S. Miller38308472011-12-03 18:02:47 -05003503 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 rtm->rtm_flags |= RTM_F_CLONED;
3505
3506 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02003507 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04003508 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003509 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02003511 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003512 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513#ifdef CONFIG_IPV6_SUBTREES
3514 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02003515 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04003516 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003517 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04003518 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02003519 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003520 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003522 if (iif) {
3523#ifdef CONFIG_IPV6_MROUTE
3524 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08003525 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02003526
David Ahernfd61c6b2017-01-17 15:51:07 -08003527 if (err == 0)
3528 return 0;
3529 if (err < 0)
3530 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003531 } else
3532#endif
David S. Millerc78679e2012-04-01 20:27:33 -04003533 if (nla_put_u32(skb, RTA_IIF, iif))
3534 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003535 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04003537 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02003538 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003539 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003541
Daniel Walterc3968a82011-04-13 21:10:57 +00003542 if (rt->rt6i_prefsrc.plen) {
3543 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003544 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02003545 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003546 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00003547 }
3548
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003549 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
3550 if (rt->rt6i_pmtu)
3551 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
3552 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07003553 goto nla_put_failure;
3554
David S. Millerc78679e2012-04-01 20:27:33 -04003555 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
3556 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00003557
David Ahernbeb1afac52017-02-02 12:37:09 -08003558 /* For multipath routes, walk the siblings list and add
3559 * each as a nexthop within RTA_MULTIPATH.
3560 */
3561 if (rt->rt6i_nsiblings) {
3562 struct rt6_info *sibling, *next_sibling;
3563 struct nlattr *mp;
3564
3565 mp = nla_nest_start(skb, RTA_MULTIPATH);
3566 if (!mp)
3567 goto nla_put_failure;
3568
3569 if (rt6_add_nexthop(skb, rt) < 0)
3570 goto nla_put_failure;
3571
3572 list_for_each_entry_safe(sibling, next_sibling,
3573 &rt->rt6i_siblings, rt6i_siblings) {
3574 if (rt6_add_nexthop(skb, sibling) < 0)
3575 goto nla_put_failure;
3576 }
3577
3578 nla_nest_end(skb, mp);
3579 } else {
David Ahern5be083c2017-03-06 15:57:31 -08003580 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003581 goto nla_put_failure;
3582 }
3583
Li Wei82539472012-07-29 16:01:30 +00003584 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07003585
David S. Miller87a50692012-07-10 05:06:14 -07003586 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08003587 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003589 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3590 goto nla_put_failure;
3591
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003592
Johannes Berg053c0952015-01-16 22:09:00 +01003593 nlmsg_end(skb, nlh);
3594 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003595
3596nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08003597 nlmsg_cancel(skb, nlh);
3598 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599}
3600
Patrick McHardy1b43af52006-08-10 23:11:17 -07003601int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602{
3603 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08003604 struct net *net = arg->net;
3605
3606 if (rt == net->ipv6.ip6_null_entry)
3607 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Thomas Graf2d7202b2006-08-22 00:01:27 -07003609 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
3610 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08003611
3612 /* user wants prefix routes only */
3613 if (rtm->rtm_flags & RTM_F_PREFIX &&
3614 !(rt->rt6i_flags & RTF_PREFIX_RT)) {
3615 /* success since this is not a prefix route */
3616 return 1;
3617 }
3618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
David Ahern1f17e2f2017-01-26 13:54:08 -08003620 return rt6_fill_node(net,
Brian Haley191cd582008-08-14 15:33:21 -07003621 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003622 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003623 NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624}
3625
David Ahernc21ef3e2017-04-16 09:48:24 -07003626static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
3627 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003629 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003630 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003631 int err, iif = 0, oif = 0;
3632 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003634 struct sk_buff *skb;
3635 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003636 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003637 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07003638
Johannes Bergfceb6432017-04-12 14:34:07 +02003639 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07003640 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07003641 if (err < 0)
3642 goto errout;
3643
3644 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003645 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02003646 rtm = nlmsg_data(nlh);
3647 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003648 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07003649
3650 if (tb[RTA_SRC]) {
3651 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3652 goto errout;
3653
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003654 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003655 }
3656
3657 if (tb[RTA_DST]) {
3658 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3659 goto errout;
3660
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003661 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003662 }
3663
3664 if (tb[RTA_IIF])
3665 iif = nla_get_u32(tb[RTA_IIF]);
3666
3667 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003668 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003669
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003670 if (tb[RTA_MARK])
3671 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3672
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09003673 if (tb[RTA_UID])
3674 fl6.flowi6_uid = make_kuid(current_user_ns(),
3675 nla_get_u32(tb[RTA_UID]));
3676 else
3677 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
3678
Thomas Grafab364a62006-08-22 00:01:47 -07003679 if (iif) {
3680 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003681 int flags = 0;
3682
Florian Westphal121622d2017-08-15 16:34:42 +02003683 rcu_read_lock();
3684
3685 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003686 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02003687 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07003688 err = -ENODEV;
3689 goto errout;
3690 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003691
3692 fl6.flowi6_iif = iif;
3693
3694 if (!ipv6_addr_any(&fl6.saddr))
3695 flags |= RT6_LOOKUP_F_HAS_SADDR;
3696
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003697 if (!fibmatch)
3698 dst = ip6_route_input_lookup(net, dev, &fl6, flags);
Arnd Bergmann401481e2017-08-18 13:34:22 +02003699 else
3700 dst = ip6_route_lookup(net, &fl6, 0);
Florian Westphal121622d2017-08-15 16:34:42 +02003701
3702 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003703 } else {
3704 fl6.flowi6_oif = oif;
3705
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003706 if (!fibmatch)
3707 dst = ip6_route_output(net, NULL, &fl6);
Arnd Bergmann401481e2017-08-18 13:34:22 +02003708 else
3709 dst = ip6_route_lookup(net, &fl6, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003710 }
3711
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003712
3713 rt = container_of(dst, struct rt6_info, dst);
3714 if (rt->dst.error) {
3715 err = rt->dst.error;
3716 ip6_rt_put(rt);
3717 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07003718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
WANG Cong9d6acb32017-03-01 20:48:39 -08003720 if (rt == net->ipv6.ip6_null_entry) {
3721 err = rt->dst.error;
3722 ip6_rt_put(rt);
3723 goto errout;
3724 }
3725
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003727 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003728 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003729 err = -ENOBUFS;
3730 goto errout;
3731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
Changli Gaod8d1f302010-06-10 23:31:35 -07003733 skb_dst_set(skb, &rt->dst);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003734 if (fibmatch)
3735 err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
3736 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3737 nlh->nlmsg_seq, 0);
3738 else
3739 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
3740 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3741 nlh->nlmsg_seq, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003743 kfree_skb(skb);
3744 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 }
3746
Eric W. Biederman15e47302012-09-07 20:12:54 +00003747 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003748errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750}
3751
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003752void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
3753 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754{
3755 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003756 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003757 u32 seq;
3758 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003760 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003761 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003762
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003763 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003764 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003765 goto errout;
3766
Brian Haley191cd582008-08-14 15:33:21 -07003767 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003768 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003769 if (err < 0) {
3770 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3771 WARN_ON(err == -EMSGSIZE);
3772 kfree_skb(skb);
3773 goto errout;
3774 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003775 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003776 info->nlh, gfp_any());
3777 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003778errout:
3779 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003780 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781}
3782
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003783static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003784 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003785{
Jiri Pirko351638e2013-05-28 01:30:21 +00003786 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003787 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003788
WANG Cong242d3a42017-05-08 10:12:13 -07003789 if (!(dev->flags & IFF_LOOPBACK))
3790 return NOTIFY_OK;
3791
3792 if (event == NETDEV_REGISTER) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003793 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003794 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3795#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003796 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003797 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003798 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003799 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3800#endif
WANG Cong76da0702017-06-20 11:42:27 -07003801 } else if (event == NETDEV_UNREGISTER &&
3802 dev->reg_state != NETREG_UNREGISTERED) {
3803 /* NETDEV_UNREGISTER could be fired for multiple times by
3804 * netdev_wait_allrefs(). Make sure we only call this once.
3805 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07003806 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07003807#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07003808 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
3809 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07003810#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003811 }
3812
3813 return NOTIFY_OK;
3814}
3815
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816/*
3817 * /proc
3818 */
3819
3820#ifdef CONFIG_PROC_FS
3821
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003822static const struct file_operations ipv6_route_proc_fops = {
3823 .owner = THIS_MODULE,
3824 .open = ipv6_route_open,
3825 .read = seq_read,
3826 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003827 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003828};
3829
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3831{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003832 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003834 net->ipv6.rt6_stats->fib_nodes,
3835 net->ipv6.rt6_stats->fib_route_nodes,
3836 net->ipv6.rt6_stats->fib_rt_alloc,
3837 net->ipv6.rt6_stats->fib_rt_entries,
3838 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003839 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003840 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841
3842 return 0;
3843}
3844
3845static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3846{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003847 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003848}
3849
Arjan van de Ven9a321442007-02-12 00:55:35 -08003850static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 .owner = THIS_MODULE,
3852 .open = rt6_stats_seq_open,
3853 .read = seq_read,
3854 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003855 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856};
3857#endif /* CONFIG_PROC_FS */
3858
3859#ifdef CONFIG_SYSCTL
3860
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003862int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 void __user *buffer, size_t *lenp, loff_t *ppos)
3864{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003865 struct net *net;
3866 int delay;
3867 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003869
3870 net = (struct net *)ctl->extra1;
3871 delay = net->ipv6.sysctl.flush_delay;
3872 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003873 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003874 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875}
3876
Joe Perchesfe2c6332013-06-11 23:04:25 -07003877struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003878 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003880 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003882 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003883 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 },
3885 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003887 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 .maxlen = sizeof(int),
3889 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003890 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 },
3892 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003894 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 .maxlen = sizeof(int),
3896 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003897 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 },
3899 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003901 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 .maxlen = sizeof(int),
3903 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003904 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 },
3906 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003908 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 .maxlen = sizeof(int),
3910 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003911 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 },
3913 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003915 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 .maxlen = sizeof(int),
3917 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003918 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 },
3920 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003922 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 .maxlen = sizeof(int),
3924 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003925 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 },
3927 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003929 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 .maxlen = sizeof(int),
3931 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003932 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 },
3934 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003936 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 .maxlen = sizeof(int),
3938 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003939 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 },
3941 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003943 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 .maxlen = sizeof(int),
3945 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003946 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003948 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949};
3950
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003951struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003952{
3953 struct ctl_table *table;
3954
3955 table = kmemdup(ipv6_route_table_template,
3956 sizeof(ipv6_route_table_template),
3957 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003958
3959 if (table) {
3960 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003961 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003962 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003963 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3964 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3965 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3966 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3967 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3968 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3969 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003970 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003971
3972 /* Don't export sysctls to unprivileged users */
3973 if (net->user_ns != &init_user_ns)
3974 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003975 }
3976
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003977 return table;
3978}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979#endif
3980
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003981static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003982{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003983 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003984
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003985 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3986 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003987
Eric Dumazetfc66f952010-10-08 06:37:34 +00003988 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3989 goto out_ip6_dst_ops;
3990
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003991 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3992 sizeof(*net->ipv6.ip6_null_entry),
3993 GFP_KERNEL);
3994 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003995 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003996 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003997 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003998 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003999 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
4000 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004001
4002#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02004003 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004004 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
4005 sizeof(*net->ipv6.ip6_prohibit_entry),
4006 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004007 if (!net->ipv6.ip6_prohibit_entry)
4008 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004009 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004010 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004011 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004012 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
4013 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004014
4015 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
4016 sizeof(*net->ipv6.ip6_blk_hole_entry),
4017 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004018 if (!net->ipv6.ip6_blk_hole_entry)
4019 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004020 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004021 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004022 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004023 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
4024 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004025#endif
4026
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07004027 net->ipv6.sysctl.flush_delay = 0;
4028 net->ipv6.sysctl.ip6_rt_max_size = 4096;
4029 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
4030 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
4031 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
4032 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
4033 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
4034 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
4035
Benjamin Thery6891a342008-03-04 13:49:47 -08004036 net->ipv6.ip6_rt_gc_expire = 30*HZ;
4037
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004038 ret = 0;
4039out:
4040 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004041
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004042#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4043out_ip6_prohibit_entry:
4044 kfree(net->ipv6.ip6_prohibit_entry);
4045out_ip6_null_entry:
4046 kfree(net->ipv6.ip6_null_entry);
4047#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00004048out_ip6_dst_entries:
4049 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004050out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004051 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004052}
4053
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004054static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004055{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004056 kfree(net->ipv6.ip6_null_entry);
4057#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4058 kfree(net->ipv6.ip6_prohibit_entry);
4059 kfree(net->ipv6.ip6_blk_hole_entry);
4060#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004061 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004062}
4063
Thomas Grafd1896342012-06-18 12:08:33 +00004064static int __net_init ip6_route_net_init_late(struct net *net)
4065{
4066#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00004067 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
4068 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00004069#endif
4070 return 0;
4071}
4072
4073static void __net_exit ip6_route_net_exit_late(struct net *net)
4074{
4075#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00004076 remove_proc_entry("ipv6_route", net->proc_net);
4077 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00004078#endif
4079}
4080
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004081static struct pernet_operations ip6_route_net_ops = {
4082 .init = ip6_route_net_init,
4083 .exit = ip6_route_net_exit,
4084};
4085
David S. Millerc3426b42012-06-09 16:27:05 -07004086static int __net_init ipv6_inetpeer_init(struct net *net)
4087{
4088 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
4089
4090 if (!bp)
4091 return -ENOMEM;
4092 inet_peer_base_init(bp);
4093 net->ipv6.peers = bp;
4094 return 0;
4095}
4096
4097static void __net_exit ipv6_inetpeer_exit(struct net *net)
4098{
4099 struct inet_peer_base *bp = net->ipv6.peers;
4100
4101 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07004102 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07004103 kfree(bp);
4104}
4105
David S. Miller2b823f72012-06-09 19:00:16 -07004106static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07004107 .init = ipv6_inetpeer_init,
4108 .exit = ipv6_inetpeer_exit,
4109};
4110
Thomas Grafd1896342012-06-18 12:08:33 +00004111static struct pernet_operations ip6_route_net_late_ops = {
4112 .init = ip6_route_net_init_late,
4113 .exit = ip6_route_net_exit_late,
4114};
4115
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004116static struct notifier_block ip6_route_dev_notifier = {
4117 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07004118 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004119};
4120
WANG Cong2f460932017-05-03 22:07:31 -07004121void __init ip6_route_init_special_entries(void)
4122{
4123 /* Registering of the loopback is done before this portion of code,
4124 * the loopback reference in rt6_info will not be taken, do it
4125 * manually for init_net */
4126 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
4127 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4128 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
4129 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
4130 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4131 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
4132 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4133 #endif
4134}
4135
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004136int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004138 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004139 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004140
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004141 ret = -ENOMEM;
4142 ip6_dst_ops_template.kmem_cachep =
4143 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
4144 SLAB_HWCACHE_ALIGN, NULL);
4145 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08004146 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07004147
Eric Dumazetfc66f952010-10-08 06:37:34 +00004148 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004149 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004150 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004151
David S. Millerc3426b42012-06-09 16:27:05 -07004152 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
4153 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004154 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00004155
David S. Miller7e52b332012-06-15 15:51:55 -07004156 ret = register_pernet_subsys(&ip6_route_net_ops);
4157 if (ret)
4158 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07004159
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07004160 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
4161
David S. Millere8803b62012-06-16 01:12:19 -07004162 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004163 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004164 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004165
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004166 ret = xfrm6_init();
4167 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004168 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08004169
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004170 ret = fib6_rules_init();
4171 if (ret)
4172 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08004173
Thomas Grafd1896342012-06-18 12:08:33 +00004174 ret = register_pernet_subsys(&ip6_route_net_late_ops);
4175 if (ret)
4176 goto fib6_rules_init;
4177
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004178 ret = -ENOBUFS;
Florian Westphalb97bac62017-08-09 20:41:48 +02004179 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, 0) ||
4180 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, 0) ||
Florian Westphale3a22b72017-08-15 16:34:43 +02004181 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL,
4182 RTNL_FLAG_DOIT_UNLOCKED))
Thomas Grafd1896342012-06-18 12:08:33 +00004183 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004184
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004185 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004186 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00004187 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004188
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004189 for_each_possible_cpu(cpu) {
4190 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
4191
4192 INIT_LIST_HEAD(&ul->head);
4193 spin_lock_init(&ul->lock);
4194 }
4195
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004196out:
4197 return ret;
4198
Thomas Grafd1896342012-06-18 12:08:33 +00004199out_register_late_subsys:
4200 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004201fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004202 fib6_rules_cleanup();
4203xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004204 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00004205out_fib6_init:
4206 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004207out_register_subsys:
4208 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07004209out_register_inetpeer:
4210 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00004211out_dst_entries:
4212 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004213out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004214 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004215 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216}
4217
4218void ip6_route_cleanup(void)
4219{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004220 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00004221 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07004222 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07004225 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004226 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004227 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004228 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229}