Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * Linux INET6 implementation
4 : : * FIB front-end.
5 : : *
6 : : * Authors:
7 : : * Pedro Roque <roque@di.fc.ul.pt>
8 : : */
9 : :
10 : : /* Changes:
11 : : *
12 : : * YOSHIFUJI Hideaki @USAGI
13 : : * reworked default router selection.
14 : : * - respect outgoing interface
15 : : * - select from (probably) reachable routers (i.e.
16 : : * routers in REACHABLE, STALE, DELAY or PROBE states).
17 : : * - always select the same router if it is (probably)
18 : : * reachable. otherwise, round-robin the list.
19 : : * Ville Nuorvala
20 : : * Fixed routing subtrees.
21 : : */
22 : :
23 : : #define pr_fmt(fmt) "IPv6: " fmt
24 : :
25 : : #include <linux/capability.h>
26 : : #include <linux/errno.h>
27 : : #include <linux/export.h>
28 : : #include <linux/types.h>
29 : : #include <linux/times.h>
30 : : #include <linux/socket.h>
31 : : #include <linux/sockios.h>
32 : : #include <linux/net.h>
33 : : #include <linux/route.h>
34 : : #include <linux/netdevice.h>
35 : : #include <linux/in6.h>
36 : : #include <linux/mroute6.h>
37 : : #include <linux/init.h>
38 : : #include <linux/if_arp.h>
39 : : #include <linux/proc_fs.h>
40 : : #include <linux/seq_file.h>
41 : : #include <linux/nsproxy.h>
42 : : #include <linux/slab.h>
43 : : #include <linux/jhash.h>
44 : : #include <net/net_namespace.h>
45 : : #include <net/snmp.h>
46 : : #include <net/ipv6.h>
47 : : #include <net/ip6_fib.h>
48 : : #include <net/ip6_route.h>
49 : : #include <net/ndisc.h>
50 : : #include <net/addrconf.h>
51 : : #include <net/tcp.h>
52 : : #include <linux/rtnetlink.h>
53 : : #include <net/dst.h>
54 : : #include <net/dst_metadata.h>
55 : : #include <net/xfrm.h>
56 : : #include <net/netevent.h>
57 : : #include <net/netlink.h>
58 : : #include <net/rtnh.h>
59 : : #include <net/lwtunnel.h>
60 : : #include <net/ip_tunnels.h>
61 : : #include <net/l3mdev.h>
62 : : #include <net/ip.h>
63 : : #include <linux/uaccess.h>
64 : :
65 : : #ifdef CONFIG_SYSCTL
66 : : #include <linux/sysctl.h>
67 : : #endif
68 : :
69 : : static int ip6_rt_type_to_error(u8 fib6_type);
70 : :
71 : : #define CREATE_TRACE_POINTS
72 : : #include <trace/events/fib6.h>
73 : : EXPORT_TRACEPOINT_SYMBOL_GPL(fib6_table_lookup);
74 : : #undef CREATE_TRACE_POINTS
75 : :
76 : : enum rt6_nud_state {
77 : : RT6_NUD_FAIL_HARD = -3,
78 : : RT6_NUD_FAIL_PROBE = -2,
79 : : RT6_NUD_FAIL_DO_RR = -1,
80 : : RT6_NUD_SUCCEED = 1
81 : : };
82 : :
83 : : static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
84 : : static unsigned int ip6_default_advmss(const struct dst_entry *dst);
85 : : static unsigned int ip6_mtu(const struct dst_entry *dst);
86 : : static struct dst_entry *ip6_negative_advice(struct dst_entry *);
87 : : static void ip6_dst_destroy(struct dst_entry *);
88 : : static void ip6_dst_ifdown(struct dst_entry *,
89 : : struct net_device *dev, int how);
90 : : static int ip6_dst_gc(struct dst_ops *ops);
91 : :
92 : : static int ip6_pkt_discard(struct sk_buff *skb);
93 : : static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
94 : : static int ip6_pkt_prohibit(struct sk_buff *skb);
95 : : static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
96 : : static void ip6_link_failure(struct sk_buff *skb);
97 : : static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
98 : : struct sk_buff *skb, u32 mtu,
99 : : bool confirm_neigh);
100 : : static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
101 : : struct sk_buff *skb);
102 : : static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
103 : : int strict);
104 : : static size_t rt6_nlmsg_size(struct fib6_info *f6i);
105 : : static int rt6_fill_node(struct net *net, struct sk_buff *skb,
106 : : struct fib6_info *rt, struct dst_entry *dst,
107 : : struct in6_addr *dest, struct in6_addr *src,
108 : : int iif, int type, u32 portid, u32 seq,
109 : : unsigned int flags);
110 : : static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
111 : : const struct in6_addr *daddr,
112 : : const struct in6_addr *saddr);
113 : :
114 : : #ifdef CONFIG_IPV6_ROUTE_INFO
115 : : static struct fib6_info *rt6_add_route_info(struct net *net,
116 : : const struct in6_addr *prefix, int prefixlen,
117 : : const struct in6_addr *gwaddr,
118 : : struct net_device *dev,
119 : : unsigned int pref);
120 : : static struct fib6_info *rt6_get_route_info(struct net *net,
121 : : const struct in6_addr *prefix, int prefixlen,
122 : : const struct in6_addr *gwaddr,
123 : : struct net_device *dev);
124 : : #endif
125 : :
126 : : struct uncached_list {
127 : : spinlock_t lock;
128 : : struct list_head head;
129 : : };
130 : :
131 : : static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
132 : :
133 : 166 : void rt6_uncached_list_add(struct rt6_info *rt)
134 : : {
135 : 166 : struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
136 : :
137 : 166 : rt->rt6i_uncached_list = ul;
138 : :
139 : 166 : spin_lock_bh(&ul->lock);
140 : 166 : list_add_tail(&rt->rt6i_uncached, &ul->head);
141 : 166 : spin_unlock_bh(&ul->lock);
142 : 166 : }
143 : :
144 : 149 : void rt6_uncached_list_del(struct rt6_info *rt)
145 : : {
146 [ + - ]: 149 : if (!list_empty(&rt->rt6i_uncached)) {
147 : 149 : struct uncached_list *ul = rt->rt6i_uncached_list;
148 : 149 : struct net *net = dev_net(rt->dst.dev);
149 : :
150 : 149 : spin_lock_bh(&ul->lock);
151 : 149 : list_del(&rt->rt6i_uncached);
152 : 149 : atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
153 : 149 : spin_unlock_bh(&ul->lock);
154 : : }
155 : 149 : }
156 : :
157 : : static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
158 : : {
159 : : struct net_device *loopback_dev = net->loopback_dev;
160 : : int cpu;
161 : :
162 : : if (dev == loopback_dev)
163 : : return;
164 : :
165 : : for_each_possible_cpu(cpu) {
166 : : struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
167 : : struct rt6_info *rt;
168 : :
169 : : spin_lock_bh(&ul->lock);
170 : : list_for_each_entry(rt, &ul->head, rt6i_uncached) {
171 : : struct inet6_dev *rt_idev = rt->rt6i_idev;
172 : : struct net_device *rt_dev = rt->dst.dev;
173 : :
174 : : if (rt_idev->dev == dev) {
175 : : rt->rt6i_idev = in6_dev_get(loopback_dev);
176 : : in6_dev_put(rt_idev);
177 : : }
178 : :
179 : : if (rt_dev == dev) {
180 : : rt->dst.dev = blackhole_netdev;
181 : : dev_hold(rt->dst.dev);
182 : : dev_put(rt_dev);
183 : : }
184 : : }
185 : : spin_unlock_bh(&ul->lock);
186 : : }
187 : : }
188 : :
189 : 0 : static inline const void *choose_neigh_daddr(const struct in6_addr *p,
190 : : struct sk_buff *skb,
191 : : const void *daddr)
192 : : {
193 [ # # ]: 0 : if (!ipv6_addr_any(p))
194 : : return (const void *) p;
195 [ # # ]: 0 : else if (skb)
196 : 0 : return &ipv6_hdr(skb)->daddr;
197 : : return daddr;
198 : : }
199 : :
200 : 0 : struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
201 : : struct net_device *dev,
202 : : struct sk_buff *skb,
203 : : const void *daddr)
204 : : {
205 : 0 : struct neighbour *n;
206 : :
207 [ # # ]: 0 : daddr = choose_neigh_daddr(gw, skb, daddr);
208 : 0 : n = __ipv6_neigh_lookup(dev, daddr);
209 [ # # ]: 0 : if (n)
210 : : return n;
211 : :
212 : 0 : n = neigh_create(&nd_tbl, daddr, dev);
213 [ # # ]: 0 : return IS_ERR(n) ? NULL : n;
214 : : }
215 : :
216 : 0 : static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
217 : : struct sk_buff *skb,
218 : : const void *daddr)
219 : : {
220 : 0 : const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
221 : :
222 [ # # ]: 0 : return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any),
223 : : dst->dev, skb, daddr);
224 : : }
225 : :
226 : 0 : static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
227 : : {
228 : 0 : struct net_device *dev = dst->dev;
229 : 0 : struct rt6_info *rt = (struct rt6_info *)dst;
230 : :
231 [ # # ]: 0 : daddr = choose_neigh_daddr(rt6_nexthop(rt, &in6addr_any), NULL, daddr);
232 [ # # ]: 0 : if (!daddr)
233 : : return;
234 [ # # ]: 0 : if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
235 : : return;
236 [ # # ]: 0 : if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
237 : : return;
238 : 0 : __ipv6_confirm_neigh(dev, daddr);
239 : : }
240 : :
241 : : static struct dst_ops ip6_dst_ops_template = {
242 : : .family = AF_INET6,
243 : : .gc = ip6_dst_gc,
244 : : .gc_thresh = 1024,
245 : : .check = ip6_dst_check,
246 : : .default_advmss = ip6_default_advmss,
247 : : .mtu = ip6_mtu,
248 : : .cow_metrics = dst_cow_metrics_generic,
249 : : .destroy = ip6_dst_destroy,
250 : : .ifdown = ip6_dst_ifdown,
251 : : .negative_advice = ip6_negative_advice,
252 : : .link_failure = ip6_link_failure,
253 : : .update_pmtu = ip6_rt_update_pmtu,
254 : : .redirect = rt6_do_redirect,
255 : : .local_out = __ip6_local_out,
256 : : .neigh_lookup = ip6_dst_neigh_lookup,
257 : : .confirm_neigh = ip6_confirm_neigh,
258 : : };
259 : :
260 : 0 : static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
261 : : {
262 [ # # ]: 0 : unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
263 : :
264 [ # # ]: 0 : return mtu ? : dst->dev->mtu;
265 : : }
266 : :
267 : 0 : static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
268 : : struct sk_buff *skb, u32 mtu,
269 : : bool confirm_neigh)
270 : : {
271 : 0 : }
272 : :
273 : 0 : static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
274 : : struct sk_buff *skb)
275 : : {
276 : 0 : }
277 : :
278 : : static struct dst_ops ip6_dst_blackhole_ops = {
279 : : .family = AF_INET6,
280 : : .destroy = ip6_dst_destroy,
281 : : .check = ip6_dst_check,
282 : : .mtu = ip6_blackhole_mtu,
283 : : .default_advmss = ip6_default_advmss,
284 : : .update_pmtu = ip6_rt_blackhole_update_pmtu,
285 : : .redirect = ip6_rt_blackhole_redirect,
286 : : .cow_metrics = dst_cow_metrics_generic,
287 : : .neigh_lookup = ip6_dst_neigh_lookup,
288 : : };
289 : :
290 : : static const u32 ip6_template_metrics[RTAX_MAX] = {
291 : : [RTAX_HOPLIMIT - 1] = 0,
292 : : };
293 : :
294 : : static const struct fib6_info fib6_null_entry_template = {
295 : : .fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
296 : : .fib6_protocol = RTPROT_KERNEL,
297 : : .fib6_metric = ~(u32)0,
298 : : .fib6_ref = REFCOUNT_INIT(1),
299 : : .fib6_type = RTN_UNREACHABLE,
300 : : .fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
301 : : };
302 : :
303 : : static const struct rt6_info ip6_null_entry_template = {
304 : : .dst = {
305 : : .__refcnt = ATOMIC_INIT(1),
306 : : .__use = 1,
307 : : .obsolete = DST_OBSOLETE_FORCE_CHK,
308 : : .error = -ENETUNREACH,
309 : : .input = ip6_pkt_discard,
310 : : .output = ip6_pkt_discard_out,
311 : : },
312 : : .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
313 : : };
314 : :
315 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
316 : :
317 : : static const struct rt6_info ip6_prohibit_entry_template = {
318 : : .dst = {
319 : : .__refcnt = ATOMIC_INIT(1),
320 : : .__use = 1,
321 : : .obsolete = DST_OBSOLETE_FORCE_CHK,
322 : : .error = -EACCES,
323 : : .input = ip6_pkt_prohibit,
324 : : .output = ip6_pkt_prohibit_out,
325 : : },
326 : : .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
327 : : };
328 : :
329 : : static const struct rt6_info ip6_blk_hole_entry_template = {
330 : : .dst = {
331 : : .__refcnt = ATOMIC_INIT(1),
332 : : .__use = 1,
333 : : .obsolete = DST_OBSOLETE_FORCE_CHK,
334 : : .error = -EINVAL,
335 : : .input = dst_discard,
336 : : .output = dst_discard_out,
337 : : },
338 : : .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
339 : : };
340 : :
341 : : #endif
342 : :
343 : 244 : static void rt6_info_init(struct rt6_info *rt)
344 : : {
345 : 244 : struct dst_entry *dst = &rt->dst;
346 : :
347 : 244 : memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
348 : 244 : INIT_LIST_HEAD(&rt->rt6i_uncached);
349 : : }
350 : :
351 : : /* allocate dst with ip6_dst_ops */
352 : 244 : struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
353 : : int flags)
354 : : {
355 : 244 : struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
356 : : 1, DST_OBSOLETE_FORCE_CHK, flags);
357 : :
358 [ + - ]: 244 : if (rt) {
359 : 244 : rt6_info_init(rt);
360 : 244 : atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
361 : : }
362 : :
363 : 244 : return rt;
364 : : }
365 : : EXPORT_SYMBOL(ip6_dst_alloc);
366 : :
367 : 149 : static void ip6_dst_destroy(struct dst_entry *dst)
368 : : {
369 : 149 : struct rt6_info *rt = (struct rt6_info *)dst;
370 : 149 : struct fib6_info *from;
371 : 149 : struct inet6_dev *idev;
372 : :
373 : 149 : ip_dst_metrics_put(dst);
374 : 149 : rt6_uncached_list_del(rt);
375 : :
376 : 149 : idev = rt->rt6i_idev;
377 [ + - ]: 149 : if (idev) {
378 : 149 : rt->rt6i_idev = NULL;
379 : 149 : in6_dev_put(idev);
380 : : }
381 : :
382 : 149 : from = xchg((__force struct fib6_info **)&rt->from, NULL);
383 : 149 : fib6_info_release(from);
384 : 149 : }
385 : :
386 : 0 : static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
387 : : int how)
388 : : {
389 : 0 : struct rt6_info *rt = (struct rt6_info *)dst;
390 : 0 : struct inet6_dev *idev = rt->rt6i_idev;
391 [ # # ]: 0 : struct net_device *loopback_dev =
392 : : dev_net(dev)->loopback_dev;
393 : :
394 [ # # # # ]: 0 : if (idev && idev->dev != loopback_dev) {
395 : 0 : struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
396 [ # # ]: 0 : if (loopback_idev) {
397 : 0 : rt->rt6i_idev = loopback_idev;
398 : 0 : in6_dev_put(idev);
399 : : }
400 : : }
401 : 0 : }
402 : :
403 : 312 : static bool __rt6_check_expired(const struct rt6_info *rt)
404 : : {
405 : 312 : if (rt->rt6i_flags & RTF_EXPIRES)
406 [ # # ]: 0 : return time_after(jiffies, rt->dst.expires);
407 : : else
408 : : return false;
409 : : }
410 : :
411 : 0 : static bool rt6_check_expired(const struct rt6_info *rt)
412 : : {
413 : 0 : struct fib6_info *from;
414 : :
415 [ # # ]: 0 : from = rcu_dereference(rt->from);
416 : :
417 [ # # ]: 0 : if (rt->rt6i_flags & RTF_EXPIRES) {
418 [ # # ]: 0 : if (time_after(jiffies, rt->dst.expires))
419 : 0 : return true;
420 [ # # ]: 0 : } else if (from) {
421 [ # # # # ]: 0 : return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
422 [ # # ]: 0 : fib6_check_expired(from);
423 : : }
424 : : return false;
425 : : }
426 : :
427 : 156 : void fib6_select_path(const struct net *net, struct fib6_result *res,
428 : : struct flowi6 *fl6, int oif, bool have_oif_match,
429 : : const struct sk_buff *skb, int strict)
430 : : {
431 : 156 : struct fib6_info *sibling, *next_sibling;
432 : 156 : struct fib6_info *match = res->f6i;
433 : :
434 [ + - - + : 156 : if ((!match->fib6_nsiblings && !match->nh) || have_oif_match)
- - ]
435 : 156 : goto out;
436 : :
437 : : /* We might have already computed the hash for ICMPv6 errors. In such
438 : : * case it will always be non-zero. Otherwise now is the time to do it.
439 : : */
440 [ # # ]: 0 : if (!fl6->mp_hash &&
441 [ # # # # ]: 0 : (!match->nh || nexthop_is_multipath(match->nh)))
442 : 0 : fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL);
443 : :
444 [ # # ]: 0 : if (unlikely(match->nh)) {
445 : 0 : nexthop_path_fib6_result(res, fl6->mp_hash);
446 : 0 : return;
447 : : }
448 : :
449 [ # # ]: 0 : if (fl6->mp_hash <= atomic_read(&match->fib6_nh->fib_nh_upper_bound))
450 : 0 : goto out;
451 : :
452 [ # # ]: 0 : list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
453 : : fib6_siblings) {
454 : 0 : const struct fib6_nh *nh = sibling->fib6_nh;
455 : 0 : int nh_upper_bound;
456 : :
457 : 0 : nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound);
458 [ # # ]: 0 : if (fl6->mp_hash > nh_upper_bound)
459 : 0 : continue;
460 [ # # ]: 0 : if (rt6_score_route(nh, sibling->fib6_flags, oif, strict) < 0)
461 : : break;
462 : 0 : match = sibling;
463 : 0 : break;
464 : : }
465 : :
466 : 0 : out:
467 : 156 : res->f6i = match;
468 : 156 : res->nh = match->fib6_nh;
469 : : }
470 : :
471 : : /*
472 : : * Route lookup. rcu_read_lock() should be held.
473 : : */
474 : :
475 : : static bool __rt6_device_match(struct net *net, const struct fib6_nh *nh,
476 : : const struct in6_addr *saddr, int oif, int flags)
477 : : {
478 : : const struct net_device *dev;
479 : :
480 : : if (nh->fib_nh_flags & RTNH_F_DEAD)
481 : : return false;
482 : :
483 : : dev = nh->fib_nh_dev;
484 : : if (oif) {
485 : : if (dev->ifindex == oif)
486 : : return true;
487 : : } else {
488 : : if (ipv6_chk_addr(net, saddr, dev,
489 : : flags & RT6_LOOKUP_F_IFACE))
490 : : return true;
491 : : }
492 : :
493 : : return false;
494 : : }
495 : :
496 : : struct fib6_nh_dm_arg {
497 : : struct net *net;
498 : : const struct in6_addr *saddr;
499 : : int oif;
500 : : int flags;
501 : : struct fib6_nh *nh;
502 : : };
503 : :
504 : 0 : static int __rt6_nh_dev_match(struct fib6_nh *nh, void *_arg)
505 : : {
506 : 0 : struct fib6_nh_dm_arg *arg = _arg;
507 : :
508 : 0 : arg->nh = nh;
509 : 0 : return __rt6_device_match(arg->net, nh, arg->saddr, arg->oif,
510 : : arg->flags);
511 : : }
512 : :
513 : : /* returns fib6_nh from nexthop or NULL */
514 : : static struct fib6_nh *rt6_nh_dev_match(struct net *net, struct nexthop *nh,
515 : : struct fib6_result *res,
516 : : const struct in6_addr *saddr,
517 : : int oif, int flags)
518 : : {
519 : : struct fib6_nh_dm_arg arg = {
520 : : .net = net,
521 : : .saddr = saddr,
522 : : .oif = oif,
523 : : .flags = flags,
524 : : };
525 : :
526 : : if (nexthop_is_blackhole(nh))
527 : : return NULL;
528 : :
529 : : if (nexthop_for_each_fib6_nh(nh, __rt6_nh_dev_match, &arg))
530 : : return arg.nh;
531 : :
532 : : return NULL;
533 : : }
534 : :
535 : 0 : static void rt6_device_match(struct net *net, struct fib6_result *res,
536 : : const struct in6_addr *saddr, int oif, int flags)
537 : : {
538 : 0 : struct fib6_info *f6i = res->f6i;
539 : 0 : struct fib6_info *spf6i;
540 : 0 : struct fib6_nh *nh;
541 : :
542 [ # # # # ]: 0 : if (!oif && ipv6_addr_any(saddr)) {
543 [ # # ]: 0 : if (unlikely(f6i->nh)) {
544 [ # # ]: 0 : nh = nexthop_fib6_nh(f6i->nh);
545 [ # # ]: 0 : if (nexthop_is_blackhole(f6i->nh))
546 : 0 : goto out_blackhole;
547 : : } else {
548 : 0 : nh = f6i->fib6_nh;
549 : : }
550 [ # # ]: 0 : if (!(nh->fib_nh_flags & RTNH_F_DEAD))
551 : 0 : goto out;
552 : : }
553 : :
554 [ # # ]: 0 : for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) {
555 : 0 : bool matched = false;
556 : :
557 [ # # ]: 0 : if (unlikely(spf6i->nh)) {
558 : 0 : nh = rt6_nh_dev_match(net, spf6i->nh, res, saddr,
559 : : oif, flags);
560 [ # # ]: 0 : if (nh)
561 : : matched = true;
562 : : } else {
563 : 0 : nh = spf6i->fib6_nh;
564 [ # # ]: 0 : if (__rt6_device_match(net, nh, saddr, oif, flags))
565 : : matched = true;
566 : : }
567 : : if (matched) {
568 : 0 : res->f6i = spf6i;
569 : 0 : goto out;
570 : : }
571 : : }
572 : :
573 [ # # # # ]: 0 : if (oif && flags & RT6_LOOKUP_F_IFACE) {
574 : 0 : res->f6i = net->ipv6.fib6_null_entry;
575 : 0 : nh = res->f6i->fib6_nh;
576 : 0 : goto out;
577 : : }
578 : :
579 [ # # ]: 0 : if (unlikely(f6i->nh)) {
580 [ # # ]: 0 : nh = nexthop_fib6_nh(f6i->nh);
581 [ # # ]: 0 : if (nexthop_is_blackhole(f6i->nh))
582 : 0 : goto out_blackhole;
583 : : } else {
584 : 0 : nh = f6i->fib6_nh;
585 : : }
586 : :
587 [ # # ]: 0 : if (nh->fib_nh_flags & RTNH_F_DEAD) {
588 : 0 : res->f6i = net->ipv6.fib6_null_entry;
589 : 0 : nh = res->f6i->fib6_nh;
590 : : }
591 : 0 : out:
592 : 0 : res->nh = nh;
593 : 0 : res->fib6_type = res->f6i->fib6_type;
594 : 0 : res->fib6_flags = res->f6i->fib6_flags;
595 : 0 : return;
596 : :
597 : 0 : out_blackhole:
598 : 0 : res->fib6_flags |= RTF_REJECT;
599 : 0 : res->fib6_type = RTN_BLACKHOLE;
600 : 0 : res->nh = nh;
601 : : }
602 : :
603 : : #ifdef CONFIG_IPV6_ROUTER_PREF
604 : : struct __rt6_probe_work {
605 : : struct work_struct work;
606 : : struct in6_addr target;
607 : : struct net_device *dev;
608 : : };
609 : :
610 : : static void rt6_probe_deferred(struct work_struct *w)
611 : : {
612 : : struct in6_addr mcaddr;
613 : : struct __rt6_probe_work *work =
614 : : container_of(w, struct __rt6_probe_work, work);
615 : :
616 : : addrconf_addr_solict_mult(&work->target, &mcaddr);
617 : : ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
618 : : dev_put(work->dev);
619 : : kfree(work);
620 : : }
621 : :
622 : : static void rt6_probe(struct fib6_nh *fib6_nh)
623 : : {
624 : : struct __rt6_probe_work *work = NULL;
625 : : const struct in6_addr *nh_gw;
626 : : unsigned long last_probe;
627 : : struct neighbour *neigh;
628 : : struct net_device *dev;
629 : : struct inet6_dev *idev;
630 : :
631 : : /*
632 : : * Okay, this does not seem to be appropriate
633 : : * for now, however, we need to check if it
634 : : * is really so; aka Router Reachability Probing.
635 : : *
636 : : * Router Reachability Probe MUST be rate-limited
637 : : * to no more than one per minute.
638 : : */
639 : : if (!fib6_nh->fib_nh_gw_family)
640 : : return;
641 : :
642 : : nh_gw = &fib6_nh->fib_nh_gw6;
643 : : dev = fib6_nh->fib_nh_dev;
644 : : rcu_read_lock_bh();
645 : : last_probe = READ_ONCE(fib6_nh->last_probe);
646 : : idev = __in6_dev_get(dev);
647 : : neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
648 : : if (neigh) {
649 : : if (neigh->nud_state & NUD_VALID)
650 : : goto out;
651 : :
652 : : write_lock(&neigh->lock);
653 : : if (!(neigh->nud_state & NUD_VALID) &&
654 : : time_after(jiffies,
655 : : neigh->updated + idev->cnf.rtr_probe_interval)) {
656 : : work = kmalloc(sizeof(*work), GFP_ATOMIC);
657 : : if (work)
658 : : __neigh_set_probe_once(neigh);
659 : : }
660 : : write_unlock(&neigh->lock);
661 : : } else if (time_after(jiffies, last_probe +
662 : : idev->cnf.rtr_probe_interval)) {
663 : : work = kmalloc(sizeof(*work), GFP_ATOMIC);
664 : : }
665 : :
666 : : if (!work || cmpxchg(&fib6_nh->last_probe,
667 : : last_probe, jiffies) != last_probe) {
668 : : kfree(work);
669 : : } else {
670 : : INIT_WORK(&work->work, rt6_probe_deferred);
671 : : work->target = *nh_gw;
672 : : dev_hold(dev);
673 : : work->dev = dev;
674 : : schedule_work(&work->work);
675 : : }
676 : :
677 : : out:
678 : : rcu_read_unlock_bh();
679 : : }
680 : : #else
681 : : static inline void rt6_probe(struct fib6_nh *fib6_nh)
682 : : {
683 : : }
684 : : #endif
685 : :
686 : : /*
687 : : * Default Router Selection (RFC 2461 6.3.6)
688 : : */
689 : 0 : static enum rt6_nud_state rt6_check_neigh(const struct fib6_nh *fib6_nh)
690 : : {
691 : 0 : enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
692 : 0 : struct neighbour *neigh;
693 : :
694 : 0 : rcu_read_lock_bh();
695 : 0 : neigh = __ipv6_neigh_lookup_noref(fib6_nh->fib_nh_dev,
696 : 0 : &fib6_nh->fib_nh_gw6);
697 [ # # ]: 0 : if (neigh) {
698 : 0 : read_lock(&neigh->lock);
699 [ # # ]: 0 : if (neigh->nud_state & NUD_VALID)
700 : 0 : ret = RT6_NUD_SUCCEED;
701 : : #ifdef CONFIG_IPV6_ROUTER_PREF
702 : : else if (!(neigh->nud_state & NUD_FAILED))
703 : : ret = RT6_NUD_SUCCEED;
704 : : else
705 : : ret = RT6_NUD_FAIL_PROBE;
706 : : #endif
707 : 0 : read_unlock(&neigh->lock);
708 : : } else {
709 : : ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
710 : : RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
711 : : }
712 : 0 : rcu_read_unlock_bh();
713 : :
714 : 0 : return ret;
715 : : }
716 : :
717 : 156 : static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
718 : : int strict)
719 : : {
720 : 156 : int m = 0;
721 : :
722 [ - + - - ]: 156 : if (!oif || nh->fib_nh_dev->ifindex == oif)
723 : : m = 2;
724 : :
725 [ # # ]: 0 : if (!m && (strict & RT6_LOOKUP_F_IFACE))
726 : : return RT6_NUD_FAIL_HARD;
727 : : #ifdef CONFIG_IPV6_ROUTER_PREF
728 : : m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(fib6_flags)) << 2;
729 : : #endif
730 [ + - ]: 156 : if ((strict & RT6_LOOKUP_F_REACHABLE) &&
731 [ - + - - ]: 156 : !(fib6_flags & RTF_NONEXTHOP) && nh->fib_nh_gw_family) {
732 : 0 : int n = rt6_check_neigh(nh);
733 [ # # ]: 0 : if (n < 0)
734 : 0 : return n;
735 : : }
736 : : return m;
737 : : }
738 : :
739 : 156 : static bool find_match(struct fib6_nh *nh, u32 fib6_flags,
740 : : int oif, int strict, int *mpri, bool *do_rr)
741 : : {
742 : 156 : bool match_do_rr = false;
743 : 156 : bool rc = false;
744 : 156 : int m;
745 : :
746 [ - + ]: 156 : if (nh->fib_nh_flags & RTNH_F_DEAD)
747 : 0 : goto out;
748 : :
749 [ - + - - ]: 156 : if (ip6_ignore_linkdown(nh->fib_nh_dev) &&
750 : 0 : nh->fib_nh_flags & RTNH_F_LINKDOWN &&
751 [ # # ]: 0 : !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
752 : 0 : goto out;
753 : :
754 : 156 : m = rt6_score_route(nh, fib6_flags, oif, strict);
755 [ + - ]: 156 : if (m == RT6_NUD_FAIL_DO_RR) {
756 : : match_do_rr = true;
757 : : m = 0; /* lowest valid score */
758 [ - + ]: 156 : } else if (m == RT6_NUD_FAIL_HARD) {
759 : 0 : goto out;
760 : : }
761 : :
762 : 156 : if (strict & RT6_LOOKUP_F_REACHABLE)
763 : : rt6_probe(nh);
764 : :
765 : : /* note that m can be RT6_NUD_FAIL_PROBE at this point */
766 [ - + ]: 156 : if (m > *mpri) {
767 : 156 : *do_rr = match_do_rr;
768 : 156 : *mpri = m;
769 : 156 : rc = true;
770 : : }
771 : 0 : out:
772 : 156 : return rc;
773 : : }
774 : :
775 : : struct fib6_nh_frl_arg {
776 : : u32 flags;
777 : : int oif;
778 : : int strict;
779 : : int *mpri;
780 : : bool *do_rr;
781 : : struct fib6_nh *nh;
782 : : };
783 : :
784 : 0 : static int rt6_nh_find_match(struct fib6_nh *nh, void *_arg)
785 : : {
786 : 0 : struct fib6_nh_frl_arg *arg = _arg;
787 : :
788 : 0 : arg->nh = nh;
789 : 0 : return find_match(nh, arg->flags, arg->oif, arg->strict,
790 : : arg->mpri, arg->do_rr);
791 : : }
792 : :
793 : 312 : static void __find_rr_leaf(struct fib6_info *f6i_start,
794 : : struct fib6_info *nomatch, u32 metric,
795 : : struct fib6_result *res, struct fib6_info **cont,
796 : : int oif, int strict, bool *do_rr, int *mpri)
797 : : {
798 : 312 : struct fib6_info *f6i;
799 : :
800 : 312 : for (f6i = f6i_start;
801 [ + + ]: 468 : f6i && f6i != nomatch;
802 : 156 : f6i = rcu_dereference(f6i->fib6_next)) {
803 : 312 : bool matched = false;
804 : 312 : struct fib6_nh *nh;
805 : :
806 [ + - + + ]: 312 : if (cont && f6i->fib6_metric != metric) {
807 : 156 : *cont = f6i;
808 : 156 : return;
809 : : }
810 : :
811 [ - + - - ]: 156 : if (fib6_check_expired(f6i))
812 : 0 : continue;
813 : :
814 [ - + ]: 156 : if (unlikely(f6i->nh)) {
815 : 0 : struct fib6_nh_frl_arg arg = {
816 : : .flags = f6i->fib6_flags,
817 : : .oif = oif,
818 : : .strict = strict,
819 : : .mpri = mpri,
820 : : .do_rr = do_rr
821 : : };
822 : :
823 [ # # ]: 0 : if (nexthop_is_blackhole(f6i->nh)) {
824 : 0 : res->fib6_flags = RTF_REJECT;
825 : 0 : res->fib6_type = RTN_BLACKHOLE;
826 : 0 : res->f6i = f6i;
827 [ # # ]: 0 : res->nh = nexthop_fib6_nh(f6i->nh);
828 : 0 : return;
829 : : }
830 [ # # ]: 0 : if (nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_find_match,
831 : : &arg)) {
832 : 0 : matched = true;
833 : 0 : nh = arg.nh;
834 : : }
835 : : } else {
836 : 156 : nh = f6i->fib6_nh;
837 [ + - ]: 156 : if (find_match(nh, f6i->fib6_flags, oif, strict,
838 : : mpri, do_rr))
839 : : matched = true;
840 : : }
841 : 0 : if (matched) {
842 : 156 : res->f6i = f6i;
843 : 156 : res->nh = nh;
844 : 156 : res->fib6_flags = f6i->fib6_flags;
845 : 156 : res->fib6_type = f6i->fib6_type;
846 : : }
847 : : }
848 : : }
849 : :
850 : : static void find_rr_leaf(struct fib6_node *fn, struct fib6_info *leaf,
851 : : struct fib6_info *rr_head, int oif, int strict,
852 : : bool *do_rr, struct fib6_result *res)
853 : : {
854 : : u32 metric = rr_head->fib6_metric;
855 : : struct fib6_info *cont = NULL;
856 : : int mpri = -1;
857 : :
858 : : __find_rr_leaf(rr_head, NULL, metric, res, &cont,
859 : : oif, strict, do_rr, &mpri);
860 : :
861 : : __find_rr_leaf(leaf, rr_head, metric, res, &cont,
862 : : oif, strict, do_rr, &mpri);
863 : :
864 : : if (res->f6i || !cont)
865 : : return;
866 : :
867 : : __find_rr_leaf(cont, NULL, metric, res, NULL,
868 : : oif, strict, do_rr, &mpri);
869 : : }
870 : :
871 : : static void rt6_select(struct net *net, struct fib6_node *fn, int oif,
872 : : struct fib6_result *res, int strict)
873 : : {
874 : : struct fib6_info *leaf = rcu_dereference(fn->leaf);
875 : : struct fib6_info *rt0;
876 : : bool do_rr = false;
877 : : int key_plen;
878 : :
879 : : /* make sure this function or its helpers sets f6i */
880 : : res->f6i = NULL;
881 : :
882 : : if (!leaf || leaf == net->ipv6.fib6_null_entry)
883 : : goto out;
884 : :
885 : : rt0 = rcu_dereference(fn->rr_ptr);
886 : : if (!rt0)
887 : : rt0 = leaf;
888 : :
889 : : /* Double check to make sure fn is not an intermediate node
890 : : * and fn->leaf does not points to its child's leaf
891 : : * (This might happen if all routes under fn are deleted from
892 : : * the tree and fib6_repair_tree() is called on the node.)
893 : : */
894 : : key_plen = rt0->fib6_dst.plen;
895 : : #ifdef CONFIG_IPV6_SUBTREES
896 : : if (rt0->fib6_src.plen)
897 : : key_plen = rt0->fib6_src.plen;
898 : : #endif
899 : : if (fn->fn_bit != key_plen)
900 : : goto out;
901 : :
902 : : find_rr_leaf(fn, leaf, rt0, oif, strict, &do_rr, res);
903 : : if (do_rr) {
904 : : struct fib6_info *next = rcu_dereference(rt0->fib6_next);
905 : :
906 : : /* no entries matched; do round-robin */
907 : : if (!next || next->fib6_metric != rt0->fib6_metric)
908 : : next = leaf;
909 : :
910 : : if (next != rt0) {
911 : : spin_lock_bh(&leaf->fib6_table->tb6_lock);
912 : : /* make sure next is not being deleted from the tree */
913 : : if (next->fib6_node)
914 : : rcu_assign_pointer(fn->rr_ptr, next);
915 : : spin_unlock_bh(&leaf->fib6_table->tb6_lock);
916 : : }
917 : : }
918 : :
919 : : out:
920 : : if (!res->f6i) {
921 : : res->f6i = net->ipv6.fib6_null_entry;
922 : : res->nh = res->f6i->fib6_nh;
923 : : res->fib6_flags = res->f6i->fib6_flags;
924 : : res->fib6_type = res->f6i->fib6_type;
925 : : }
926 : : }
927 : :
928 : : static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res)
929 : : {
930 : : return (res->f6i->fib6_flags & RTF_NONEXTHOP) ||
931 : : res->nh->fib_nh_gw_family;
932 : : }
933 : :
934 : : #ifdef CONFIG_IPV6_ROUTE_INFO
935 : : int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
936 : : const struct in6_addr *gwaddr)
937 : : {
938 : : struct net *net = dev_net(dev);
939 : : struct route_info *rinfo = (struct route_info *) opt;
940 : : struct in6_addr prefix_buf, *prefix;
941 : : unsigned int pref;
942 : : unsigned long lifetime;
943 : : struct fib6_info *rt;
944 : :
945 : : if (len < sizeof(struct route_info)) {
946 : : return -EINVAL;
947 : : }
948 : :
949 : : /* Sanity check for prefix_len and length */
950 : : if (rinfo->length > 3) {
951 : : return -EINVAL;
952 : : } else if (rinfo->prefix_len > 128) {
953 : : return -EINVAL;
954 : : } else if (rinfo->prefix_len > 64) {
955 : : if (rinfo->length < 2) {
956 : : return -EINVAL;
957 : : }
958 : : } else if (rinfo->prefix_len > 0) {
959 : : if (rinfo->length < 1) {
960 : : return -EINVAL;
961 : : }
962 : : }
963 : :
964 : : pref = rinfo->route_pref;
965 : : if (pref == ICMPV6_ROUTER_PREF_INVALID)
966 : : return -EINVAL;
967 : :
968 : : lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
969 : :
970 : : if (rinfo->length == 3)
971 : : prefix = (struct in6_addr *)rinfo->prefix;
972 : : else {
973 : : /* this function is safe */
974 : : ipv6_addr_prefix(&prefix_buf,
975 : : (struct in6_addr *)rinfo->prefix,
976 : : rinfo->prefix_len);
977 : : prefix = &prefix_buf;
978 : : }
979 : :
980 : : if (rinfo->prefix_len == 0)
981 : : rt = rt6_get_dflt_router(net, gwaddr, dev);
982 : : else
983 : : rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
984 : : gwaddr, dev);
985 : :
986 : : if (rt && !lifetime) {
987 : : ip6_del_rt(net, rt);
988 : : rt = NULL;
989 : : }
990 : :
991 : : if (!rt && lifetime)
992 : : rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
993 : : dev, pref);
994 : : else if (rt)
995 : : rt->fib6_flags = RTF_ROUTEINFO |
996 : : (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
997 : :
998 : : if (rt) {
999 : : if (!addrconf_finite_timeout(lifetime))
1000 : : fib6_clean_expires(rt);
1001 : : else
1002 : : fib6_set_expires(rt, jiffies + HZ * lifetime);
1003 : :
1004 : : fib6_info_release(rt);
1005 : : }
1006 : : return 0;
1007 : : }
1008 : : #endif
1009 : :
1010 : : /*
1011 : : * Misc support functions
1012 : : */
1013 : :
1014 : : /* called with rcu_lock held */
1015 : 78 : static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
1016 : : {
1017 : 78 : struct net_device *dev = res->nh->fib_nh_dev;
1018 : :
1019 [ + - ]: 78 : if (res->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
1020 : : /* for copies of local routes, dst->dev needs to be the
1021 : : * device if it is a master device, the master device if
1022 : : * device is enslaved, and the loopback as the default
1023 : : */
1024 [ - + - - ]: 78 : if (netif_is_l3_slave(dev) &&
1025 : 0 : !rt6_need_strict(&res->f6i->fib6_dst.addr))
1026 : : dev = l3mdev_master_dev_rcu(dev);
1027 [ + - ]: 78 : else if (!netif_is_l3_master(dev))
1028 : 78 : dev = dev_net(dev)->loopback_dev;
1029 : : /* last case is netif_is_l3_master(dev) is true in which
1030 : : * case we want dev returned to be dev
1031 : : */
1032 : : }
1033 : :
1034 : 78 : return dev;
1035 : : }
1036 : :
1037 : : static const int fib6_prop[RTN_MAX + 1] = {
1038 : : [RTN_UNSPEC] = 0,
1039 : : [RTN_UNICAST] = 0,
1040 : : [RTN_LOCAL] = 0,
1041 : : [RTN_BROADCAST] = 0,
1042 : : [RTN_ANYCAST] = 0,
1043 : : [RTN_MULTICAST] = 0,
1044 : : [RTN_BLACKHOLE] = -EINVAL,
1045 : : [RTN_UNREACHABLE] = -EHOSTUNREACH,
1046 : : [RTN_PROHIBIT] = -EACCES,
1047 : : [RTN_THROW] = -EAGAIN,
1048 : : [RTN_NAT] = -EINVAL,
1049 : : [RTN_XRESOLVE] = -EINVAL,
1050 : : };
1051 : :
1052 : 0 : static int ip6_rt_type_to_error(u8 fib6_type)
1053 : : {
1054 [ # # # # ]: 0 : return fib6_prop[fib6_type];
1055 : : }
1056 : :
1057 : 78 : static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
1058 : : {
1059 : 78 : unsigned short flags = 0;
1060 : :
1061 : 78 : if (rt->dst_nocount)
1062 : 78 : flags |= DST_NOCOUNT;
1063 [ - + - - ]: 78 : if (rt->dst_nopolicy)
1064 : 0 : flags |= DST_NOPOLICY;
1065 [ + - - - ]: 78 : if (rt->dst_host)
1066 : 78 : flags |= DST_HOST;
1067 : :
1068 : 78 : return flags;
1069 : : }
1070 : :
1071 : 0 : static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type)
1072 : : {
1073 : 0 : rt->dst.error = ip6_rt_type_to_error(fib6_type);
1074 : :
1075 : 0 : switch (fib6_type) {
1076 : 0 : case RTN_BLACKHOLE:
1077 : 0 : rt->dst.output = dst_discard_out;
1078 : 0 : rt->dst.input = dst_discard;
1079 : 0 : break;
1080 : 0 : case RTN_PROHIBIT:
1081 : 0 : rt->dst.output = ip6_pkt_prohibit_out;
1082 : 0 : rt->dst.input = ip6_pkt_prohibit;
1083 : 0 : break;
1084 : 0 : case RTN_THROW:
1085 : : case RTN_UNREACHABLE:
1086 : : default:
1087 : 0 : rt->dst.output = ip6_pkt_discard_out;
1088 : 0 : rt->dst.input = ip6_pkt_discard;
1089 : 0 : break;
1090 : : }
1091 : : }
1092 : :
1093 : 78 : static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res)
1094 : : {
1095 : 78 : struct fib6_info *f6i = res->f6i;
1096 : :
1097 [ - + ]: 78 : if (res->fib6_flags & RTF_REJECT) {
1098 [ # # # ]: 0 : ip6_rt_init_dst_reject(rt, res->fib6_type);
1099 : 0 : return;
1100 : : }
1101 : :
1102 : 78 : rt->dst.error = 0;
1103 : 78 : rt->dst.output = ip6_output;
1104 : :
1105 [ + - ]: 78 : if (res->fib6_type == RTN_LOCAL || res->fib6_type == RTN_ANYCAST) {
1106 : 78 : rt->dst.input = ip6_input;
1107 [ # # ]: 0 : } else if (ipv6_addr_type(&f6i->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
1108 : 0 : rt->dst.input = ip6_mc_input;
1109 : : } else {
1110 : 0 : rt->dst.input = ip6_forward;
1111 : : }
1112 : :
1113 [ - + ]: 78 : if (res->nh->fib_nh_lws) {
1114 : 0 : rt->dst.lwtstate = lwtstate_get(res->nh->fib_nh_lws);
1115 : 0 : lwtunnel_set_redirect(&rt->dst);
1116 : : }
1117 : :
1118 : 78 : rt->dst.lastuse = jiffies;
1119 : : }
1120 : :
1121 : : /* Caller must already hold reference to @from */
1122 : 78 : static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
1123 : : {
1124 : 78 : rt->rt6i_flags &= ~RTF_EXPIRES;
1125 [ - + ]: 78 : rcu_assign_pointer(rt->from, from);
1126 [ - + ]: 78 : ip_dst_init_metrics(&rt->dst, from->fib6_metrics);
1127 : 78 : }
1128 : :
1129 : : /* Caller must already hold reference to f6i in result */
1130 : 78 : static void ip6_rt_copy_init(struct rt6_info *rt, const struct fib6_result *res)
1131 : : {
1132 : 78 : const struct fib6_nh *nh = res->nh;
1133 : 78 : const struct net_device *dev = nh->fib_nh_dev;
1134 : 78 : struct fib6_info *f6i = res->f6i;
1135 : :
1136 : 78 : ip6_rt_init_dst(rt, res);
1137 : :
1138 : 78 : rt->rt6i_dst = f6i->fib6_dst;
1139 [ + - ]: 78 : rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
1140 : 78 : rt->rt6i_flags = res->fib6_flags;
1141 [ - + ]: 78 : if (nh->fib_nh_gw_family) {
1142 : 0 : rt->rt6i_gateway = nh->fib_nh_gw6;
1143 : 0 : rt->rt6i_flags |= RTF_GATEWAY;
1144 : : }
1145 : 78 : rt6_set_from(rt, f6i);
1146 : : #ifdef CONFIG_IPV6_SUBTREES
1147 : : rt->rt6i_src = f6i->fib6_src;
1148 : : #endif
1149 : 78 : }
1150 : :
1151 : : static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
1152 : : struct in6_addr *saddr)
1153 : : {
1154 : 0 : struct fib6_node *pn, *sn;
1155 : 0 : while (1) {
1156 [ # # # # : 0 : if (fn->fn_flags & RTN_TL_ROOT)
# # ]
1157 : : return NULL;
1158 [ # # # # : 0 : pn = rcu_dereference(fn->parent);
# # ]
1159 : 0 : sn = FIB6_SUBTREE(pn);
1160 : 0 : if (sn && sn != fn)
1161 : : fn = fib6_node_lookup(sn, NULL, saddr);
1162 : : else
1163 : 0 : fn = pn;
1164 [ # # # # : 0 : if (fn->fn_flags & RTN_RTINFO)
# # ]
1165 : : return fn;
1166 : : }
1167 : : }
1168 : :
1169 : 0 : static bool ip6_hold_safe(struct net *net, struct rt6_info **prt)
1170 : : {
1171 : 0 : struct rt6_info *rt = *prt;
1172 : :
1173 [ # # ]: 0 : if (dst_hold_safe(&rt->dst))
1174 : : return true;
1175 [ # # ]: 0 : if (net) {
1176 : 0 : rt = net->ipv6.ip6_null_entry;
1177 : 0 : dst_hold(&rt->dst);
1178 : : } else {
1179 : : rt = NULL;
1180 : : }
1181 : 0 : *prt = rt;
1182 : 0 : return false;
1183 : : }
1184 : :
1185 : : /* called with rcu_lock held */
1186 : 0 : static struct rt6_info *ip6_create_rt_rcu(const struct fib6_result *res)
1187 : : {
1188 : 0 : struct net_device *dev = res->nh->fib_nh_dev;
1189 : 0 : struct fib6_info *f6i = res->f6i;
1190 : 0 : unsigned short flags;
1191 : 0 : struct rt6_info *nrt;
1192 : :
1193 [ # # ]: 0 : if (!fib6_info_hold_safe(f6i))
1194 : 0 : goto fallback;
1195 : :
1196 [ # # ]: 0 : flags = fib6_info_dst_flags(f6i);
1197 : 0 : nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
1198 [ # # ]: 0 : if (!nrt) {
1199 : 0 : fib6_info_release(f6i);
1200 : 0 : goto fallback;
1201 : : }
1202 : :
1203 : 0 : ip6_rt_copy_init(nrt, res);
1204 : 0 : return nrt;
1205 : :
1206 : 0 : fallback:
1207 : 0 : nrt = dev_net(dev)->ipv6.ip6_null_entry;
1208 : 0 : dst_hold(&nrt->dst);
1209 : 0 : return nrt;
1210 : : }
1211 : :
1212 : 0 : static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1213 : : struct fib6_table *table,
1214 : : struct flowi6 *fl6,
1215 : : const struct sk_buff *skb,
1216 : : int flags)
1217 : : {
1218 : 0 : struct fib6_result res = {};
1219 : 0 : struct fib6_node *fn;
1220 : 0 : struct rt6_info *rt;
1221 : :
1222 [ # # ]: 0 : if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1223 : 0 : flags &= ~RT6_LOOKUP_F_IFACE;
1224 : :
1225 : 0 : rcu_read_lock();
1226 : 0 : fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1227 : 0 : restart:
1228 [ # # ]: 0 : res.f6i = rcu_dereference(fn->leaf);
1229 [ # # ]: 0 : if (!res.f6i)
1230 : 0 : res.f6i = net->ipv6.fib6_null_entry;
1231 : : else
1232 : 0 : rt6_device_match(net, &res, &fl6->saddr, fl6->flowi6_oif,
1233 : : flags);
1234 : :
1235 [ # # ]: 0 : if (res.f6i == net->ipv6.fib6_null_entry) {
1236 : : fn = fib6_backtrack(fn, &fl6->saddr);
1237 [ # # ]: 0 : if (fn)
1238 : 0 : goto restart;
1239 : :
1240 : 0 : rt = net->ipv6.ip6_null_entry;
1241 : 0 : dst_hold(&rt->dst);
1242 : 0 : goto out;
1243 [ # # ]: 0 : } else if (res.fib6_flags & RTF_REJECT) {
1244 : 0 : goto do_create;
1245 : : }
1246 : :
1247 : 0 : fib6_select_path(net, &res, fl6, fl6->flowi6_oif,
1248 : 0 : fl6->flowi6_oif != 0, skb, flags);
1249 : :
1250 : : /* Search through exception table */
1251 : 0 : rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
1252 [ # # ]: 0 : if (rt) {
1253 [ # # ]: 0 : if (ip6_hold_safe(net, &rt))
1254 [ # # ]: 0 : dst_use_noref(&rt->dst, jiffies);
1255 : : } else {
1256 : 0 : do_create:
1257 : 0 : rt = ip6_create_rt_rcu(&res);
1258 : : }
1259 : :
1260 : 0 : out:
1261 : 0 : trace_fib6_table_lookup(net, &res, table, fl6);
1262 : :
1263 : 0 : rcu_read_unlock();
1264 : :
1265 : 0 : return rt;
1266 : : }
1267 : :
1268 : 0 : struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
1269 : : const struct sk_buff *skb, int flags)
1270 : : {
1271 : 0 : return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
1272 : : }
1273 : : EXPORT_SYMBOL_GPL(ip6_route_lookup);
1274 : :
1275 : 0 : struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
1276 : : const struct in6_addr *saddr, int oif,
1277 : : const struct sk_buff *skb, int strict)
1278 : : {
1279 : 0 : struct flowi6 fl6 = {
1280 : : .flowi6_oif = oif,
1281 : : .daddr = *daddr,
1282 : : };
1283 : 0 : struct dst_entry *dst;
1284 : 0 : int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
1285 : :
1286 [ # # ]: 0 : if (saddr) {
1287 : 0 : memcpy(&fl6.saddr, saddr, sizeof(*saddr));
1288 : 0 : flags |= RT6_LOOKUP_F_HAS_SADDR;
1289 : : }
1290 : :
1291 : 0 : dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
1292 [ # # ]: 0 : if (dst->error == 0)
1293 : : return (struct rt6_info *) dst;
1294 : :
1295 : 0 : dst_release(dst);
1296 : :
1297 : 0 : return NULL;
1298 : : }
1299 : : EXPORT_SYMBOL(rt6_lookup);
1300 : :
1301 : : /* ip6_ins_rt is called with FREE table->tb6_lock.
1302 : : * It takes new route entry, the addition fails by any reason the
1303 : : * route is released.
1304 : : * Caller must hold dst before calling it.
1305 : : */
1306 : :
1307 : 240 : static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
1308 : : struct netlink_ext_ack *extack)
1309 : : {
1310 : 240 : int err;
1311 : 240 : struct fib6_table *table;
1312 : :
1313 : 240 : table = rt->fib6_table;
1314 : 240 : spin_lock_bh(&table->tb6_lock);
1315 : 240 : err = fib6_add(&table->tb6_root, rt, info, extack);
1316 : 240 : spin_unlock_bh(&table->tb6_lock);
1317 : :
1318 : 240 : return err;
1319 : : }
1320 : :
1321 : 106 : int ip6_ins_rt(struct net *net, struct fib6_info *rt)
1322 : : {
1323 : 106 : struct nl_info info = { .nl_net = net, };
1324 : :
1325 : 106 : return __ip6_ins_rt(rt, &info, NULL);
1326 : : }
1327 : :
1328 : : static struct rt6_info *ip6_rt_cache_alloc(const struct fib6_result *res,
1329 : : const struct in6_addr *daddr,
1330 : : const struct in6_addr *saddr)
1331 : : {
1332 : : struct fib6_info *f6i = res->f6i;
1333 : : struct net_device *dev;
1334 : : struct rt6_info *rt;
1335 : :
1336 : : /*
1337 : : * Clone the route.
1338 : : */
1339 : :
1340 : : if (!fib6_info_hold_safe(f6i))
1341 : : return NULL;
1342 : :
1343 : : dev = ip6_rt_get_dev_rcu(res);
1344 : : rt = ip6_dst_alloc(dev_net(dev), dev, 0);
1345 : : if (!rt) {
1346 : : fib6_info_release(f6i);
1347 : : return NULL;
1348 : : }
1349 : :
1350 : : ip6_rt_copy_init(rt, res);
1351 : : rt->rt6i_flags |= RTF_CACHE;
1352 : : rt->dst.flags |= DST_HOST;
1353 : : rt->rt6i_dst.addr = *daddr;
1354 : : rt->rt6i_dst.plen = 128;
1355 : :
1356 : : if (!rt6_is_gw_or_nonexthop(res)) {
1357 : : if (f6i->fib6_dst.plen != 128 &&
1358 : : ipv6_addr_equal(&f6i->fib6_dst.addr, daddr))
1359 : : rt->rt6i_flags |= RTF_ANYCAST;
1360 : : #ifdef CONFIG_IPV6_SUBTREES
1361 : : if (rt->rt6i_src.plen && saddr) {
1362 : : rt->rt6i_src.addr = *saddr;
1363 : : rt->rt6i_src.plen = 128;
1364 : : }
1365 : : #endif
1366 : : }
1367 : :
1368 : : return rt;
1369 : : }
1370 : :
1371 : 78 : static struct rt6_info *ip6_rt_pcpu_alloc(const struct fib6_result *res)
1372 : : {
1373 : 78 : struct fib6_info *f6i = res->f6i;
1374 [ + - ]: 78 : unsigned short flags = fib6_info_dst_flags(f6i);
1375 : 78 : struct net_device *dev;
1376 : 78 : struct rt6_info *pcpu_rt;
1377 : :
1378 [ + - ]: 78 : if (!fib6_info_hold_safe(f6i))
1379 : : return NULL;
1380 : :
1381 : 78 : rcu_read_lock();
1382 : 78 : dev = ip6_rt_get_dev_rcu(res);
1383 : 78 : pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
1384 : 78 : rcu_read_unlock();
1385 [ - + ]: 78 : if (!pcpu_rt) {
1386 : 0 : fib6_info_release(f6i);
1387 : 0 : return NULL;
1388 : : }
1389 : 78 : ip6_rt_copy_init(pcpu_rt, res);
1390 : 78 : pcpu_rt->rt6i_flags |= RTF_PCPU;
1391 : 78 : return pcpu_rt;
1392 : : }
1393 : :
1394 : : /* It should be called with rcu_read_lock() acquired */
1395 : 156 : static struct rt6_info *rt6_get_pcpu_route(const struct fib6_result *res)
1396 : : {
1397 : 156 : struct rt6_info *pcpu_rt;
1398 : :
1399 : 312 : pcpu_rt = this_cpu_read(*res->nh->rt6i_pcpu);
1400 : :
1401 : 156 : return pcpu_rt;
1402 : : }
1403 : :
1404 : : static struct rt6_info *rt6_make_pcpu_route(struct net *net,
1405 : : const struct fib6_result *res)
1406 : : {
1407 : : struct rt6_info *pcpu_rt, *prev, **p;
1408 : :
1409 : : pcpu_rt = ip6_rt_pcpu_alloc(res);
1410 : : if (!pcpu_rt)
1411 : : return NULL;
1412 : :
1413 : : p = this_cpu_ptr(res->nh->rt6i_pcpu);
1414 : : prev = cmpxchg(p, NULL, pcpu_rt);
1415 : : BUG_ON(prev);
1416 : :
1417 : : if (res->f6i->fib6_destroying) {
1418 : : struct fib6_info *from;
1419 : :
1420 : : from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL);
1421 : : fib6_info_release(from);
1422 : : }
1423 : :
1424 : : return pcpu_rt;
1425 : : }
1426 : :
1427 : : /* exception hash table implementation
1428 : : */
1429 : : static DEFINE_SPINLOCK(rt6_exception_lock);
1430 : :
1431 : : /* Remove rt6_ex from hash table and free the memory
1432 : : * Caller must hold rt6_exception_lock
1433 : : */
1434 : 0 : static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1435 : : struct rt6_exception *rt6_ex)
1436 : : {
1437 : 0 : struct fib6_info *from;
1438 : 0 : struct net *net;
1439 : :
1440 [ # # ]: 0 : if (!bucket || !rt6_ex)
1441 : : return;
1442 : :
1443 : 0 : net = dev_net(rt6_ex->rt6i->dst.dev);
1444 : 0 : net->ipv6.rt6_stats->fib_rt_cache--;
1445 : :
1446 : : /* purge completely the exception to allow releasing the held resources:
1447 : : * some [sk] cache may keep the dst around for unlimited time
1448 : : */
1449 : 0 : from = xchg((__force struct fib6_info **)&rt6_ex->rt6i->from, NULL);
1450 : 0 : fib6_info_release(from);
1451 : 0 : dst_dev_put(&rt6_ex->rt6i->dst);
1452 : :
1453 [ # # ]: 0 : hlist_del_rcu(&rt6_ex->hlist);
1454 : 0 : dst_release(&rt6_ex->rt6i->dst);
1455 : 0 : kfree_rcu(rt6_ex, rcu);
1456 [ # # ]: 0 : WARN_ON_ONCE(!bucket->depth);
1457 : 0 : bucket->depth--;
1458 : : }
1459 : :
1460 : : /* Remove oldest rt6_ex in bucket and free the memory
1461 : : * Caller must hold rt6_exception_lock
1462 : : */
1463 : 0 : static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1464 : : {
1465 : 0 : struct rt6_exception *rt6_ex, *oldest = NULL;
1466 : :
1467 [ # # ]: 0 : if (!bucket)
1468 : : return;
1469 : :
1470 [ # # # # : 0 : hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
# # ]
1471 [ # # # # ]: 0 : if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1472 : : oldest = rt6_ex;
1473 : : }
1474 : 0 : rt6_remove_exception(bucket, oldest);
1475 : : }
1476 : :
1477 : : static u32 rt6_exception_hash(const struct in6_addr *dst,
1478 : : const struct in6_addr *src)
1479 : : {
1480 : : static u32 seed __read_mostly;
1481 : : u32 val;
1482 : :
1483 : : net_get_random_once(&seed, sizeof(seed));
1484 : : val = jhash2((const u32 *)dst, sizeof(*dst)/sizeof(u32), seed);
1485 : :
1486 : : #ifdef CONFIG_IPV6_SUBTREES
1487 : : if (src)
1488 : : val = jhash2((const u32 *)src, sizeof(*src)/sizeof(u32), val);
1489 : : #endif
1490 : : return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1491 : : }
1492 : :
1493 : : /* Helper function to find the cached rt in the hash table
1494 : : * and update bucket pointer to point to the bucket for this
1495 : : * (daddr, saddr) pair
1496 : : * Caller must hold rt6_exception_lock
1497 : : */
1498 : : static struct rt6_exception *
1499 : : __rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1500 : : const struct in6_addr *daddr,
1501 : : const struct in6_addr *saddr)
1502 : : {
1503 : : struct rt6_exception *rt6_ex;
1504 : : u32 hval;
1505 : :
1506 : : if (!(*bucket) || !daddr)
1507 : : return NULL;
1508 : :
1509 : : hval = rt6_exception_hash(daddr, saddr);
1510 : : *bucket += hval;
1511 : :
1512 : : hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1513 : : struct rt6_info *rt6 = rt6_ex->rt6i;
1514 : : bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1515 : :
1516 : : #ifdef CONFIG_IPV6_SUBTREES
1517 : : if (matched && saddr)
1518 : : matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1519 : : #endif
1520 : : if (matched)
1521 : : return rt6_ex;
1522 : : }
1523 : : return NULL;
1524 : : }
1525 : :
1526 : : /* Helper function to find the cached rt in the hash table
1527 : : * and update bucket pointer to point to the bucket for this
1528 : : * (daddr, saddr) pair
1529 : : * Caller must hold rcu_read_lock()
1530 : : */
1531 : : static struct rt6_exception *
1532 : : __rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1533 : : const struct in6_addr *daddr,
1534 : : const struct in6_addr *saddr)
1535 : : {
1536 : : struct rt6_exception *rt6_ex;
1537 : : u32 hval;
1538 : :
1539 : : WARN_ON_ONCE(!rcu_read_lock_held());
1540 : :
1541 : : if (!(*bucket) || !daddr)
1542 : : return NULL;
1543 : :
1544 : : hval = rt6_exception_hash(daddr, saddr);
1545 : : *bucket += hval;
1546 : :
1547 : : hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1548 : : struct rt6_info *rt6 = rt6_ex->rt6i;
1549 : : bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1550 : :
1551 : : #ifdef CONFIG_IPV6_SUBTREES
1552 : : if (matched && saddr)
1553 : : matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1554 : : #endif
1555 : : if (matched)
1556 : : return rt6_ex;
1557 : : }
1558 : : return NULL;
1559 : : }
1560 : :
1561 : 0 : static unsigned int fib6_mtu(const struct fib6_result *res)
1562 : : {
1563 : 0 : const struct fib6_nh *nh = res->nh;
1564 : 0 : unsigned int mtu;
1565 : :
1566 [ # # ]: 0 : if (res->f6i->fib6_pmtu) {
1567 : : mtu = res->f6i->fib6_pmtu;
1568 : : } else {
1569 : 0 : struct net_device *dev = nh->fib_nh_dev;
1570 : 0 : struct inet6_dev *idev;
1571 : :
1572 : 0 : rcu_read_lock();
1573 : 0 : idev = __in6_dev_get(dev);
1574 : 0 : mtu = idev->cnf.mtu6;
1575 : 0 : rcu_read_unlock();
1576 : : }
1577 : :
1578 : 0 : mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1579 : :
1580 [ # # ]: 0 : return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu);
1581 : : }
1582 : :
1583 : : #define FIB6_EXCEPTION_BUCKET_FLUSHED 0x1UL
1584 : :
1585 : : /* used when the flushed bit is not relevant, only access to the bucket
1586 : : * (ie., all bucket users except rt6_insert_exception);
1587 : : *
1588 : : * called under rcu lock; sometimes called with rt6_exception_lock held
1589 : : */
1590 : : static
1591 : 312 : struct rt6_exception_bucket *fib6_nh_get_excptn_bucket(const struct fib6_nh *nh,
1592 : : spinlock_t *lock)
1593 : : {
1594 : 312 : struct rt6_exception_bucket *bucket;
1595 : :
1596 : 312 : if (lock)
1597 : 156 : bucket = rcu_dereference_protected(nh->rt6i_exception_bucket,
1598 : : lockdep_is_held(lock));
1599 : : else
1600 : 156 : bucket = rcu_dereference(nh->rt6i_exception_bucket);
1601 : :
1602 : : /* remove bucket flushed bit if set */
1603 [ - - - + ]: 156 : if (bucket) {
1604 : 0 : unsigned long p = (unsigned long)bucket;
1605 : :
1606 : 0 : p &= ~FIB6_EXCEPTION_BUCKET_FLUSHED;
1607 : 0 : bucket = (struct rt6_exception_bucket *)p;
1608 : : }
1609 : :
1610 : 312 : return bucket;
1611 : : }
1612 : :
1613 : 0 : static bool fib6_nh_excptn_bucket_flushed(struct rt6_exception_bucket *bucket)
1614 : : {
1615 : 0 : unsigned long p = (unsigned long)bucket;
1616 : :
1617 : 0 : return !!(p & FIB6_EXCEPTION_BUCKET_FLUSHED);
1618 : : }
1619 : :
1620 : : /* called with rt6_exception_lock held */
1621 : 0 : static void fib6_nh_excptn_bucket_set_flushed(struct fib6_nh *nh,
1622 : : spinlock_t *lock)
1623 : : {
1624 : 0 : struct rt6_exception_bucket *bucket;
1625 : 0 : unsigned long p;
1626 : :
1627 : 0 : bucket = rcu_dereference_protected(nh->rt6i_exception_bucket,
1628 : : lockdep_is_held(lock));
1629 : :
1630 : 0 : p = (unsigned long)bucket;
1631 : 0 : p |= FIB6_EXCEPTION_BUCKET_FLUSHED;
1632 : 0 : bucket = (struct rt6_exception_bucket *)p;
1633 : 0 : rcu_assign_pointer(nh->rt6i_exception_bucket, bucket);
1634 : 0 : }
1635 : :
1636 : 0 : static int rt6_insert_exception(struct rt6_info *nrt,
1637 : : const struct fib6_result *res)
1638 : : {
1639 : 0 : struct net *net = dev_net(nrt->dst.dev);
1640 : 0 : struct rt6_exception_bucket *bucket;
1641 : 0 : struct fib6_info *f6i = res->f6i;
1642 : 0 : struct in6_addr *src_key = NULL;
1643 : 0 : struct rt6_exception *rt6_ex;
1644 : 0 : struct fib6_nh *nh = res->nh;
1645 : 0 : int err = 0;
1646 : :
1647 : 0 : spin_lock_bh(&rt6_exception_lock);
1648 : :
1649 : 0 : bucket = rcu_dereference_protected(nh->rt6i_exception_bucket,
1650 : : lockdep_is_held(&rt6_exception_lock));
1651 [ # # ]: 0 : if (!bucket) {
1652 : 0 : bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1653 : : GFP_ATOMIC);
1654 [ # # ]: 0 : if (!bucket) {
1655 : 0 : err = -ENOMEM;
1656 : 0 : goto out;
1657 : : }
1658 : 0 : rcu_assign_pointer(nh->rt6i_exception_bucket, bucket);
1659 [ # # ]: 0 : } else if (fib6_nh_excptn_bucket_flushed(bucket)) {
1660 : 0 : err = -EINVAL;
1661 : 0 : goto out;
1662 : : }
1663 : :
1664 : : #ifdef CONFIG_IPV6_SUBTREES
1665 : : /* fib6_src.plen != 0 indicates f6i is in subtree
1666 : : * and exception table is indexed by a hash of
1667 : : * both fib6_dst and fib6_src.
1668 : : * Otherwise, the exception table is indexed by
1669 : : * a hash of only fib6_dst.
1670 : : */
1671 : : if (f6i->fib6_src.plen)
1672 : : src_key = &nrt->rt6i_src.addr;
1673 : : #endif
1674 : : /* rt6_mtu_change() might lower mtu on f6i.
1675 : : * Only insert this exception route if its mtu
1676 : : * is less than f6i's mtu value.
1677 : : */
1678 [ # # # # ]: 0 : if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(res)) {
1679 : 0 : err = -EINVAL;
1680 : 0 : goto out;
1681 : : }
1682 : :
1683 : 0 : rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1684 : : src_key);
1685 [ # # ]: 0 : if (rt6_ex)
1686 : 0 : rt6_remove_exception(bucket, rt6_ex);
1687 : :
1688 : 0 : rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1689 [ # # ]: 0 : if (!rt6_ex) {
1690 : 0 : err = -ENOMEM;
1691 : 0 : goto out;
1692 : : }
1693 : 0 : rt6_ex->rt6i = nrt;
1694 : 0 : rt6_ex->stamp = jiffies;
1695 : 0 : hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1696 : 0 : bucket->depth++;
1697 : 0 : net->ipv6.rt6_stats->fib_rt_cache++;
1698 : :
1699 [ # # ]: 0 : if (bucket->depth > FIB6_MAX_DEPTH)
1700 : 0 : rt6_exception_remove_oldest(bucket);
1701 : :
1702 : 0 : out:
1703 : 0 : spin_unlock_bh(&rt6_exception_lock);
1704 : :
1705 : : /* Update fn->fn_sernum to invalidate all cached dst */
1706 [ # # ]: 0 : if (!err) {
1707 : 0 : spin_lock_bh(&f6i->fib6_table->tb6_lock);
1708 : 0 : fib6_update_sernum(net, f6i);
1709 : 0 : spin_unlock_bh(&f6i->fib6_table->tb6_lock);
1710 : 0 : fib6_force_start_gc(net);
1711 : : }
1712 : :
1713 : 0 : return err;
1714 : : }
1715 : :
1716 : 156 : static void fib6_nh_flush_exceptions(struct fib6_nh *nh, struct fib6_info *from)
1717 : : {
1718 : 156 : struct rt6_exception_bucket *bucket;
1719 : 156 : struct rt6_exception *rt6_ex;
1720 : 156 : struct hlist_node *tmp;
1721 : 156 : int i;
1722 : :
1723 : 156 : spin_lock_bh(&rt6_exception_lock);
1724 : :
1725 [ - + ]: 156 : bucket = fib6_nh_get_excptn_bucket(nh, &rt6_exception_lock);
1726 [ + - ]: 156 : if (!bucket)
1727 : 156 : goto out;
1728 : :
1729 : : /* Prevent rt6_insert_exception() to recreate the bucket list */
1730 [ # # ]: 0 : if (!from)
1731 : 0 : fib6_nh_excptn_bucket_set_flushed(nh, &rt6_exception_lock);
1732 : :
1733 [ # # ]: 0 : for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1734 [ # # # # : 0 : hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist) {
# # ]
1735 [ # # # # ]: 0 : if (!from ||
1736 [ # # ]: 0 : rcu_access_pointer(rt6_ex->rt6i->from) == from)
1737 : 0 : rt6_remove_exception(bucket, rt6_ex);
1738 : : }
1739 [ # # # # : 0 : WARN_ON_ONCE(!from && bucket->depth);
# # ]
1740 : 0 : bucket++;
1741 : : }
1742 : 0 : out:
1743 : 156 : spin_unlock_bh(&rt6_exception_lock);
1744 : 156 : }
1745 : :
1746 : 0 : static int rt6_nh_flush_exceptions(struct fib6_nh *nh, void *arg)
1747 : : {
1748 : 0 : struct fib6_info *f6i = arg;
1749 : :
1750 : 0 : fib6_nh_flush_exceptions(nh, f6i);
1751 : :
1752 : 0 : return 0;
1753 : : }
1754 : :
1755 : 0 : void rt6_flush_exceptions(struct fib6_info *f6i)
1756 : : {
1757 [ # # ]: 0 : if (f6i->nh)
1758 : 0 : nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_flush_exceptions,
1759 : : f6i);
1760 : : else
1761 : 0 : fib6_nh_flush_exceptions(f6i->fib6_nh, f6i);
1762 : 0 : }
1763 : :
1764 : : /* Find cached rt in the hash table inside passed in rt
1765 : : * Caller has to hold rcu_read_lock()
1766 : : */
1767 : : static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
1768 : : const struct in6_addr *daddr,
1769 : : const struct in6_addr *saddr)
1770 : : {
1771 : : const struct in6_addr *src_key = NULL;
1772 : : struct rt6_exception_bucket *bucket;
1773 : : struct rt6_exception *rt6_ex;
1774 : : struct rt6_info *ret = NULL;
1775 : :
1776 : : #ifdef CONFIG_IPV6_SUBTREES
1777 : : /* fib6i_src.plen != 0 indicates f6i is in subtree
1778 : : * and exception table is indexed by a hash of
1779 : : * both fib6_dst and fib6_src.
1780 : : * However, the src addr used to create the hash
1781 : : * might not be exactly the passed in saddr which
1782 : : * is a /128 addr from the flow.
1783 : : * So we need to use f6i->fib6_src to redo lookup
1784 : : * if the passed in saddr does not find anything.
1785 : : * (See the logic in ip6_rt_cache_alloc() on how
1786 : : * rt->rt6i_src is updated.)
1787 : : */
1788 : : if (res->f6i->fib6_src.plen)
1789 : : src_key = saddr;
1790 : : find_ex:
1791 : : #endif
1792 : : bucket = fib6_nh_get_excptn_bucket(res->nh, NULL);
1793 : : rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1794 : :
1795 : : if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1796 : : ret = rt6_ex->rt6i;
1797 : :
1798 : : #ifdef CONFIG_IPV6_SUBTREES
1799 : : /* Use fib6_src as src_key and redo lookup */
1800 : : if (!ret && src_key && src_key != &res->f6i->fib6_src.addr) {
1801 : : src_key = &res->f6i->fib6_src.addr;
1802 : : goto find_ex;
1803 : : }
1804 : : #endif
1805 : :
1806 : : return ret;
1807 : : }
1808 : :
1809 : : /* Remove the passed in cached rt from the hash table that contains it */
1810 : : static int fib6_nh_remove_exception(const struct fib6_nh *nh, int plen,
1811 : : const struct rt6_info *rt)
1812 : : {
1813 : : const struct in6_addr *src_key = NULL;
1814 : : struct rt6_exception_bucket *bucket;
1815 : : struct rt6_exception *rt6_ex;
1816 : : int err;
1817 : :
1818 : : if (!rcu_access_pointer(nh->rt6i_exception_bucket))
1819 : : return -ENOENT;
1820 : :
1821 : : spin_lock_bh(&rt6_exception_lock);
1822 : : bucket = fib6_nh_get_excptn_bucket(nh, &rt6_exception_lock);
1823 : :
1824 : : #ifdef CONFIG_IPV6_SUBTREES
1825 : : /* rt6i_src.plen != 0 indicates 'from' is in subtree
1826 : : * and exception table is indexed by a hash of
1827 : : * both rt6i_dst and rt6i_src.
1828 : : * Otherwise, the exception table is indexed by
1829 : : * a hash of only rt6i_dst.
1830 : : */
1831 : : if (plen)
1832 : : src_key = &rt->rt6i_src.addr;
1833 : : #endif
1834 : : rt6_ex = __rt6_find_exception_spinlock(&bucket,
1835 : : &rt->rt6i_dst.addr,
1836 : : src_key);
1837 : : if (rt6_ex) {
1838 : : rt6_remove_exception(bucket, rt6_ex);
1839 : : err = 0;
1840 : : } else {
1841 : : err = -ENOENT;
1842 : : }
1843 : :
1844 : : spin_unlock_bh(&rt6_exception_lock);
1845 : : return err;
1846 : : }
1847 : :
1848 : : struct fib6_nh_excptn_arg {
1849 : : struct rt6_info *rt;
1850 : : int plen;
1851 : : };
1852 : :
1853 : 0 : static int rt6_nh_remove_exception_rt(struct fib6_nh *nh, void *_arg)
1854 : : {
1855 : 0 : struct fib6_nh_excptn_arg *arg = _arg;
1856 : 0 : int err;
1857 : :
1858 : 0 : err = fib6_nh_remove_exception(nh, arg->plen, arg->rt);
1859 [ # # ]: 0 : if (err == 0)
1860 : 0 : return 1;
1861 : :
1862 : : return 0;
1863 : : }
1864 : :
1865 : 0 : static int rt6_remove_exception_rt(struct rt6_info *rt)
1866 : : {
1867 : 0 : struct fib6_info *from;
1868 : :
1869 [ # # ]: 0 : from = rcu_dereference(rt->from);
1870 [ # # # # ]: 0 : if (!from || !(rt->rt6i_flags & RTF_CACHE))
1871 : : return -EINVAL;
1872 : :
1873 [ # # ]: 0 : if (from->nh) {
1874 : 0 : struct fib6_nh_excptn_arg arg = {
1875 : : .rt = rt,
1876 : 0 : .plen = from->fib6_src.plen
1877 : : };
1878 : 0 : int rc;
1879 : :
1880 : : /* rc = 1 means an entry was found */
1881 : 0 : rc = nexthop_for_each_fib6_nh(from->nh,
1882 : : rt6_nh_remove_exception_rt,
1883 : : &arg);
1884 [ # # ]: 0 : return rc ? 0 : -ENOENT;
1885 : : }
1886 : :
1887 : 0 : return fib6_nh_remove_exception(from->fib6_nh,
1888 : : from->fib6_src.plen, rt);
1889 : : }
1890 : :
1891 : : /* Find rt6_ex which contains the passed in rt cache and
1892 : : * refresh its stamp
1893 : : */
1894 : : static void fib6_nh_update_exception(const struct fib6_nh *nh, int plen,
1895 : : const struct rt6_info *rt)
1896 : : {
1897 : : const struct in6_addr *src_key = NULL;
1898 : : struct rt6_exception_bucket *bucket;
1899 : : struct rt6_exception *rt6_ex;
1900 : :
1901 : : bucket = fib6_nh_get_excptn_bucket(nh, NULL);
1902 : : #ifdef CONFIG_IPV6_SUBTREES
1903 : : /* rt6i_src.plen != 0 indicates 'from' is in subtree
1904 : : * and exception table is indexed by a hash of
1905 : : * both rt6i_dst and rt6i_src.
1906 : : * Otherwise, the exception table is indexed by
1907 : : * a hash of only rt6i_dst.
1908 : : */
1909 : : if (plen)
1910 : : src_key = &rt->rt6i_src.addr;
1911 : : #endif
1912 : : rt6_ex = __rt6_find_exception_rcu(&bucket, &rt->rt6i_dst.addr, src_key);
1913 : : if (rt6_ex)
1914 : : rt6_ex->stamp = jiffies;
1915 : : }
1916 : :
1917 : : struct fib6_nh_match_arg {
1918 : : const struct net_device *dev;
1919 : : const struct in6_addr *gw;
1920 : : struct fib6_nh *match;
1921 : : };
1922 : :
1923 : : /* determine if fib6_nh has given device and gateway */
1924 : 0 : static int fib6_nh_find_match(struct fib6_nh *nh, void *_arg)
1925 : : {
1926 : 0 : struct fib6_nh_match_arg *arg = _arg;
1927 : :
1928 [ # # ]: 0 : if (arg->dev != nh->fib_nh_dev ||
1929 [ # # # # : 0 : (arg->gw && !nh->fib_nh_gw_family) ||
# # ]
1930 [ # # # # ]: 0 : (!arg->gw && nh->fib_nh_gw_family) ||
1931 [ # # ]: 0 : (arg->gw && !ipv6_addr_equal(arg->gw, &nh->fib_nh_gw6)))
1932 : : return 0;
1933 : :
1934 : 0 : arg->match = nh;
1935 : :
1936 : : /* found a match, break the loop */
1937 : 0 : return 1;
1938 : : }
1939 : :
1940 : 0 : static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1941 : : {
1942 : 0 : struct fib6_info *from;
1943 : 0 : struct fib6_nh *fib6_nh;
1944 : :
1945 : 0 : rcu_read_lock();
1946 : :
1947 [ # # ]: 0 : from = rcu_dereference(rt->from);
1948 [ # # # # ]: 0 : if (!from || !(rt->rt6i_flags & RTF_CACHE))
1949 : 0 : goto unlock;
1950 : :
1951 [ # # ]: 0 : if (from->nh) {
1952 : 0 : struct fib6_nh_match_arg arg = {
1953 : 0 : .dev = rt->dst.dev,
1954 : 0 : .gw = &rt->rt6i_gateway,
1955 : : };
1956 : :
1957 : 0 : nexthop_for_each_fib6_nh(from->nh, fib6_nh_find_match, &arg);
1958 : :
1959 [ # # ]: 0 : if (!arg.match)
1960 : 0 : goto unlock;
1961 : 0 : fib6_nh = arg.match;
1962 : : } else {
1963 : 0 : fib6_nh = from->fib6_nh;
1964 : : }
1965 : 0 : fib6_nh_update_exception(fib6_nh, from->fib6_src.plen, rt);
1966 : 0 : unlock:
1967 : 0 : rcu_read_unlock();
1968 : 0 : }
1969 : :
1970 : : static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1971 : : struct rt6_info *rt, int mtu)
1972 : : {
1973 : : /* If the new MTU is lower than the route PMTU, this new MTU will be the
1974 : : * lowest MTU in the path: always allow updating the route PMTU to
1975 : : * reflect PMTU decreases.
1976 : : *
1977 : : * If the new MTU is higher, and the route PMTU is equal to the local
1978 : : * MTU, this means the old MTU is the lowest in the path, so allow
1979 : : * updating it: if other nodes now have lower MTUs, PMTU discovery will
1980 : : * handle this.
1981 : : */
1982 : :
1983 : : if (dst_mtu(&rt->dst) >= mtu)
1984 : : return true;
1985 : :
1986 : : if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1987 : : return true;
1988 : :
1989 : : return false;
1990 : : }
1991 : :
1992 : : static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
1993 : : const struct fib6_nh *nh, int mtu)
1994 : : {
1995 : : struct rt6_exception_bucket *bucket;
1996 : : struct rt6_exception *rt6_ex;
1997 : : int i;
1998 : :
1999 : : bucket = fib6_nh_get_excptn_bucket(nh, &rt6_exception_lock);
2000 : : if (!bucket)
2001 : : return;
2002 : :
2003 : : for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
2004 : : hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
2005 : : struct rt6_info *entry = rt6_ex->rt6i;
2006 : :
2007 : : /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
2008 : : * route), the metrics of its rt->from have already
2009 : : * been updated.
2010 : : */
2011 : : if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
2012 : : rt6_mtu_change_route_allowed(idev, entry, mtu))
2013 : : dst_metric_set(&entry->dst, RTAX_MTU, mtu);
2014 : : }
2015 : : bucket++;
2016 : : }
2017 : : }
2018 : :
2019 : : #define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2020 : :
2021 : 0 : static void fib6_nh_exceptions_clean_tohost(const struct fib6_nh *nh,
2022 : : const struct in6_addr *gateway)
2023 : : {
2024 : 0 : struct rt6_exception_bucket *bucket;
2025 : 0 : struct rt6_exception *rt6_ex;
2026 : 0 : struct hlist_node *tmp;
2027 : 0 : int i;
2028 : :
2029 [ # # ]: 0 : if (!rcu_access_pointer(nh->rt6i_exception_bucket))
2030 : : return;
2031 : :
2032 : 0 : spin_lock_bh(&rt6_exception_lock);
2033 [ # # ]: 0 : bucket = fib6_nh_get_excptn_bucket(nh, &rt6_exception_lock);
2034 [ # # ]: 0 : if (bucket) {
2035 [ # # ]: 0 : for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
2036 [ # # # # : 0 : hlist_for_each_entry_safe(rt6_ex, tmp,
# # ]
2037 : : &bucket->chain, hlist) {
2038 : 0 : struct rt6_info *entry = rt6_ex->rt6i;
2039 : :
2040 [ # # ]: 0 : if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
2041 [ # # ]: 0 : RTF_CACHE_GATEWAY &&
2042 : : ipv6_addr_equal(gateway,
2043 : : &entry->rt6i_gateway)) {
2044 : 0 : rt6_remove_exception(bucket, rt6_ex);
2045 : : }
2046 : : }
2047 : 0 : bucket++;
2048 : : }
2049 : : }
2050 : :
2051 : 0 : spin_unlock_bh(&rt6_exception_lock);
2052 : : }
2053 : :
2054 : : static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
2055 : : struct rt6_exception *rt6_ex,
2056 : : struct fib6_gc_args *gc_args,
2057 : : unsigned long now)
2058 : : {
2059 : : struct rt6_info *rt = rt6_ex->rt6i;
2060 : :
2061 : : /* we are pruning and obsoleting aged-out and non gateway exceptions
2062 : : * even if others have still references to them, so that on next
2063 : : * dst_check() such references can be dropped.
2064 : : * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
2065 : : * expired, independently from their aging, as per RFC 8201 section 4
2066 : : */
2067 : : if (!(rt->rt6i_flags & RTF_EXPIRES)) {
2068 : : if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
2069 : : RT6_TRACE("aging clone %p\n", rt);
2070 : : rt6_remove_exception(bucket, rt6_ex);
2071 : : return;
2072 : : }
2073 : : } else if (time_after(jiffies, rt->dst.expires)) {
2074 : : RT6_TRACE("purging expired route %p\n", rt);
2075 : : rt6_remove_exception(bucket, rt6_ex);
2076 : : return;
2077 : : }
2078 : :
2079 : : if (rt->rt6i_flags & RTF_GATEWAY) {
2080 : : struct neighbour *neigh;
2081 : : __u8 neigh_flags = 0;
2082 : :
2083 : : neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
2084 : : if (neigh)
2085 : : neigh_flags = neigh->flags;
2086 : :
2087 : : if (!(neigh_flags & NTF_ROUTER)) {
2088 : : RT6_TRACE("purging route %p via non-router but gateway\n",
2089 : : rt);
2090 : : rt6_remove_exception(bucket, rt6_ex);
2091 : : return;
2092 : : }
2093 : : }
2094 : :
2095 : : gc_args->more++;
2096 : : }
2097 : :
2098 : 0 : static void fib6_nh_age_exceptions(const struct fib6_nh *nh,
2099 : : struct fib6_gc_args *gc_args,
2100 : : unsigned long now)
2101 : : {
2102 : 0 : struct rt6_exception_bucket *bucket;
2103 : 0 : struct rt6_exception *rt6_ex;
2104 : 0 : struct hlist_node *tmp;
2105 : 0 : int i;
2106 : :
2107 [ # # ]: 0 : if (!rcu_access_pointer(nh->rt6i_exception_bucket))
2108 : : return;
2109 : :
2110 : 0 : rcu_read_lock_bh();
2111 : 0 : spin_lock(&rt6_exception_lock);
2112 [ # # ]: 0 : bucket = fib6_nh_get_excptn_bucket(nh, &rt6_exception_lock);
2113 [ # # ]: 0 : if (bucket) {
2114 [ # # ]: 0 : for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
2115 [ # # # # : 0 : hlist_for_each_entry_safe(rt6_ex, tmp,
# # ]
2116 : : &bucket->chain, hlist) {
2117 : 0 : rt6_age_examine_exception(bucket, rt6_ex,
2118 : : gc_args, now);
2119 : : }
2120 : 0 : bucket++;
2121 : : }
2122 : : }
2123 : 0 : spin_unlock(&rt6_exception_lock);
2124 : 0 : rcu_read_unlock_bh();
2125 : : }
2126 : :
2127 : : struct fib6_nh_age_excptn_arg {
2128 : : struct fib6_gc_args *gc_args;
2129 : : unsigned long now;
2130 : : };
2131 : :
2132 : 0 : static int rt6_nh_age_exceptions(struct fib6_nh *nh, void *_arg)
2133 : : {
2134 : 0 : struct fib6_nh_age_excptn_arg *arg = _arg;
2135 : :
2136 : 0 : fib6_nh_age_exceptions(nh, arg->gc_args, arg->now);
2137 : 0 : return 0;
2138 : : }
2139 : :
2140 : 0 : void rt6_age_exceptions(struct fib6_info *f6i,
2141 : : struct fib6_gc_args *gc_args,
2142 : : unsigned long now)
2143 : : {
2144 [ # # ]: 0 : if (f6i->nh) {
2145 : 0 : struct fib6_nh_age_excptn_arg arg = {
2146 : : .gc_args = gc_args,
2147 : : .now = now
2148 : : };
2149 : :
2150 : 0 : nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_age_exceptions,
2151 : : &arg);
2152 : : } else {
2153 : 0 : fib6_nh_age_exceptions(f6i->fib6_nh, gc_args, now);
2154 : : }
2155 : 0 : }
2156 : :
2157 : : /* must be called with rcu lock held */
2158 : 156 : int fib6_table_lookup(struct net *net, struct fib6_table *table, int oif,
2159 : : struct flowi6 *fl6, struct fib6_result *res, int strict)
2160 : : {
2161 : 156 : struct fib6_node *fn, *saved_fn;
2162 : :
2163 : 156 : fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
2164 : 156 : saved_fn = fn;
2165 : :
2166 [ + - ]: 156 : if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
2167 : 0 : oif = 0;
2168 : :
2169 : 156 : redo_rt6_select:
2170 : 156 : rt6_select(net, fn, oif, res, strict);
2171 [ - + ]: 156 : if (res->f6i == net->ipv6.fib6_null_entry) {
2172 : : fn = fib6_backtrack(fn, &fl6->saddr);
2173 [ # # ]: 0 : if (fn)
2174 : 0 : goto redo_rt6_select;
2175 [ # # ]: 0 : else if (strict & RT6_LOOKUP_F_REACHABLE) {
2176 : : /* also consider unreachable route */
2177 : 0 : strict &= ~RT6_LOOKUP_F_REACHABLE;
2178 : 0 : fn = saved_fn;
2179 : 0 : goto redo_rt6_select;
2180 : : }
2181 : : }
2182 : :
2183 : 156 : trace_fib6_table_lookup(net, res, table, fl6);
2184 : :
2185 : 156 : return 0;
2186 : : }
2187 : :
2188 : 156 : struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
2189 : : int oif, struct flowi6 *fl6,
2190 : : const struct sk_buff *skb, int flags)
2191 : : {
2192 : 156 : struct fib6_result res = {};
2193 : 156 : struct rt6_info *rt = NULL;
2194 : 156 : int strict = 0;
2195 : :
2196 : 156 : WARN_ON_ONCE((flags & RT6_LOOKUP_F_DST_NOREF) &&
2197 : : !rcu_read_lock_held());
2198 : :
2199 : 156 : strict |= flags & RT6_LOOKUP_F_IFACE;
2200 : 156 : strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
2201 [ + - ]: 156 : if (net->ipv6.devconf_all->forwarding == 0)
2202 : 156 : strict |= RT6_LOOKUP_F_REACHABLE;
2203 : :
2204 : 156 : rcu_read_lock();
2205 : :
2206 : 156 : fib6_table_lookup(net, table, oif, fl6, &res, strict);
2207 [ - + ]: 156 : if (res.f6i == net->ipv6.fib6_null_entry)
2208 : 0 : goto out;
2209 : :
2210 : 156 : fib6_select_path(net, &res, fl6, oif, false, skb, strict);
2211 : :
2212 : : /*Search through exception table */
2213 : 156 : rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
2214 [ - + ]: 156 : if (rt) {
2215 : 0 : goto out;
2216 [ - + - - ]: 156 : } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
2217 : : !res.nh->fib_nh_gw_family)) {
2218 : : /* Create a RTF_CACHE clone which will not be
2219 : : * owned by the fib6 tree. It is for the special case where
2220 : : * the daddr in the skb during the neighbor look-up is different
2221 : : * from the fl6->daddr used to look-up route here.
2222 : : */
2223 : 0 : rt = ip6_rt_cache_alloc(&res, &fl6->daddr, NULL);
2224 : :
2225 [ # # ]: 0 : if (rt) {
2226 : : /* 1 refcnt is taken during ip6_rt_cache_alloc().
2227 : : * As rt6_uncached_list_add() does not consume refcnt,
2228 : : * this refcnt is always returned to the caller even
2229 : : * if caller sets RT6_LOOKUP_F_DST_NOREF flag.
2230 : : */
2231 : 0 : rt6_uncached_list_add(rt);
2232 : 0 : atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
2233 : 0 : rcu_read_unlock();
2234 : :
2235 : 0 : return rt;
2236 : : }
2237 : : } else {
2238 : : /* Get a percpu copy */
2239 : 156 : local_bh_disable();
2240 : 156 : rt = rt6_get_pcpu_route(&res);
2241 : :
2242 [ + + ]: 156 : if (!rt)
2243 : 78 : rt = rt6_make_pcpu_route(net, &res);
2244 : :
2245 : 156 : local_bh_enable();
2246 : : }
2247 : 156 : out:
2248 [ - + ]: 156 : if (!rt)
2249 : 0 : rt = net->ipv6.ip6_null_entry;
2250 [ - + ]: 156 : if (!(flags & RT6_LOOKUP_F_DST_NOREF))
2251 : 0 : ip6_hold_safe(net, &rt);
2252 : 156 : rcu_read_unlock();
2253 : :
2254 : 156 : return rt;
2255 : : }
2256 : : EXPORT_SYMBOL_GPL(ip6_pol_route);
2257 : :
2258 : 0 : static struct rt6_info *ip6_pol_route_input(struct net *net,
2259 : : struct fib6_table *table,
2260 : : struct flowi6 *fl6,
2261 : : const struct sk_buff *skb,
2262 : : int flags)
2263 : : {
2264 : 0 : return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
2265 : : }
2266 : :
2267 : 0 : struct dst_entry *ip6_route_input_lookup(struct net *net,
2268 : : struct net_device *dev,
2269 : : struct flowi6 *fl6,
2270 : : const struct sk_buff *skb,
2271 : : int flags)
2272 : : {
2273 [ # # # # ]: 0 : if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
2274 : 0 : flags |= RT6_LOOKUP_F_IFACE;
2275 : :
2276 : 0 : return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
2277 : : }
2278 : : EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
2279 : :
2280 : 0 : static void ip6_multipath_l3_keys(const struct sk_buff *skb,
2281 : : struct flow_keys *keys,
2282 : : struct flow_keys *flkeys)
2283 : : {
2284 [ # # ]: 0 : const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
2285 : 0 : const struct ipv6hdr *key_iph = outer_iph;
2286 : 0 : struct flow_keys *_flkeys = flkeys;
2287 : 0 : const struct ipv6hdr *inner_iph;
2288 : 0 : const struct icmp6hdr *icmph;
2289 : 0 : struct ipv6hdr _inner_iph;
2290 : 0 : struct icmp6hdr _icmph;
2291 : :
2292 [ # # ]: 0 : if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
2293 : 0 : goto out;
2294 : :
2295 : 0 : icmph = skb_header_pointer(skb, skb_transport_offset(skb),
2296 : : sizeof(_icmph), &_icmph);
2297 [ # # ]: 0 : if (!icmph)
2298 : 0 : goto out;
2299 : :
2300 [ # # ]: 0 : if (!icmpv6_is_err(icmph->icmp6_type))
2301 : 0 : goto out;
2302 : :
2303 : 0 : inner_iph = skb_header_pointer(skb,
2304 : 0 : skb_transport_offset(skb) + sizeof(*icmph),
2305 : : sizeof(_inner_iph), &_inner_iph);
2306 [ # # ]: 0 : if (!inner_iph)
2307 : 0 : goto out;
2308 : :
2309 : : key_iph = inner_iph;
2310 : : _flkeys = NULL;
2311 : 0 : out:
2312 [ # # ]: 0 : if (_flkeys) {
2313 : 0 : keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
2314 : 0 : keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
2315 : 0 : keys->tags.flow_label = _flkeys->tags.flow_label;
2316 : 0 : keys->basic.ip_proto = _flkeys->basic.ip_proto;
2317 : : } else {
2318 : 0 : keys->addrs.v6addrs.src = key_iph->saddr;
2319 : 0 : keys->addrs.v6addrs.dst = key_iph->daddr;
2320 : 0 : keys->tags.flow_label = ip6_flowlabel(key_iph);
2321 : 0 : keys->basic.ip_proto = key_iph->nexthdr;
2322 : : }
2323 : 0 : }
2324 : :
2325 : : /* if skb is set it will be used and fl6 can be NULL */
2326 : 0 : u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
2327 : : const struct sk_buff *skb, struct flow_keys *flkeys)
2328 : : {
2329 : 0 : struct flow_keys hash_keys;
2330 : 0 : u32 mhash;
2331 : :
2332 [ # # # # ]: 0 : switch (ip6_multipath_hash_policy(net)) {
2333 : 0 : case 0:
2334 : 0 : memset(&hash_keys, 0, sizeof(hash_keys));
2335 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2336 [ # # ]: 0 : if (skb) {
2337 : 0 : ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2338 : : } else {
2339 : 0 : hash_keys.addrs.v6addrs.src = fl6->saddr;
2340 : 0 : hash_keys.addrs.v6addrs.dst = fl6->daddr;
2341 : 0 : hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
2342 : 0 : hash_keys.basic.ip_proto = fl6->flowi6_proto;
2343 : : }
2344 : : break;
2345 : 0 : case 1:
2346 [ # # ]: 0 : if (skb) {
2347 : 0 : unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2348 : 0 : struct flow_keys keys;
2349 : :
2350 : : /* short-circuit if we already have L4 hash present */
2351 [ # # ]: 0 : if (skb->l4_hash)
2352 : 0 : return skb_get_hash_raw(skb) >> 1;
2353 : :
2354 : 0 : memset(&hash_keys, 0, sizeof(hash_keys));
2355 : :
2356 [ # # ]: 0 : if (!flkeys) {
2357 : 0 : skb_flow_dissect_flow_keys(skb, &keys, flag);
2358 : 0 : flkeys = &keys;
2359 : : }
2360 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2361 : 0 : hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2362 : 0 : hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2363 : 0 : hash_keys.ports.src = flkeys->ports.src;
2364 : 0 : hash_keys.ports.dst = flkeys->ports.dst;
2365 : 0 : hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2366 : : } else {
2367 : 0 : memset(&hash_keys, 0, sizeof(hash_keys));
2368 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2369 : 0 : hash_keys.addrs.v6addrs.src = fl6->saddr;
2370 : 0 : hash_keys.addrs.v6addrs.dst = fl6->daddr;
2371 : 0 : hash_keys.ports.src = fl6->fl6_sport;
2372 : 0 : hash_keys.ports.dst = fl6->fl6_dport;
2373 : 0 : hash_keys.basic.ip_proto = fl6->flowi6_proto;
2374 : : }
2375 : : break;
2376 : 0 : case 2:
2377 : 0 : memset(&hash_keys, 0, sizeof(hash_keys));
2378 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2379 [ # # ]: 0 : if (skb) {
2380 : 0 : struct flow_keys keys;
2381 : :
2382 [ # # ]: 0 : if (!flkeys) {
2383 : 0 : skb_flow_dissect_flow_keys(skb, &keys, 0);
2384 : 0 : flkeys = &keys;
2385 : : }
2386 : :
2387 : : /* Inner can be v4 or v6 */
2388 [ # # ]: 0 : if (flkeys->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
2389 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
2390 : 0 : hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src;
2391 : 0 : hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst;
2392 [ # # ]: 0 : } else if (flkeys->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
2393 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2394 : 0 : hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2395 : 0 : hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2396 : 0 : hash_keys.tags.flow_label = flkeys->tags.flow_label;
2397 : 0 : hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2398 : : } else {
2399 : : /* Same as case 0 */
2400 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2401 : 0 : ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2402 : : }
2403 : : } else {
2404 : : /* Same as case 0 */
2405 : 0 : hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2406 : 0 : hash_keys.addrs.v6addrs.src = fl6->saddr;
2407 : 0 : hash_keys.addrs.v6addrs.dst = fl6->daddr;
2408 : 0 : hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
2409 : 0 : hash_keys.basic.ip_proto = fl6->flowi6_proto;
2410 : : }
2411 : : break;
2412 : : }
2413 : 0 : mhash = flow_hash_from_keys(&hash_keys);
2414 : :
2415 : 0 : return mhash >> 1;
2416 : : }
2417 : :
2418 : : /* Called with rcu held */
2419 : 0 : void ip6_route_input(struct sk_buff *skb)
2420 : : {
2421 [ # # ]: 0 : const struct ipv6hdr *iph = ipv6_hdr(skb);
2422 [ # # ]: 0 : struct net *net = dev_net(skb->dev);
2423 : 0 : int flags = RT6_LOOKUP_F_HAS_SADDR | RT6_LOOKUP_F_DST_NOREF;
2424 : 0 : struct ip_tunnel_info *tun_info;
2425 : 0 : struct flowi6 fl6 = {
2426 : 0 : .flowi6_iif = skb->dev->ifindex,
2427 : : .daddr = iph->daddr,
2428 : : .saddr = iph->saddr,
2429 : : .flowlabel = ip6_flowinfo(iph),
2430 : 0 : .flowi6_mark = skb->mark,
2431 [ # # ]: 0 : .flowi6_proto = iph->nexthdr,
2432 : : };
2433 : 0 : struct flow_keys *flkeys = NULL, _flkeys;
2434 : :
2435 [ # # ]: 0 : tun_info = skb_tunnel_info(skb);
2436 [ # # # # ]: 0 : if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
2437 : 0 : fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
2438 : :
2439 [ # # ]: 0 : if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2440 : : flkeys = &_flkeys;
2441 : :
2442 [ # # ]: 0 : if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
2443 : 0 : fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
2444 [ # # ]: 0 : skb_dst_drop(skb);
2445 : 0 : skb_dst_set_noref(skb, ip6_route_input_lookup(net, skb->dev,
2446 : : &fl6, skb, flags));
2447 : 0 : }
2448 : :
2449 : 156 : static struct rt6_info *ip6_pol_route_output(struct net *net,
2450 : : struct fib6_table *table,
2451 : : struct flowi6 *fl6,
2452 : : const struct sk_buff *skb,
2453 : : int flags)
2454 : : {
2455 : 156 : return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
2456 : : }
2457 : :
2458 : 156 : struct dst_entry *ip6_route_output_flags_noref(struct net *net,
2459 : : const struct sock *sk,
2460 : : struct flowi6 *fl6, int flags)
2461 : : {
2462 : 156 : bool any_src;
2463 : :
2464 : 156 : if (ipv6_addr_type(&fl6->daddr) &
2465 : : (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
2466 : : struct dst_entry *dst;
2467 : :
2468 : : /* This function does not take refcnt on the dst */
2469 : : dst = l3mdev_link_scope_lookup(net, fl6);
2470 : : if (dst)
2471 : : return dst;
2472 : : }
2473 : :
2474 : 156 : fl6->flowi6_iif = LOOPBACK_IFINDEX;
2475 : :
2476 : 156 : flags |= RT6_LOOKUP_F_DST_NOREF;
2477 [ + - ]: 156 : any_src = ipv6_addr_any(&fl6->saddr);
2478 [ + - + - : 312 : if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
- + ]
2479 [ # # # # ]: 0 : (fl6->flowi6_oif && any_src))
2480 : 156 : flags |= RT6_LOOKUP_F_IFACE;
2481 : :
2482 [ - + ]: 156 : if (!any_src)
2483 : 0 : flags |= RT6_LOOKUP_F_HAS_SADDR;
2484 [ + - ]: 156 : else if (sk)
2485 [ + - ]: 312 : flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
2486 : :
2487 : 156 : return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
2488 : : }
2489 : : EXPORT_SYMBOL_GPL(ip6_route_output_flags_noref);
2490 : :
2491 : 156 : struct dst_entry *ip6_route_output_flags(struct net *net,
2492 : : const struct sock *sk,
2493 : : struct flowi6 *fl6,
2494 : : int flags)
2495 : : {
2496 : 156 : struct dst_entry *dst;
2497 : 156 : struct rt6_info *rt6;
2498 : :
2499 : 156 : rcu_read_lock();
2500 : 156 : dst = ip6_route_output_flags_noref(net, sk, fl6, flags);
2501 : 156 : rt6 = (struct rt6_info *)dst;
2502 : : /* For dst cached in uncached_list, refcnt is already taken. */
2503 [ + - - + ]: 312 : if (list_empty(&rt6->rt6i_uncached) && !dst_hold_safe(dst)) {
2504 : 0 : dst = &net->ipv6.ip6_null_entry->dst;
2505 : 0 : dst_hold(dst);
2506 : : }
2507 : 156 : rcu_read_unlock();
2508 : :
2509 : 156 : return dst;
2510 : : }
2511 : : EXPORT_SYMBOL_GPL(ip6_route_output_flags);
2512 : :
2513 : 0 : struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
2514 : : {
2515 : 0 : struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
2516 : 0 : struct net_device *loopback_dev = net->loopback_dev;
2517 : 0 : struct dst_entry *new = NULL;
2518 : :
2519 : 0 : rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
2520 : : DST_OBSOLETE_DEAD, 0);
2521 [ # # ]: 0 : if (rt) {
2522 : 0 : rt6_info_init(rt);
2523 : 0 : atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
2524 : :
2525 : 0 : new = &rt->dst;
2526 : 0 : new->__use = 1;
2527 : 0 : new->input = dst_discard;
2528 : 0 : new->output = dst_discard_out;
2529 : :
2530 : 0 : dst_copy_metrics(new, &ort->dst);
2531 : :
2532 : 0 : rt->rt6i_idev = in6_dev_get(loopback_dev);
2533 : 0 : rt->rt6i_gateway = ort->rt6i_gateway;
2534 : 0 : rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
2535 : :
2536 : 0 : memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2537 : : #ifdef CONFIG_IPV6_SUBTREES
2538 : : memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2539 : : #endif
2540 : : }
2541 : :
2542 : 0 : dst_release(dst_orig);
2543 [ # # ]: 0 : return new ? new : ERR_PTR(-ENOMEM);
2544 : : }
2545 : :
2546 : : /*
2547 : : * Destination cache support functions
2548 : : */
2549 : :
2550 : 312 : static bool fib6_check(struct fib6_info *f6i, u32 cookie)
2551 : : {
2552 : 312 : u32 rt_cookie = 0;
2553 : :
2554 [ + - + - : 624 : if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
+ - ]
2555 : : return false;
2556 : :
2557 [ - + - - ]: 312 : if (fib6_check_expired(f6i))
2558 : 0 : return false;
2559 : :
2560 : : return true;
2561 : : }
2562 : :
2563 : 0 : static struct dst_entry *rt6_check(struct rt6_info *rt,
2564 : : struct fib6_info *from,
2565 : : u32 cookie)
2566 : : {
2567 : 0 : u32 rt_cookie = 0;
2568 : :
2569 [ # # # # : 0 : if (!from || !fib6_get_cookie_safe(from, &rt_cookie) ||
# # ]
2570 : : rt_cookie != cookie)
2571 : 0 : return NULL;
2572 : :
2573 [ # # ]: 0 : if (rt6_check_expired(rt))
2574 : : return NULL;
2575 : :
2576 : 0 : return &rt->dst;
2577 : : }
2578 : :
2579 : 312 : static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2580 : : struct fib6_info *from,
2581 : : u32 cookie)
2582 : : {
2583 [ - + - - ]: 312 : if (!__rt6_check_expired(rt) &&
2584 [ + - + - ]: 624 : rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
2585 : 312 : fib6_check(from, cookie))
2586 : 312 : return &rt->dst;
2587 : : else
2588 : 0 : return NULL;
2589 : : }
2590 : :
2591 : 312 : static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2592 : : {
2593 : 312 : struct dst_entry *dst_ret;
2594 : 312 : struct fib6_info *from;
2595 : 312 : struct rt6_info *rt;
2596 : :
2597 : 312 : rt = container_of(dst, struct rt6_info, dst);
2598 : :
2599 : 312 : rcu_read_lock();
2600 : :
2601 : : /* All IPV6 dsts are created with ->obsolete set to the value
2602 : : * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2603 : : * into this function always.
2604 : : */
2605 : :
2606 [ + - ]: 312 : from = rcu_dereference(rt->from);
2607 : :
2608 [ + - - + : 312 : if (from && (rt->rt6i_flags & RTF_PCPU ||
- - ]
2609 [ # # ]: 0 : unlikely(!list_empty(&rt->rt6i_uncached))))
2610 : 312 : dst_ret = rt6_dst_from_check(rt, from, cookie);
2611 : : else
2612 : 0 : dst_ret = rt6_check(rt, from, cookie);
2613 : :
2614 : 312 : rcu_read_unlock();
2615 : :
2616 : 312 : return dst_ret;
2617 : : }
2618 : :
2619 : 0 : static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2620 : : {
2621 : 0 : struct rt6_info *rt = (struct rt6_info *) dst;
2622 : :
2623 [ # # ]: 0 : if (rt) {
2624 [ # # ]: 0 : if (rt->rt6i_flags & RTF_CACHE) {
2625 : 0 : rcu_read_lock();
2626 [ # # ]: 0 : if (rt6_check_expired(rt)) {
2627 : 0 : rt6_remove_exception_rt(rt);
2628 : 0 : dst = NULL;
2629 : : }
2630 : 0 : rcu_read_unlock();
2631 : : } else {
2632 : 0 : dst_release(dst);
2633 : 0 : dst = NULL;
2634 : : }
2635 : : }
2636 : 0 : return dst;
2637 : : }
2638 : :
2639 : 0 : static void ip6_link_failure(struct sk_buff *skb)
2640 : : {
2641 : 0 : struct rt6_info *rt;
2642 : :
2643 : 0 : icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
2644 : :
2645 [ # # ]: 0 : rt = (struct rt6_info *) skb_dst(skb);
2646 [ # # ]: 0 : if (rt) {
2647 : 0 : rcu_read_lock();
2648 [ # # ]: 0 : if (rt->rt6i_flags & RTF_CACHE) {
2649 : 0 : rt6_remove_exception_rt(rt);
2650 : : } else {
2651 : 0 : struct fib6_info *from;
2652 : 0 : struct fib6_node *fn;
2653 : :
2654 [ # # ]: 0 : from = rcu_dereference(rt->from);
2655 [ # # ]: 0 : if (from) {
2656 [ # # ]: 0 : fn = rcu_dereference(from->fib6_node);
2657 [ # # # # ]: 0 : if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2658 : 0 : fn->fn_sernum = -1;
2659 : : }
2660 : : }
2661 : 0 : rcu_read_unlock();
2662 : : }
2663 : 0 : }
2664 : :
2665 : 0 : static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2666 : : {
2667 [ # # ]: 0 : if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2668 : 0 : struct fib6_info *from;
2669 : :
2670 : 0 : rcu_read_lock();
2671 [ # # ]: 0 : from = rcu_dereference(rt0->from);
2672 [ # # ]: 0 : if (from)
2673 : 0 : rt0->dst.expires = from->expires;
2674 : 0 : rcu_read_unlock();
2675 : : }
2676 : :
2677 [ # # ]: 0 : dst_set_expires(&rt0->dst, timeout);
2678 : 0 : rt0->rt6i_flags |= RTF_EXPIRES;
2679 : 0 : }
2680 : :
2681 : 0 : static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2682 : : {
2683 : 0 : struct net *net = dev_net(rt->dst.dev);
2684 : :
2685 : 0 : dst_metric_set(&rt->dst, RTAX_MTU, mtu);
2686 : 0 : rt->rt6i_flags |= RTF_MODIFIED;
2687 : 0 : rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2688 : 0 : }
2689 : :
2690 : 0 : static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2691 : : {
2692 : 0 : return !(rt->rt6i_flags & RTF_CACHE) &&
2693 [ # # # # ]: 0 : (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from));
2694 : : }
2695 : :
2696 : 0 : static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2697 : : const struct ipv6hdr *iph, u32 mtu,
2698 : : bool confirm_neigh)
2699 : : {
2700 : 0 : const struct in6_addr *daddr, *saddr;
2701 : 0 : struct rt6_info *rt6 = (struct rt6_info *)dst;
2702 : :
2703 [ # # ]: 0 : if (dst_metric_locked(dst, RTAX_MTU))
2704 : : return;
2705 : :
2706 [ # # ]: 0 : if (iph) {
2707 : 0 : daddr = &iph->daddr;
2708 : 0 : saddr = &iph->saddr;
2709 [ # # ]: 0 : } else if (sk) {
2710 : 0 : daddr = &sk->sk_v6_daddr;
2711 : 0 : saddr = &inet6_sk(sk)->saddr;
2712 : : } else {
2713 : : daddr = NULL;
2714 : : saddr = NULL;
2715 : : }
2716 : :
2717 [ # # ]: 0 : if (confirm_neigh)
2718 [ # # ]: 0 : dst_confirm_neigh(dst, daddr);
2719 : :
2720 : 0 : mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2721 [ # # ]: 0 : if (mtu >= dst_mtu(dst))
2722 : : return;
2723 : :
2724 [ # # # # ]: 0 : if (!rt6_cache_allowed_for_pmtu(rt6)) {
2725 : 0 : rt6_do_update_pmtu(rt6, mtu);
2726 : : /* update rt6_ex->stamp for cache */
2727 [ # # ]: 0 : if (rt6->rt6i_flags & RTF_CACHE)
2728 : 0 : rt6_update_exception_stamp_rt(rt6);
2729 [ # # ]: 0 : } else if (daddr) {
2730 : 0 : struct fib6_result res = {};
2731 : 0 : struct rt6_info *nrt6;
2732 : :
2733 : 0 : rcu_read_lock();
2734 [ # # ]: 0 : res.f6i = rcu_dereference(rt6->from);
2735 [ # # ]: 0 : if (!res.f6i)
2736 : 0 : goto out_unlock;
2737 : :
2738 : 0 : res.fib6_flags = res.f6i->fib6_flags;
2739 : 0 : res.fib6_type = res.f6i->fib6_type;
2740 : :
2741 [ # # ]: 0 : if (res.f6i->nh) {
2742 : 0 : struct fib6_nh_match_arg arg = {
2743 : 0 : .dev = dst->dev,
2744 : 0 : .gw = &rt6->rt6i_gateway,
2745 : : };
2746 : :
2747 : 0 : nexthop_for_each_fib6_nh(res.f6i->nh,
2748 : : fib6_nh_find_match, &arg);
2749 : :
2750 : : /* fib6_info uses a nexthop that does not have fib6_nh
2751 : : * using the dst->dev + gw. Should be impossible.
2752 : : */
2753 [ # # ]: 0 : if (!arg.match)
2754 : 0 : goto out_unlock;
2755 : :
2756 : 0 : res.nh = arg.match;
2757 : : } else {
2758 : 0 : res.nh = res.f6i->fib6_nh;
2759 : : }
2760 : :
2761 : 0 : nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr);
2762 [ # # ]: 0 : if (nrt6) {
2763 : 0 : rt6_do_update_pmtu(nrt6, mtu);
2764 [ # # ]: 0 : if (rt6_insert_exception(nrt6, &res))
2765 : 0 : dst_release_immediate(&nrt6->dst);
2766 : : }
2767 : 0 : out_unlock:
2768 : 0 : rcu_read_unlock();
2769 : : }
2770 : : }
2771 : :
2772 : 0 : static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2773 : : struct sk_buff *skb, u32 mtu,
2774 : : bool confirm_neigh)
2775 : : {
2776 [ # # ]: 0 : __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu,
2777 : : confirm_neigh);
2778 : 0 : }
2779 : :
2780 : 0 : void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
2781 : : int oif, u32 mark, kuid_t uid)
2782 : : {
2783 : 0 : const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2784 : 0 : struct dst_entry *dst;
2785 : 0 : struct flowi6 fl6 = {
2786 : : .flowi6_oif = oif,
2787 [ # # # # ]: 0 : .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark),
2788 : : .daddr = iph->daddr,
2789 : : .saddr = iph->saddr,
2790 : : .flowlabel = ip6_flowinfo(iph),
2791 : : .flowi6_uid = uid,
2792 : : };
2793 : :
2794 : 0 : dst = ip6_route_output(net, NULL, &fl6);
2795 [ # # ]: 0 : if (!dst->error)
2796 : 0 : __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu), true);
2797 : 0 : dst_release(dst);
2798 : 0 : }
2799 : : EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2800 : :
2801 : 0 : void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2802 : : {
2803 : 0 : int oif = sk->sk_bound_dev_if;
2804 : 0 : struct dst_entry *dst;
2805 : :
2806 [ # # ]: 0 : if (!oif && skb->dev)
2807 : : oif = l3mdev_master_ifindex(skb->dev);
2808 : :
2809 : 0 : ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
2810 : :
2811 [ # # ]: 0 : dst = __sk_dst_get(sk);
2812 [ # # # # : 0 : if (!dst || !dst->obsolete ||
# # ]
2813 [ # # ]: 0 : dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2814 : 0 : return;
2815 : :
2816 : 0 : bh_lock_sock(sk);
2817 [ # # # # ]: 0 : if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2818 : 0 : ip6_datagram_dst_update(sk, false);
2819 : 0 : bh_unlock_sock(sk);
2820 : : }
2821 : : EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2822 : :
2823 : 156 : void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2824 : : const struct flowi6 *fl6)
2825 : : {
2826 : : #ifdef CONFIG_IPV6_SUBTREES
2827 : : struct ipv6_pinfo *np = inet6_sk(sk);
2828 : : #endif
2829 : :
2830 [ + - ]: 156 : ip6_dst_store(sk, dst,
2831 : : ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2832 : : &sk->sk_v6_daddr : NULL,
2833 : : #ifdef CONFIG_IPV6_SUBTREES
2834 : : ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2835 : : &np->saddr :
2836 : : #endif
2837 : : NULL);
2838 : 156 : }
2839 : :
2840 : : static bool ip6_redirect_nh_match(const struct fib6_result *res,
2841 : : struct flowi6 *fl6,
2842 : : const struct in6_addr *gw,
2843 : : struct rt6_info **ret)
2844 : : {
2845 : : const struct fib6_nh *nh = res->nh;
2846 : :
2847 : : if (nh->fib_nh_flags & RTNH_F_DEAD || !nh->fib_nh_gw_family ||
2848 : : fl6->flowi6_oif != nh->fib_nh_dev->ifindex)
2849 : : return false;
2850 : :
2851 : : /* rt_cache's gateway might be different from its 'parent'
2852 : : * in the case of an ip redirect.
2853 : : * So we keep searching in the exception table if the gateway
2854 : : * is different.
2855 : : */
2856 : : if (!ipv6_addr_equal(gw, &nh->fib_nh_gw6)) {
2857 : : struct rt6_info *rt_cache;
2858 : :
2859 : : rt_cache = rt6_find_cached_rt(res, &fl6->daddr, &fl6->saddr);
2860 : : if (rt_cache &&
2861 : : ipv6_addr_equal(gw, &rt_cache->rt6i_gateway)) {
2862 : : *ret = rt_cache;
2863 : : return true;
2864 : : }
2865 : : return false;
2866 : : }
2867 : : return true;
2868 : : }
2869 : :
2870 : : struct fib6_nh_rd_arg {
2871 : : struct fib6_result *res;
2872 : : struct flowi6 *fl6;
2873 : : const struct in6_addr *gw;
2874 : : struct rt6_info **ret;
2875 : : };
2876 : :
2877 : 0 : static int fib6_nh_redirect_match(struct fib6_nh *nh, void *_arg)
2878 : : {
2879 : 0 : struct fib6_nh_rd_arg *arg = _arg;
2880 : :
2881 : 0 : arg->res->nh = nh;
2882 : 0 : return ip6_redirect_nh_match(arg->res, arg->fl6, arg->gw, arg->ret);
2883 : : }
2884 : :
2885 : : /* Handle redirects */
2886 : : struct ip6rd_flowi {
2887 : : struct flowi6 fl6;
2888 : : struct in6_addr gateway;
2889 : : };
2890 : :
2891 : 0 : static struct rt6_info *__ip6_route_redirect(struct net *net,
2892 : : struct fib6_table *table,
2893 : : struct flowi6 *fl6,
2894 : : const struct sk_buff *skb,
2895 : : int flags)
2896 : : {
2897 : 0 : struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
2898 : 0 : struct rt6_info *ret = NULL;
2899 : 0 : struct fib6_result res = {};
2900 : 0 : struct fib6_nh_rd_arg arg = {
2901 : : .res = &res,
2902 : : .fl6 = fl6,
2903 : 0 : .gw = &rdfl->gateway,
2904 : : .ret = &ret
2905 : : };
2906 : 0 : struct fib6_info *rt;
2907 : 0 : struct fib6_node *fn;
2908 : :
2909 : : /* l3mdev_update_flow overrides oif if the device is enslaved; in
2910 : : * this case we must match on the real ingress device, so reset it
2911 : : */
2912 [ # # ]: 0 : if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
2913 : 0 : fl6->flowi6_oif = skb->dev->ifindex;
2914 : :
2915 : : /* Get the "current" route for this destination and
2916 : : * check if the redirect has come from appropriate router.
2917 : : *
2918 : : * RFC 4861 specifies that redirects should only be
2919 : : * accepted if they come from the nexthop to the target.
2920 : : * Due to the way the routes are chosen, this notion
2921 : : * is a bit fuzzy and one might need to check all possible
2922 : : * routes.
2923 : : */
2924 : :
2925 : 0 : rcu_read_lock();
2926 : 0 : fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
2927 : 0 : restart:
2928 [ # # ]: 0 : for_each_fib6_node_rt_rcu(fn) {
2929 : 0 : res.f6i = rt;
2930 [ # # # # ]: 0 : if (fib6_check_expired(rt))
2931 : 0 : continue;
2932 [ # # ]: 0 : if (rt->fib6_flags & RTF_REJECT)
2933 : : break;
2934 [ # # ]: 0 : if (unlikely(rt->nh)) {
2935 [ # # ]: 0 : if (nexthop_is_blackhole(rt->nh))
2936 : 0 : continue;
2937 : : /* on match, res->nh is filled in and potentially ret */
2938 [ # # ]: 0 : if (nexthop_for_each_fib6_nh(rt->nh,
2939 : : fib6_nh_redirect_match,
2940 : : &arg))
2941 : 0 : goto out;
2942 : : } else {
2943 : 0 : res.nh = rt->fib6_nh;
2944 [ # # ]: 0 : if (ip6_redirect_nh_match(&res, fl6, &rdfl->gateway,
2945 : : &ret))
2946 : 0 : goto out;
2947 : : }
2948 : : }
2949 : :
2950 [ # # ]: 0 : if (!rt)
2951 : 0 : rt = net->ipv6.fib6_null_entry;
2952 [ # # ]: 0 : else if (rt->fib6_flags & RTF_REJECT) {
2953 : 0 : ret = net->ipv6.ip6_null_entry;
2954 : 0 : goto out;
2955 : : }
2956 : :
2957 [ # # ]: 0 : if (rt == net->ipv6.fib6_null_entry) {
2958 : : fn = fib6_backtrack(fn, &fl6->saddr);
2959 [ # # ]: 0 : if (fn)
2960 : 0 : goto restart;
2961 : : }
2962 : :
2963 : 0 : res.f6i = rt;
2964 : 0 : res.nh = rt->fib6_nh;
2965 : 0 : out:
2966 [ # # ]: 0 : if (ret) {
2967 : 0 : ip6_hold_safe(net, &ret);
2968 : : } else {
2969 : 0 : res.fib6_flags = res.f6i->fib6_flags;
2970 : 0 : res.fib6_type = res.f6i->fib6_type;
2971 : 0 : ret = ip6_create_rt_rcu(&res);
2972 : : }
2973 : :
2974 : 0 : rcu_read_unlock();
2975 : :
2976 : 0 : trace_fib6_table_lookup(net, &res, table, fl6);
2977 : 0 : return ret;
2978 : : };
2979 : :
2980 : : static struct dst_entry *ip6_route_redirect(struct net *net,
2981 : : const struct flowi6 *fl6,
2982 : : const struct sk_buff *skb,
2983 : : const struct in6_addr *gateway)
2984 : : {
2985 : : int flags = RT6_LOOKUP_F_HAS_SADDR;
2986 : : struct ip6rd_flowi rdfl;
2987 : :
2988 : : rdfl.fl6 = *fl6;
2989 : : rdfl.gateway = *gateway;
2990 : :
2991 : : return fib6_rule_lookup(net, &rdfl.fl6, skb,
2992 : : flags, __ip6_route_redirect);
2993 : : }
2994 : :
2995 : 0 : void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2996 : : kuid_t uid)
2997 : : {
2998 : 0 : const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2999 : 0 : struct dst_entry *dst;
3000 : 0 : struct flowi6 fl6 = {
3001 : : .flowi6_iif = LOOPBACK_IFINDEX,
3002 : : .flowi6_oif = oif,
3003 : : .flowi6_mark = mark,
3004 : : .daddr = iph->daddr,
3005 : : .saddr = iph->saddr,
3006 : : .flowlabel = ip6_flowinfo(iph),
3007 : : .flowi6_uid = uid,
3008 : : };
3009 : :
3010 : 0 : dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
3011 : 0 : rt6_do_redirect(dst, NULL, skb);
3012 : 0 : dst_release(dst);
3013 : 0 : }
3014 : : EXPORT_SYMBOL_GPL(ip6_redirect);
3015 : :
3016 : 0 : void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
3017 : : {
3018 : 0 : const struct ipv6hdr *iph = ipv6_hdr(skb);
3019 : 0 : const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
3020 : 0 : struct dst_entry *dst;
3021 : 0 : struct flowi6 fl6 = {
3022 : : .flowi6_iif = LOOPBACK_IFINDEX,
3023 : : .flowi6_oif = oif,
3024 : : .daddr = msg->dest,
3025 : : .saddr = iph->daddr,
3026 : 0 : .flowi6_uid = sock_net_uid(net, NULL),
3027 : : };
3028 : :
3029 : 0 : dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
3030 : 0 : rt6_do_redirect(dst, NULL, skb);
3031 : 0 : dst_release(dst);
3032 : 0 : }
3033 : :
3034 : 0 : void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
3035 : : {
3036 : 0 : ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
3037 : : sk->sk_uid);
3038 : 0 : }
3039 : : EXPORT_SYMBOL_GPL(ip6_sk_redirect);
3040 : :
3041 : 0 : static unsigned int ip6_default_advmss(const struct dst_entry *dst)
3042 : : {
3043 : 0 : struct net_device *dev = dst->dev;
3044 : 0 : unsigned int mtu = dst_mtu(dst);
3045 [ # # ]: 0 : struct net *net = dev_net(dev);
3046 : :
3047 : 0 : mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
3048 : :
3049 : 0 : if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
3050 : : mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
3051 : :
3052 : : /*
3053 : : * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
3054 : : * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
3055 : : * IPV6_MAXPLEN is also valid and means: "any MSS,
3056 : : * rely only on pmtu discovery"
3057 : : */
3058 [ # # ]: 0 : if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
3059 : 0 : mtu = IPV6_MAXPLEN;
3060 : 0 : return mtu;
3061 : : }
3062 : :
3063 : 166 : static unsigned int ip6_mtu(const struct dst_entry *dst)
3064 : : {
3065 : 166 : struct inet6_dev *idev;
3066 : 166 : unsigned int mtu;
3067 : :
3068 [ - + ]: 166 : mtu = dst_metric_raw(dst, RTAX_MTU);
3069 [ - + ]: 166 : if (mtu)
3070 : 0 : goto out;
3071 : :
3072 : 166 : mtu = IPV6_MIN_MTU;
3073 : :
3074 : 166 : rcu_read_lock();
3075 [ + - ]: 166 : idev = __in6_dev_get(dst->dev);
3076 [ + - ]: 166 : if (idev)
3077 : 166 : mtu = idev->cnf.mtu6;
3078 : 166 : rcu_read_unlock();
3079 : :
3080 : 166 : out:
3081 : 166 : mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
3082 : :
3083 : 166 : return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
3084 : : }
3085 : :
3086 : : /* MTU selection:
3087 : : * 1. mtu on route is locked - use it
3088 : : * 2. mtu from nexthop exception
3089 : : * 3. mtu from egress device
3090 : : *
3091 : : * based on ip6_dst_mtu_forward and exception logic of
3092 : : * rt6_find_cached_rt; called with rcu_read_lock
3093 : : */
3094 : 0 : u32 ip6_mtu_from_fib6(const struct fib6_result *res,
3095 : : const struct in6_addr *daddr,
3096 : : const struct in6_addr *saddr)
3097 : : {
3098 : 0 : const struct fib6_nh *nh = res->nh;
3099 : 0 : struct fib6_info *f6i = res->f6i;
3100 : 0 : struct inet6_dev *idev;
3101 : 0 : struct rt6_info *rt;
3102 : 0 : u32 mtu = 0;
3103 : :
3104 [ # # ]: 0 : if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
3105 : 0 : mtu = f6i->fib6_pmtu;
3106 [ # # ]: 0 : if (mtu)
3107 : 0 : goto out;
3108 : : }
3109 : :
3110 : 0 : rt = rt6_find_cached_rt(res, daddr, saddr);
3111 [ # # ]: 0 : if (unlikely(rt)) {
3112 : 0 : mtu = dst_metric_raw(&rt->dst, RTAX_MTU);
3113 : : } else {
3114 : 0 : struct net_device *dev = nh->fib_nh_dev;
3115 : :
3116 : 0 : mtu = IPV6_MIN_MTU;
3117 [ # # ]: 0 : idev = __in6_dev_get(dev);
3118 [ # # ]: 0 : if (idev && idev->cnf.mtu6 > mtu)
3119 : : mtu = idev->cnf.mtu6;
3120 : : }
3121 : :
3122 : 0 : mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
3123 : 0 : out:
3124 : 0 : return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu);
3125 : : }
3126 : :
3127 : 166 : struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
3128 : : struct flowi6 *fl6)
3129 : : {
3130 : 166 : struct dst_entry *dst;
3131 : 166 : struct rt6_info *rt;
3132 : 166 : struct inet6_dev *idev = in6_dev_get(dev);
3133 [ + - ]: 166 : struct net *net = dev_net(dev);
3134 : :
3135 [ + - ]: 166 : if (unlikely(!idev))
3136 : : return ERR_PTR(-ENODEV);
3137 : :
3138 : 166 : rt = ip6_dst_alloc(net, dev, 0);
3139 [ - + ]: 166 : if (unlikely(!rt)) {
3140 : 0 : in6_dev_put(idev);
3141 : 0 : dst = ERR_PTR(-ENOMEM);
3142 : 0 : goto out;
3143 : : }
3144 : :
3145 : 166 : rt->dst.flags |= DST_HOST;
3146 : 166 : rt->dst.input = ip6_input;
3147 : 166 : rt->dst.output = ip6_output;
3148 : 166 : rt->rt6i_gateway = fl6->daddr;
3149 : 166 : rt->rt6i_dst.addr = fl6->daddr;
3150 : 166 : rt->rt6i_dst.plen = 128;
3151 : 166 : rt->rt6i_idev = idev;
3152 : 166 : dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
3153 : :
3154 : : /* Add this dst into uncached_list so that rt6_disable_ip() can
3155 : : * do proper release of the net_device
3156 : : */
3157 : 166 : rt6_uncached_list_add(rt);
3158 : 166 : atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
3159 : :
3160 : 166 : dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
3161 : :
3162 : : out:
3163 : : return dst;
3164 : : }
3165 : :
3166 : 0 : static int ip6_dst_gc(struct dst_ops *ops)
3167 : : {
3168 : 0 : struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
3169 : 0 : int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
3170 : 0 : int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
3171 : 0 : int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
3172 : 0 : int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
3173 : 0 : unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
3174 : 0 : int entries;
3175 : :
3176 : 0 : entries = dst_entries_get_fast(ops);
3177 [ # # # # ]: 0 : if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
3178 : : entries <= rt_max_size)
3179 : 0 : goto out;
3180 : :
3181 : 0 : net->ipv6.ip6_rt_gc_expire++;
3182 : 0 : fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
3183 : 0 : entries = dst_entries_get_slow(ops);
3184 [ # # ]: 0 : if (entries < ops->gc_thresh)
3185 : 0 : net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
3186 : 0 : out:
3187 : 0 : net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
3188 : 0 : return entries > rt_max_size;
3189 : : }
3190 : :
3191 : : static int ip6_nh_lookup_table(struct net *net, struct fib6_config *cfg,
3192 : : const struct in6_addr *gw_addr, u32 tbid,
3193 : : int flags, struct fib6_result *res)
3194 : : {
3195 : : struct flowi6 fl6 = {
3196 : : .flowi6_oif = cfg->fc_ifindex,
3197 : : .daddr = *gw_addr,
3198 : : .saddr = cfg->fc_prefsrc,
3199 : : };
3200 : : struct fib6_table *table;
3201 : : int err;
3202 : :
3203 : : table = fib6_get_table(net, tbid);
3204 : : if (!table)
3205 : : return -EINVAL;
3206 : :
3207 : : if (!ipv6_addr_any(&cfg->fc_prefsrc))
3208 : : flags |= RT6_LOOKUP_F_HAS_SADDR;
3209 : :
3210 : : flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
3211 : :
3212 : : err = fib6_table_lookup(net, table, cfg->fc_ifindex, &fl6, res, flags);
3213 : : if (!err && res->f6i != net->ipv6.fib6_null_entry)
3214 : : fib6_select_path(net, res, &fl6, cfg->fc_ifindex,
3215 : : cfg->fc_ifindex != 0, NULL, flags);
3216 : :
3217 : : return err;
3218 : : }
3219 : :
3220 : 0 : static int ip6_route_check_nh_onlink(struct net *net,
3221 : : struct fib6_config *cfg,
3222 : : const struct net_device *dev,
3223 : : struct netlink_ext_ack *extack)
3224 : : {
3225 : 0 : u32 tbid = l3mdev_fib_table_rcu(dev) ? : RT_TABLE_MAIN;
3226 : 0 : const struct in6_addr *gw_addr = &cfg->fc_gateway;
3227 : 0 : struct fib6_result res = {};
3228 : 0 : int err;
3229 : :
3230 : 0 : err = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0, &res);
3231 [ # # # # : 0 : if (!err && !(res.fib6_flags & RTF_REJECT) &&
# # ]
3232 : : /* ignore match if it is the default route */
3233 [ # # ]: 0 : !ipv6_addr_any(&res.f6i->fib6_dst.addr) &&
3234 [ # # # # ]: 0 : (res.fib6_type != RTN_UNICAST || dev != res.nh->fib_nh_dev)) {
3235 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
3236 : : "Nexthop has invalid gateway or device mismatch");
3237 : : err = -EINVAL;
3238 : : }
3239 : :
3240 : 0 : return err;
3241 : : }
3242 : :
3243 : 0 : static int ip6_route_check_nh(struct net *net,
3244 : : struct fib6_config *cfg,
3245 : : struct net_device **_dev,
3246 : : struct inet6_dev **idev)
3247 : : {
3248 : 0 : const struct in6_addr *gw_addr = &cfg->fc_gateway;
3249 [ # # ]: 0 : struct net_device *dev = _dev ? *_dev : NULL;
3250 : 0 : int flags = RT6_LOOKUP_F_IFACE;
3251 : 0 : struct fib6_result res = {};
3252 : 0 : int err = -EHOSTUNREACH;
3253 : :
3254 [ # # ]: 0 : if (cfg->fc_table) {
3255 : 0 : err = ip6_nh_lookup_table(net, cfg, gw_addr,
3256 : : cfg->fc_table, flags, &res);
3257 : : /* gw_addr can not require a gateway or resolve to a reject
3258 : : * route. If a device is given, it must match the result.
3259 : : */
3260 [ # # # # ]: 0 : if (err || res.fib6_flags & RTF_REJECT ||
3261 [ # # # # ]: 0 : res.nh->fib_nh_gw_family ||
3262 [ # # ]: 0 : (dev && dev != res.nh->fib_nh_dev))
3263 : : err = -EHOSTUNREACH;
3264 : : }
3265 : :
3266 : : if (err < 0) {
3267 : 0 : struct flowi6 fl6 = {
3268 : 0 : .flowi6_oif = cfg->fc_ifindex,
3269 : : .daddr = *gw_addr,
3270 : : };
3271 : :
3272 : 0 : err = fib6_lookup(net, cfg->fc_ifindex, &fl6, &res, flags);
3273 [ # # # # ]: 0 : if (err || res.fib6_flags & RTF_REJECT ||
3274 [ # # ]: 0 : res.nh->fib_nh_gw_family)
3275 : 0 : err = -EHOSTUNREACH;
3276 : :
3277 : 0 : if (err)
3278 : 0 : return err;
3279 : :
3280 : 0 : fib6_select_path(net, &res, &fl6, cfg->fc_ifindex,
3281 : 0 : cfg->fc_ifindex != 0, NULL, flags);
3282 : : }
3283 : :
3284 : 0 : err = 0;
3285 [ # # ]: 0 : if (dev) {
3286 [ # # ]: 0 : if (dev != res.nh->fib_nh_dev)
3287 : 0 : err = -EHOSTUNREACH;
3288 : : } else {
3289 : 0 : *_dev = dev = res.nh->fib_nh_dev;
3290 : 0 : dev_hold(dev);
3291 : 0 : *idev = in6_dev_get(dev);
3292 : : }
3293 : :
3294 : : return err;
3295 : : }
3296 : :
3297 : 0 : static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
3298 : : struct net_device **_dev, struct inet6_dev **idev,
3299 : : struct netlink_ext_ack *extack)
3300 : : {
3301 : 0 : const struct in6_addr *gw_addr = &cfg->fc_gateway;
3302 : 0 : int gwa_type = ipv6_addr_type(gw_addr);
3303 : 0 : bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
3304 : 0 : const struct net_device *dev = *_dev;
3305 : 0 : bool need_addr_check = !dev;
3306 : 0 : int err = -EINVAL;
3307 : :
3308 : : /* if gw_addr is local we will fail to detect this in case
3309 : : * address is still TENTATIVE (DAD in progress). rt6_lookup()
3310 : : * will return already-added prefix route via interface that
3311 : : * prefix route was assigned to, which might be non-loopback.
3312 : : */
3313 [ # # # # ]: 0 : if (dev &&
3314 : 0 : ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
3315 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
3316 : 0 : goto out;
3317 : : }
3318 : :
3319 [ # # ]: 0 : if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
3320 : : /* IPv6 strictly inhibits using not link-local
3321 : : * addresses as nexthop address.
3322 : : * Otherwise, router will not able to send redirects.
3323 : : * It is very good, but in some (rare!) circumstances
3324 : : * (SIT, PtP, NBMA NOARP links) it is handy to allow
3325 : : * some exceptions. --ANK
3326 : : * We allow IPv4-mapped nexthops to support RFC4798-type
3327 : : * addressing
3328 : : */
3329 [ # # ]: 0 : if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
3330 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Invalid gateway address");
3331 : 0 : goto out;
3332 : : }
3333 : :
3334 : 0 : rcu_read_lock();
3335 : :
3336 [ # # ]: 0 : if (cfg->fc_flags & RTNH_F_ONLINK)
3337 : 0 : err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
3338 : : else
3339 : 0 : err = ip6_route_check_nh(net, cfg, _dev, idev);
3340 : :
3341 : 0 : rcu_read_unlock();
3342 : :
3343 [ # # ]: 0 : if (err)
3344 : 0 : goto out;
3345 : : }
3346 : :
3347 : : /* reload in case device was changed */
3348 : 0 : dev = *_dev;
3349 : :
3350 : 0 : err = -EINVAL;
3351 [ # # ]: 0 : if (!dev) {
3352 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Egress device not specified");
3353 : 0 : goto out;
3354 [ # # ]: 0 : } else if (dev->flags & IFF_LOOPBACK) {
3355 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
3356 : : "Egress device can not be loopback device for this route");
3357 : 0 : goto out;
3358 : : }
3359 : :
3360 : : /* if we did not check gw_addr above, do so now that the
3361 : : * egress device has been resolved.
3362 : : */
3363 [ # # # # ]: 0 : if (need_addr_check &&
3364 : 0 : ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
3365 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
3366 : 0 : goto out;
3367 : : }
3368 : :
3369 : : err = 0;
3370 : 0 : out:
3371 : 0 : return err;
3372 : : }
3373 : :
3374 : 714 : static bool fib6_is_reject(u32 flags, struct net_device *dev, int addr_type)
3375 : : {
3376 [ + - + - ]: 714 : if ((flags & RTF_REJECT) ||
3377 [ + + + + ]: 714 : (dev && (dev->flags & IFF_LOOPBACK) &&
3378 [ - + - + ]: 546 : !(addr_type & IPV6_ADDR_LOOPBACK) &&
3379 [ # # # # ]: 0 : !(flags & RTF_LOCAL)))
3380 : 0 : return true;
3381 : :
3382 : : return false;
3383 : : }
3384 : :
3385 : 396 : int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
3386 : : struct fib6_config *cfg, gfp_t gfp_flags,
3387 : : struct netlink_ext_ack *extack)
3388 : : {
3389 : 396 : struct net_device *dev = NULL;
3390 : 396 : struct inet6_dev *idev = NULL;
3391 : 396 : int addr_type;
3392 : 396 : int err;
3393 : :
3394 : 396 : fib6_nh->fib_nh_family = AF_INET6;
3395 : : #ifdef CONFIG_IPV6_ROUTER_PREF
3396 : : fib6_nh->last_probe = jiffies;
3397 : : #endif
3398 : :
3399 : 396 : err = -ENODEV;
3400 [ + - ]: 396 : if (cfg->fc_ifindex) {
3401 : 396 : dev = dev_get_by_index(net, cfg->fc_ifindex);
3402 [ - + ]: 396 : if (!dev)
3403 : 0 : goto out;
3404 : 396 : idev = in6_dev_get(dev);
3405 [ - + ]: 396 : if (!idev)
3406 : 0 : goto out;
3407 : : }
3408 : :
3409 [ - + ]: 396 : if (cfg->fc_flags & RTNH_F_ONLINK) {
3410 [ # # ]: 0 : if (!dev) {
3411 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
3412 : : "Nexthop device required for onlink");
3413 : 0 : goto out;
3414 : : }
3415 : :
3416 [ # # ]: 0 : if (!(dev->flags & IFF_UP)) {
3417 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3418 : 0 : err = -ENETDOWN;
3419 : 0 : goto out;
3420 : : }
3421 : :
3422 : 0 : fib6_nh->fib_nh_flags |= RTNH_F_ONLINK;
3423 : : }
3424 : :
3425 : 396 : fib6_nh->fib_nh_weight = 1;
3426 : :
3427 : : /* We cannot add true routes via loopback here,
3428 : : * they would result in kernel looping; promote them to reject routes
3429 : : */
3430 : 396 : addr_type = ipv6_addr_type(&cfg->fc_dst);
3431 [ + - ]: 396 : if (fib6_is_reject(cfg->fc_flags, dev, addr_type)) {
3432 : : /* hold loopback dev/idev if we haven't done so. */
3433 [ # # ]: 0 : if (dev != net->loopback_dev) {
3434 [ # # ]: 0 : if (dev) {
3435 : 0 : dev_put(dev);
3436 : 0 : in6_dev_put(idev);
3437 : : }
3438 : 0 : dev = net->loopback_dev;
3439 : 0 : dev_hold(dev);
3440 : 0 : idev = in6_dev_get(dev);
3441 [ # # ]: 0 : if (!idev) {
3442 : 0 : err = -ENODEV;
3443 : 0 : goto out;
3444 : : }
3445 : : }
3446 : 0 : goto pcpu_alloc;
3447 : : }
3448 : :
3449 [ - + ]: 396 : if (cfg->fc_flags & RTF_GATEWAY) {
3450 : 0 : err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3451 [ # # ]: 0 : if (err)
3452 : 0 : goto out;
3453 : :
3454 : 0 : fib6_nh->fib_nh_gw6 = cfg->fc_gateway;
3455 : 0 : fib6_nh->fib_nh_gw_family = AF_INET6;
3456 : : }
3457 : :
3458 : 396 : err = -ENODEV;
3459 [ - + ]: 396 : if (!dev)
3460 : 0 : goto out;
3461 : :
3462 [ - + ]: 396 : if (idev->cnf.disable_ipv6) {
3463 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3464 : 0 : err = -EACCES;
3465 : 0 : goto out;
3466 : : }
3467 : :
3468 [ + + + + ]: 396 : if (!(dev->flags & IFF_UP) && !cfg->fc_ignore_dev_down) {
3469 [ - + ]: 78 : NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3470 : 78 : err = -ENETDOWN;
3471 : 78 : goto out;
3472 : : }
3473 : :
3474 [ + + - + ]: 452 : if (!(cfg->fc_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
3475 : : !netif_carrier_ok(dev))
3476 : 0 : fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN;
3477 : :
3478 : 318 : err = fib_nh_common_init(&fib6_nh->nh_common, cfg->fc_encap,
3479 : 318 : cfg->fc_encap_type, cfg, gfp_flags, extack);
3480 [ - + ]: 318 : if (err)
3481 : 0 : goto out;
3482 : :
3483 : 318 : pcpu_alloc:
3484 : 318 : fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags);
3485 [ - + ]: 318 : if (!fib6_nh->rt6i_pcpu) {
3486 : 0 : err = -ENOMEM;
3487 : 0 : goto out;
3488 : : }
3489 : :
3490 : 318 : fib6_nh->fib_nh_dev = dev;
3491 : 318 : fib6_nh->fib_nh_oif = dev->ifindex;
3492 : 318 : err = 0;
3493 : 396 : out:
3494 [ + - ]: 396 : if (idev)
3495 : 396 : in6_dev_put(idev);
3496 : :
3497 [ + + ]: 396 : if (err) {
3498 [ + - ]: 78 : lwtstate_put(fib6_nh->fib_nh_lws);
3499 : 78 : fib6_nh->fib_nh_lws = NULL;
3500 [ + - ]: 78 : if (dev)
3501 : 78 : dev_put(dev);
3502 : : }
3503 : :
3504 : 396 : return err;
3505 : : }
3506 : :
3507 : 156 : void fib6_nh_release(struct fib6_nh *fib6_nh)
3508 : : {
3509 : 156 : struct rt6_exception_bucket *bucket;
3510 : :
3511 : 156 : rcu_read_lock();
3512 : :
3513 : 156 : fib6_nh_flush_exceptions(fib6_nh, NULL);
3514 [ - + ]: 156 : bucket = fib6_nh_get_excptn_bucket(fib6_nh, NULL);
3515 [ - + ]: 156 : if (bucket) {
3516 : 0 : rcu_assign_pointer(fib6_nh->rt6i_exception_bucket, NULL);
3517 : 0 : kfree(bucket);
3518 : : }
3519 : :
3520 : 156 : rcu_read_unlock();
3521 : :
3522 [ + + ]: 156 : if (fib6_nh->rt6i_pcpu) {
3523 : : int cpu;
3524 : :
3525 [ + + ]: 156 : for_each_possible_cpu(cpu) {
3526 : 78 : struct rt6_info **ppcpu_rt;
3527 : 78 : struct rt6_info *pcpu_rt;
3528 : :
3529 : 78 : ppcpu_rt = per_cpu_ptr(fib6_nh->rt6i_pcpu, cpu);
3530 : 78 : pcpu_rt = *ppcpu_rt;
3531 [ - + ]: 78 : if (pcpu_rt) {
3532 : 0 : dst_dev_put(&pcpu_rt->dst);
3533 : 0 : dst_release(&pcpu_rt->dst);
3534 : 0 : *ppcpu_rt = NULL;
3535 : : }
3536 : : }
3537 : :
3538 : 78 : free_percpu(fib6_nh->rt6i_pcpu);
3539 : : }
3540 : :
3541 : 156 : fib_nh_common_release(&fib6_nh->nh_common);
3542 : 156 : }
3543 : :
3544 : 396 : static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
3545 : : gfp_t gfp_flags,
3546 : : struct netlink_ext_ack *extack)
3547 : : {
3548 : 396 : struct net *net = cfg->fc_nlinfo.nl_net;
3549 : 396 : struct fib6_info *rt = NULL;
3550 : 396 : struct nexthop *nh = NULL;
3551 : 396 : struct fib6_table *table;
3552 : 396 : struct fib6_nh *fib6_nh;
3553 : 396 : int err = -EINVAL;
3554 : 396 : int addr_type;
3555 : :
3556 : : /* RTF_PCPU is an internal flag; can not be set by userspace */
3557 [ - + ]: 396 : if (cfg->fc_flags & RTF_PCPU) {
3558 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
3559 : 0 : goto out;
3560 : : }
3561 : :
3562 : : /* RTF_CACHE is an internal flag; can not be set by userspace */
3563 [ - + ]: 396 : if (cfg->fc_flags & RTF_CACHE) {
3564 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
3565 : 0 : goto out;
3566 : : }
3567 : :
3568 [ - + ]: 396 : if (cfg->fc_type > RTN_MAX) {
3569 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Invalid route type");
3570 : 0 : goto out;
3571 : : }
3572 : :
3573 [ - + ]: 396 : if (cfg->fc_dst_len > 128) {
3574 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Invalid prefix length");
3575 : 0 : goto out;
3576 : : }
3577 [ - + ]: 396 : if (cfg->fc_src_len > 128) {
3578 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Invalid source address length");
3579 : 0 : goto out;
3580 : : }
3581 : : #ifndef CONFIG_IPV6_SUBTREES
3582 [ - + ]: 396 : if (cfg->fc_src_len) {
3583 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
3584 : : "Specifying source address requires IPV6_SUBTREES to be enabled");
3585 : 0 : goto out;
3586 : : }
3587 : : #endif
3588 [ - + ]: 396 : if (cfg->fc_nh_id) {
3589 : 0 : nh = nexthop_find_by_id(net, cfg->fc_nh_id);
3590 [ # # ]: 0 : if (!nh) {
3591 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Nexthop id does not exist");
3592 : 0 : goto out;
3593 : : }
3594 : 0 : err = fib6_check_nexthop(nh, cfg, extack);
3595 [ # # ]: 0 : if (err)
3596 : 0 : goto out;
3597 : : }
3598 : :
3599 : 396 : err = -ENOBUFS;
3600 [ - + ]: 396 : if (cfg->fc_nlinfo.nlh &&
3601 [ # # ]: 0 : !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
3602 : 0 : table = fib6_get_table(net, cfg->fc_table);
3603 [ # # ]: 0 : if (!table) {
3604 : 0 : pr_warn("NLM_F_CREATE should be specified when creating new route\n");
3605 : 0 : table = fib6_new_table(net, cfg->fc_table);
3606 : : }
3607 : : } else {
3608 : 396 : table = fib6_new_table(net, cfg->fc_table);
3609 : : }
3610 : :
3611 [ - + ]: 396 : if (!table)
3612 : 0 : goto out;
3613 : :
3614 : 396 : err = -ENOMEM;
3615 : 396 : rt = fib6_info_alloc(gfp_flags, !nh);
3616 [ - + ]: 396 : if (!rt)
3617 : 0 : goto out;
3618 : :
3619 : 396 : rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
3620 : : extack);
3621 [ - + ]: 396 : if (IS_ERR(rt->fib6_metrics)) {
3622 : 0 : err = PTR_ERR(rt->fib6_metrics);
3623 : : /* Do not leave garbage there. */
3624 : 0 : rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
3625 : 0 : goto out;
3626 : : }
3627 : :
3628 [ - + ]: 396 : if (cfg->fc_flags & RTF_ADDRCONF)
3629 : 0 : rt->dst_nocount = true;
3630 : :
3631 [ - + ]: 396 : if (cfg->fc_flags & RTF_EXPIRES)
3632 : 0 : fib6_set_expires(rt, jiffies +
3633 : 0 : clock_t_to_jiffies(cfg->fc_expires));
3634 : : else
3635 : 396 : fib6_clean_expires(rt);
3636 : :
3637 [ + + ]: 396 : if (cfg->fc_protocol == RTPROT_UNSPEC)
3638 : 28 : cfg->fc_protocol = RTPROT_BOOT;
3639 : 396 : rt->fib6_protocol = cfg->fc_protocol;
3640 : :
3641 : 396 : rt->fib6_table = table;
3642 : 396 : rt->fib6_metric = cfg->fc_metric;
3643 : 396 : rt->fib6_type = cfg->fc_type ? : RTN_UNICAST;
3644 : 396 : rt->fib6_flags = cfg->fc_flags & ~RTF_GATEWAY;
3645 : :
3646 : 396 : ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3647 : 396 : rt->fib6_dst.plen = cfg->fc_dst_len;
3648 [ + + ]: 396 : if (rt->fib6_dst.plen == 128)
3649 : 340 : rt->dst_host = true;
3650 : :
3651 : : #ifdef CONFIG_IPV6_SUBTREES
3652 : : ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3653 : : rt->fib6_src.plen = cfg->fc_src_len;
3654 : : #endif
3655 [ - + ]: 396 : if (nh) {
3656 [ # # ]: 0 : if (!nexthop_get(nh)) {
3657 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Nexthop has been deleted");
3658 : 0 : goto out;
3659 : : }
3660 [ # # ]: 0 : if (rt->fib6_src.plen) {
3661 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Nexthops can not be used with source routing");
3662 : 0 : goto out;
3663 : : }
3664 : 0 : rt->nh = nh;
3665 [ # # ]: 0 : fib6_nh = nexthop_fib6_nh(rt->nh);
3666 : : } else {
3667 : 396 : err = fib6_nh_init(net, rt->fib6_nh, cfg, gfp_flags, extack);
3668 [ + + ]: 396 : if (err)
3669 : 78 : goto out;
3670 : :
3671 : 318 : fib6_nh = rt->fib6_nh;
3672 : :
3673 : : /* We cannot add true routes via loopback here, they would
3674 : : * result in kernel looping; promote them to reject routes
3675 : : */
3676 : 318 : addr_type = ipv6_addr_type(&cfg->fc_dst);
3677 [ + - ]: 318 : if (fib6_is_reject(cfg->fc_flags, rt->fib6_nh->fib_nh_dev,
3678 : : addr_type))
3679 : 0 : rt->fib6_flags = RTF_REJECT | RTF_NONEXTHOP;
3680 : : }
3681 : :
3682 [ - + ]: 318 : if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
3683 : 0 : struct net_device *dev = fib6_nh->fib_nh_dev;
3684 : :
3685 [ # # ]: 0 : if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
3686 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Invalid source address");
3687 : 0 : err = -EINVAL;
3688 : 0 : goto out;
3689 : : }
3690 : 0 : rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3691 : 0 : rt->fib6_prefsrc.plen = 128;
3692 : : } else
3693 : 318 : rt->fib6_prefsrc.plen = 0;
3694 : :
3695 : : return rt;
3696 : 78 : out:
3697 : 78 : fib6_info_release(rt);
3698 : 78 : return ERR_PTR(err);
3699 : : }
3700 : :
3701 : 212 : int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
3702 : : struct netlink_ext_ack *extack)
3703 : : {
3704 : 212 : struct fib6_info *rt;
3705 : 212 : int err;
3706 : :
3707 : 212 : rt = ip6_route_info_create(cfg, gfp_flags, extack);
3708 [ + + ]: 212 : if (IS_ERR(rt))
3709 : 78 : return PTR_ERR(rt);
3710 : :
3711 : 134 : err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
3712 : 134 : fib6_info_release(rt);
3713 : :
3714 : 134 : return err;
3715 : : }
3716 : :
3717 : 0 : static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
3718 : : {
3719 : 0 : struct net *net = info->nl_net;
3720 : 0 : struct fib6_table *table;
3721 : 0 : int err;
3722 : :
3723 [ # # ]: 0 : if (rt == net->ipv6.fib6_null_entry) {
3724 : 0 : err = -ENOENT;
3725 : 0 : goto out;
3726 : : }
3727 : :
3728 : 0 : table = rt->fib6_table;
3729 : 0 : spin_lock_bh(&table->tb6_lock);
3730 : 0 : err = fib6_del(rt, info);
3731 : 0 : spin_unlock_bh(&table->tb6_lock);
3732 : :
3733 : 0 : out:
3734 : 0 : fib6_info_release(rt);
3735 : 0 : return err;
3736 : : }
3737 : :
3738 : 0 : int ip6_del_rt(struct net *net, struct fib6_info *rt)
3739 : : {
3740 : 0 : struct nl_info info = { .nl_net = net };
3741 : :
3742 : 0 : return __ip6_del_rt(rt, &info);
3743 : : }
3744 : :
3745 : 0 : static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
3746 : : {
3747 : 0 : struct nl_info *info = &cfg->fc_nlinfo;
3748 : 0 : struct net *net = info->nl_net;
3749 : 0 : struct sk_buff *skb = NULL;
3750 : 0 : struct fib6_table *table;
3751 : 0 : int err = -ENOENT;
3752 : :
3753 [ # # ]: 0 : if (rt == net->ipv6.fib6_null_entry)
3754 : 0 : goto out_put;
3755 : 0 : table = rt->fib6_table;
3756 : 0 : spin_lock_bh(&table->tb6_lock);
3757 : :
3758 [ # # # # ]: 0 : if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
3759 : 0 : struct fib6_info *sibling, *next_sibling;
3760 : 0 : struct fib6_node *fn;
3761 : :
3762 : : /* prefer to send a single notification with all hops */
3763 [ # # ]: 0 : skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3764 [ # # ]: 0 : if (skb) {
3765 [ # # ]: 0 : u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3766 : :
3767 [ # # ]: 0 : if (rt6_fill_node(net, skb, rt, NULL,
3768 : : NULL, NULL, 0, RTM_DELROUTE,
3769 : : info->portid, seq, 0) < 0) {
3770 : 0 : kfree_skb(skb);
3771 : 0 : skb = NULL;
3772 : : } else
3773 : 0 : info->skip_notify = 1;
3774 : : }
3775 : :
3776 : : /* 'rt' points to the first sibling route. If it is not the
3777 : : * leaf, then we do not need to send a notification. Otherwise,
3778 : : * we need to check if the last sibling has a next route or not
3779 : : * and emit a replace or delete notification, respectively.
3780 : : */
3781 : 0 : info->skip_notify_kernel = 1;
3782 : 0 : fn = rcu_dereference_protected(rt->fib6_node,
3783 : : lockdep_is_held(&table->tb6_lock));
3784 [ # # ]: 0 : if (rcu_access_pointer(fn->leaf) == rt) {
3785 : 0 : struct fib6_info *last_sibling, *replace_rt;
3786 : :
3787 : 0 : last_sibling = list_last_entry(&rt->fib6_siblings,
3788 : : struct fib6_info,
3789 : : fib6_siblings);
3790 : 0 : replace_rt = rcu_dereference_protected(
3791 : : last_sibling->fib6_next,
3792 : : lockdep_is_held(&table->tb6_lock));
3793 [ # # ]: 0 : if (replace_rt)
3794 : 0 : call_fib6_entry_notifiers_replace(net,
3795 : : replace_rt);
3796 : : else
3797 : 0 : call_fib6_multipath_entry_notifiers(net,
3798 : : FIB_EVENT_ENTRY_DEL,
3799 : : rt, rt->fib6_nsiblings,
3800 : : NULL);
3801 : : }
3802 [ # # ]: 0 : list_for_each_entry_safe(sibling, next_sibling,
3803 : : &rt->fib6_siblings,
3804 : : fib6_siblings) {
3805 : 0 : err = fib6_del(sibling, info);
3806 [ # # ]: 0 : if (err)
3807 : 0 : goto out_unlock;
3808 : : }
3809 : : }
3810 : :
3811 : 0 : err = fib6_del(rt, info);
3812 : 0 : out_unlock:
3813 : 0 : spin_unlock_bh(&table->tb6_lock);
3814 : 0 : out_put:
3815 : 0 : fib6_info_release(rt);
3816 : :
3817 [ # # ]: 0 : if (skb) {
3818 [ # # ]: 0 : rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
3819 : : info->nlh, gfp_any());
3820 : : }
3821 : 0 : return err;
3822 : : }
3823 : :
3824 : 0 : static int __ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3825 : : {
3826 : 0 : int rc = -ESRCH;
3827 : :
3828 [ # # # # ]: 0 : if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3829 : 0 : goto out;
3830 : :
3831 [ # # # # ]: 0 : if (cfg->fc_flags & RTF_GATEWAY &&
3832 : : !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3833 : 0 : goto out;
3834 : :
3835 : 0 : rc = rt6_remove_exception_rt(rt);
3836 : 0 : out:
3837 : 0 : return rc;
3838 : : }
3839 : :
3840 : : static int ip6_del_cached_rt(struct fib6_config *cfg, struct fib6_info *rt,
3841 : : struct fib6_nh *nh)
3842 : : {
3843 : : struct fib6_result res = {
3844 : : .f6i = rt,
3845 : : .nh = nh,
3846 : : };
3847 : : struct rt6_info *rt_cache;
3848 : :
3849 : : rt_cache = rt6_find_cached_rt(&res, &cfg->fc_dst, &cfg->fc_src);
3850 : : if (rt_cache)
3851 : : return __ip6_del_cached_rt(rt_cache, cfg);
3852 : :
3853 : : return 0;
3854 : : }
3855 : :
3856 : : struct fib6_nh_del_cached_rt_arg {
3857 : : struct fib6_config *cfg;
3858 : : struct fib6_info *f6i;
3859 : : };
3860 : :
3861 : 0 : static int fib6_nh_del_cached_rt(struct fib6_nh *nh, void *_arg)
3862 : : {
3863 : 0 : struct fib6_nh_del_cached_rt_arg *arg = _arg;
3864 : 0 : int rc;
3865 : :
3866 : 0 : rc = ip6_del_cached_rt(arg->cfg, arg->f6i, nh);
3867 [ # # ]: 0 : return rc != -ESRCH ? rc : 0;
3868 : : }
3869 : :
3870 : 0 : static int ip6_del_cached_rt_nh(struct fib6_config *cfg, struct fib6_info *f6i)
3871 : : {
3872 : 0 : struct fib6_nh_del_cached_rt_arg arg = {
3873 : : .cfg = cfg,
3874 : : .f6i = f6i
3875 : : };
3876 : :
3877 : 0 : return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_del_cached_rt, &arg);
3878 : : }
3879 : :
3880 : 0 : static int ip6_route_del(struct fib6_config *cfg,
3881 : : struct netlink_ext_ack *extack)
3882 : : {
3883 : 0 : struct fib6_table *table;
3884 : 0 : struct fib6_info *rt;
3885 : 0 : struct fib6_node *fn;
3886 : 0 : int err = -ESRCH;
3887 : :
3888 : 0 : table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
3889 [ # # ]: 0 : if (!table) {
3890 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "FIB table does not exist");
3891 : 0 : return err;
3892 : : }
3893 : :
3894 : 0 : rcu_read_lock();
3895 : :
3896 : 0 : fn = fib6_locate(&table->tb6_root,
3897 : 0 : &cfg->fc_dst, cfg->fc_dst_len,
3898 : 0 : &cfg->fc_src, cfg->fc_src_len,
3899 : 0 : !(cfg->fc_flags & RTF_CACHE));
3900 : :
3901 [ # # ]: 0 : if (fn) {
3902 [ # # ]: 0 : for_each_fib6_node_rt_rcu(fn) {
3903 : 0 : struct fib6_nh *nh;
3904 : :
3905 [ # # # # ]: 0 : if (rt->nh && cfg->fc_nh_id &&
3906 [ # # ]: 0 : rt->nh->id != cfg->fc_nh_id)
3907 : 0 : continue;
3908 : :
3909 [ # # ]: 0 : if (cfg->fc_flags & RTF_CACHE) {
3910 : 0 : int rc = 0;
3911 : :
3912 [ # # ]: 0 : if (rt->nh) {
3913 : 0 : rc = ip6_del_cached_rt_nh(cfg, rt);
3914 [ # # ]: 0 : } else if (cfg->fc_nh_id) {
3915 : 0 : continue;
3916 : : } else {
3917 : 0 : nh = rt->fib6_nh;
3918 : 0 : rc = ip6_del_cached_rt(cfg, rt, nh);
3919 : : }
3920 [ # # ]: 0 : if (rc != -ESRCH) {
3921 : 0 : rcu_read_unlock();
3922 : 0 : return rc;
3923 : : }
3924 : 0 : continue;
3925 : : }
3926 : :
3927 [ # # # # ]: 0 : if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
3928 : 0 : continue;
3929 [ # # ]: 0 : if (cfg->fc_protocol &&
3930 [ # # ]: 0 : cfg->fc_protocol != rt->fib6_protocol)
3931 : 0 : continue;
3932 : :
3933 [ # # ]: 0 : if (rt->nh) {
3934 [ # # ]: 0 : if (!fib6_info_hold_safe(rt))
3935 : 0 : continue;
3936 : 0 : rcu_read_unlock();
3937 : :
3938 : 0 : return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3939 : : }
3940 [ # # ]: 0 : if (cfg->fc_nh_id)
3941 : 0 : continue;
3942 : :
3943 : 0 : nh = rt->fib6_nh;
3944 [ # # ]: 0 : if (cfg->fc_ifindex &&
3945 [ # # ]: 0 : (!nh->fib_nh_dev ||
3946 [ # # ]: 0 : nh->fib_nh_dev->ifindex != cfg->fc_ifindex))
3947 : 0 : continue;
3948 [ # # # # ]: 0 : if (cfg->fc_flags & RTF_GATEWAY &&
3949 : : !ipv6_addr_equal(&cfg->fc_gateway, &nh->fib_nh_gw6))
3950 : 0 : continue;
3951 [ # # ]: 0 : if (!fib6_info_hold_safe(rt))
3952 : 0 : continue;
3953 : 0 : rcu_read_unlock();
3954 : :
3955 : : /* if gateway was specified only delete the one hop */
3956 [ # # ]: 0 : if (cfg->fc_flags & RTF_GATEWAY)
3957 : 0 : return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3958 : :
3959 : 0 : return __ip6_del_rt_siblings(rt, cfg);
3960 : : }
3961 : : }
3962 : 0 : rcu_read_unlock();
3963 : :
3964 : 0 : return err;
3965 : : }
3966 : :
3967 : 0 : static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
3968 : : {
3969 : 0 : struct netevent_redirect netevent;
3970 : 0 : struct rt6_info *rt, *nrt = NULL;
3971 : 0 : struct fib6_result res = {};
3972 : 0 : struct ndisc_options ndopts;
3973 : 0 : struct inet6_dev *in6_dev;
3974 : 0 : struct neighbour *neigh;
3975 : 0 : struct rd_msg *msg;
3976 : 0 : int optlen, on_link;
3977 : 0 : u8 *lladdr;
3978 : :
3979 [ # # ]: 0 : optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
3980 : 0 : optlen -= sizeof(*msg);
3981 : :
3982 [ # # ]: 0 : if (optlen < 0) {
3983 : : net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
3984 : 0 : return;
3985 : : }
3986 : :
3987 [ # # ]: 0 : msg = (struct rd_msg *)icmp6_hdr(skb);
3988 : :
3989 [ # # ]: 0 : if (ipv6_addr_is_multicast(&msg->dest)) {
3990 : : net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
3991 : : return;
3992 : : }
3993 : :
3994 : 0 : on_link = 0;
3995 [ # # ]: 0 : if (ipv6_addr_equal(&msg->dest, &msg->target)) {
3996 : : on_link = 1;
3997 [ # # ]: 0 : } else if (ipv6_addr_type(&msg->target) !=
3998 : : (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
3999 : : net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
4000 : : return;
4001 : : }
4002 : :
4003 [ # # ]: 0 : in6_dev = __in6_dev_get(skb->dev);
4004 [ # # ]: 0 : if (!in6_dev)
4005 : : return;
4006 [ # # # # ]: 0 : if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
4007 : : return;
4008 : :
4009 : : /* RFC2461 8.1:
4010 : : * The IP source address of the Redirect MUST be the same as the current
4011 : : * first-hop router for the specified ICMP Destination Address.
4012 : : */
4013 : :
4014 [ # # ]: 0 : if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
4015 : : net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
4016 : : return;
4017 : : }
4018 : :
4019 : 0 : lladdr = NULL;
4020 [ # # ]: 0 : if (ndopts.nd_opts_tgt_lladdr) {
4021 [ # # ]: 0 : lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
4022 : : skb->dev);
4023 [ # # ]: 0 : if (!lladdr) {
4024 : : net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
4025 : : return;
4026 : : }
4027 : : }
4028 : :
4029 : 0 : rt = (struct rt6_info *) dst;
4030 [ # # ]: 0 : if (rt->rt6i_flags & RTF_REJECT) {
4031 : : net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
4032 : : return;
4033 : : }
4034 : :
4035 : : /* Redirect received -> path was valid.
4036 : : * Look, redirects are sent only in response to data packets,
4037 : : * so that this nexthop apparently is reachable. --ANK
4038 : : */
4039 [ # # ]: 0 : dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
4040 : :
4041 : 0 : neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
4042 [ # # ]: 0 : if (!neigh)
4043 : : return;
4044 : :
4045 : : /*
4046 : : * We have finally decided to accept it.
4047 : : */
4048 : :
4049 [ # # ]: 0 : ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
4050 : : NEIGH_UPDATE_F_WEAK_OVERRIDE|
4051 : : NEIGH_UPDATE_F_OVERRIDE|
4052 : : (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
4053 : : NEIGH_UPDATE_F_ISROUTER)),
4054 : : NDISC_REDIRECT, &ndopts);
4055 : :
4056 : 0 : rcu_read_lock();
4057 [ # # ]: 0 : res.f6i = rcu_dereference(rt->from);
4058 [ # # ]: 0 : if (!res.f6i)
4059 : 0 : goto out;
4060 : :
4061 [ # # ]: 0 : if (res.f6i->nh) {
4062 : 0 : struct fib6_nh_match_arg arg = {
4063 : 0 : .dev = dst->dev,
4064 : 0 : .gw = &rt->rt6i_gateway,
4065 : : };
4066 : :
4067 : 0 : nexthop_for_each_fib6_nh(res.f6i->nh,
4068 : : fib6_nh_find_match, &arg);
4069 : :
4070 : : /* fib6_info uses a nexthop that does not have fib6_nh
4071 : : * using the dst->dev. Should be impossible
4072 : : */
4073 [ # # ]: 0 : if (!arg.match)
4074 : 0 : goto out;
4075 : 0 : res.nh = arg.match;
4076 : : } else {
4077 : 0 : res.nh = res.f6i->fib6_nh;
4078 : : }
4079 : :
4080 : 0 : res.fib6_flags = res.f6i->fib6_flags;
4081 : 0 : res.fib6_type = res.f6i->fib6_type;
4082 : 0 : nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL);
4083 [ # # ]: 0 : if (!nrt)
4084 : 0 : goto out;
4085 : :
4086 : 0 : nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
4087 [ # # ]: 0 : if (on_link)
4088 : 0 : nrt->rt6i_flags &= ~RTF_GATEWAY;
4089 : :
4090 : 0 : nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
4091 : :
4092 : : /* rt6_insert_exception() will take care of duplicated exceptions */
4093 [ # # ]: 0 : if (rt6_insert_exception(nrt, &res)) {
4094 : 0 : dst_release_immediate(&nrt->dst);
4095 : 0 : goto out;
4096 : : }
4097 : :
4098 : 0 : netevent.old = &rt->dst;
4099 : 0 : netevent.new = &nrt->dst;
4100 : 0 : netevent.daddr = &msg->dest;
4101 : 0 : netevent.neigh = neigh;
4102 : 0 : call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
4103 : :
4104 : 0 : out:
4105 : 0 : rcu_read_unlock();
4106 : 0 : neigh_release(neigh);
4107 : : }
4108 : :
4109 : : #ifdef CONFIG_IPV6_ROUTE_INFO
4110 : : static struct fib6_info *rt6_get_route_info(struct net *net,
4111 : : const struct in6_addr *prefix, int prefixlen,
4112 : : const struct in6_addr *gwaddr,
4113 : : struct net_device *dev)
4114 : : {
4115 : : u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
4116 : : int ifindex = dev->ifindex;
4117 : : struct fib6_node *fn;
4118 : : struct fib6_info *rt = NULL;
4119 : : struct fib6_table *table;
4120 : :
4121 : : table = fib6_get_table(net, tb_id);
4122 : : if (!table)
4123 : : return NULL;
4124 : :
4125 : : rcu_read_lock();
4126 : : fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
4127 : : if (!fn)
4128 : : goto out;
4129 : :
4130 : : for_each_fib6_node_rt_rcu(fn) {
4131 : : /* these routes do not use nexthops */
4132 : : if (rt->nh)
4133 : : continue;
4134 : : if (rt->fib6_nh->fib_nh_dev->ifindex != ifindex)
4135 : : continue;
4136 : : if (!(rt->fib6_flags & RTF_ROUTEINFO) ||
4137 : : !rt->fib6_nh->fib_nh_gw_family)
4138 : : continue;
4139 : : if (!ipv6_addr_equal(&rt->fib6_nh->fib_nh_gw6, gwaddr))
4140 : : continue;
4141 : : if (!fib6_info_hold_safe(rt))
4142 : : continue;
4143 : : break;
4144 : : }
4145 : : out:
4146 : : rcu_read_unlock();
4147 : : return rt;
4148 : : }
4149 : :
4150 : : static struct fib6_info *rt6_add_route_info(struct net *net,
4151 : : const struct in6_addr *prefix, int prefixlen,
4152 : : const struct in6_addr *gwaddr,
4153 : : struct net_device *dev,
4154 : : unsigned int pref)
4155 : : {
4156 : : struct fib6_config cfg = {
4157 : : .fc_metric = IP6_RT_PRIO_USER,
4158 : : .fc_ifindex = dev->ifindex,
4159 : : .fc_dst_len = prefixlen,
4160 : : .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
4161 : : RTF_UP | RTF_PREF(pref),
4162 : : .fc_protocol = RTPROT_RA,
4163 : : .fc_type = RTN_UNICAST,
4164 : : .fc_nlinfo.portid = 0,
4165 : : .fc_nlinfo.nlh = NULL,
4166 : : .fc_nlinfo.nl_net = net,
4167 : : };
4168 : :
4169 : : cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
4170 : : cfg.fc_dst = *prefix;
4171 : : cfg.fc_gateway = *gwaddr;
4172 : :
4173 : : /* We should treat it as a default route if prefix length is 0. */
4174 : : if (!prefixlen)
4175 : : cfg.fc_flags |= RTF_DEFAULT;
4176 : :
4177 : : ip6_route_add(&cfg, GFP_ATOMIC, NULL);
4178 : :
4179 : : return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
4180 : : }
4181 : : #endif
4182 : :
4183 : 0 : struct fib6_info *rt6_get_dflt_router(struct net *net,
4184 : : const struct in6_addr *addr,
4185 : : struct net_device *dev)
4186 : : {
4187 : 0 : u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
4188 : 0 : struct fib6_info *rt;
4189 : 0 : struct fib6_table *table;
4190 : :
4191 : 0 : table = fib6_get_table(net, tb_id);
4192 [ # # ]: 0 : if (!table)
4193 : : return NULL;
4194 : :
4195 : 0 : rcu_read_lock();
4196 [ # # ]: 0 : for_each_fib6_node_rt_rcu(&table->tb6_root) {
4197 : 0 : struct fib6_nh *nh;
4198 : :
4199 : : /* RA routes do not use nexthops */
4200 [ # # ]: 0 : if (rt->nh)
4201 : 0 : continue;
4202 : :
4203 : 0 : nh = rt->fib6_nh;
4204 [ # # ]: 0 : if (dev == nh->fib_nh_dev &&
4205 [ # # # # ]: 0 : ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
4206 : : ipv6_addr_equal(&nh->fib_nh_gw6, addr))
4207 : : break;
4208 : : }
4209 [ # # # # ]: 0 : if (rt && !fib6_info_hold_safe(rt))
4210 : 0 : rt = NULL;
4211 : 0 : rcu_read_unlock();
4212 : 0 : return rt;
4213 : : }
4214 : :
4215 : 0 : struct fib6_info *rt6_add_dflt_router(struct net *net,
4216 : : const struct in6_addr *gwaddr,
4217 : : struct net_device *dev,
4218 : : unsigned int pref)
4219 : : {
4220 : 0 : struct fib6_config cfg = {
4221 : : .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
4222 : : .fc_metric = IP6_RT_PRIO_USER,
4223 : 0 : .fc_ifindex = dev->ifindex,
4224 : : .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
4225 : 0 : RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
4226 : : .fc_protocol = RTPROT_RA,
4227 : : .fc_type = RTN_UNICAST,
4228 : : .fc_nlinfo.portid = 0,
4229 : : .fc_nlinfo.nlh = NULL,
4230 : : .fc_nlinfo.nl_net = net,
4231 : : };
4232 : :
4233 : 0 : cfg.fc_gateway = *gwaddr;
4234 : :
4235 [ # # ]: 0 : if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
4236 : 0 : struct fib6_table *table;
4237 : :
4238 : 0 : table = fib6_get_table(dev_net(dev), cfg.fc_table);
4239 [ # # ]: 0 : if (table)
4240 : 0 : table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
4241 : : }
4242 : :
4243 : 0 : return rt6_get_dflt_router(net, gwaddr, dev);
4244 : : }
4245 : :
4246 : 0 : static void __rt6_purge_dflt_routers(struct net *net,
4247 : : struct fib6_table *table)
4248 : : {
4249 : 0 : struct fib6_info *rt;
4250 : :
4251 : 0 : restart:
4252 : 0 : rcu_read_lock();
4253 [ # # ]: 0 : for_each_fib6_node_rt_rcu(&table->tb6_root) {
4254 : 0 : struct net_device *dev = fib6_info_nh_dev(rt);
4255 [ # # ]: 0 : struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
4256 : :
4257 [ # # # # ]: 0 : if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
4258 [ # # # # ]: 0 : (!idev || idev->cnf.accept_ra != 2) &&
4259 : : fib6_info_hold_safe(rt)) {
4260 : 0 : rcu_read_unlock();
4261 : 0 : ip6_del_rt(net, rt);
4262 : 0 : goto restart;
4263 : : }
4264 : : }
4265 : 0 : rcu_read_unlock();
4266 : :
4267 : 0 : table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
4268 : 0 : }
4269 : :
4270 : 0 : void rt6_purge_dflt_routers(struct net *net)
4271 : : {
4272 : 0 : struct fib6_table *table;
4273 : 0 : struct hlist_head *head;
4274 : 0 : unsigned int h;
4275 : :
4276 : 0 : rcu_read_lock();
4277 : :
4278 [ # # ]: 0 : for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
4279 : 0 : head = &net->ipv6.fib_table_hash[h];
4280 [ # # # # : 0 : hlist_for_each_entry_rcu(table, head, tb6_hlist) {
# # ]
4281 [ # # ]: 0 : if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
4282 : 0 : __rt6_purge_dflt_routers(net, table);
4283 : : }
4284 : : }
4285 : :
4286 : 0 : rcu_read_unlock();
4287 : 0 : }
4288 : :
4289 : 0 : static void rtmsg_to_fib6_config(struct net *net,
4290 : : struct in6_rtmsg *rtmsg,
4291 : : struct fib6_config *cfg)
4292 : : {
4293 : 0 : *cfg = (struct fib6_config){
4294 [ # # ]: 0 : .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
4295 : : : RT6_TABLE_MAIN,
4296 : : .fc_ifindex = rtmsg->rtmsg_ifindex,
4297 [ # # ]: 0 : .fc_metric = rtmsg->rtmsg_metric ? : IP6_RT_PRIO_USER,
4298 : 0 : .fc_expires = rtmsg->rtmsg_info,
4299 : 0 : .fc_dst_len = rtmsg->rtmsg_dst_len,
4300 : 0 : .fc_src_len = rtmsg->rtmsg_src_len,
4301 : 0 : .fc_flags = rtmsg->rtmsg_flags,
4302 : 0 : .fc_type = rtmsg->rtmsg_type,
4303 : :
4304 : : .fc_nlinfo.nl_net = net,
4305 : :
4306 : 0 : .fc_dst = rtmsg->rtmsg_dst,
4307 : 0 : .fc_src = rtmsg->rtmsg_src,
4308 : 0 : .fc_gateway = rtmsg->rtmsg_gateway,
4309 : : };
4310 : 0 : }
4311 : :
4312 : 0 : int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
4313 : : {
4314 : 0 : struct fib6_config cfg;
4315 : 0 : struct in6_rtmsg rtmsg;
4316 : 0 : int err;
4317 : :
4318 [ # # ]: 0 : switch (cmd) {
4319 : 0 : case SIOCADDRT: /* Add a route */
4320 : : case SIOCDELRT: /* Delete a route */
4321 [ # # ]: 0 : if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
4322 : : return -EPERM;
4323 : 0 : err = copy_from_user(&rtmsg, arg,
4324 : : sizeof(struct in6_rtmsg));
4325 [ # # ]: 0 : if (err)
4326 : : return -EFAULT;
4327 : :
4328 : 0 : rtmsg_to_fib6_config(net, &rtmsg, &cfg);
4329 : :
4330 : 0 : rtnl_lock();
4331 [ # # ]: 0 : switch (cmd) {
4332 : 0 : case SIOCADDRT:
4333 : 0 : err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
4334 : 0 : break;
4335 : 0 : case SIOCDELRT:
4336 : 0 : err = ip6_route_del(&cfg, NULL);
4337 : 0 : break;
4338 : : default:
4339 : : err = -EINVAL;
4340 : : }
4341 : 0 : rtnl_unlock();
4342 : :
4343 : 0 : return err;
4344 : : }
4345 : :
4346 : : return -EINVAL;
4347 : : }
4348 : :
4349 : : /*
4350 : : * Drop the packet on the floor
4351 : : */
4352 : :
4353 : 0 : static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
4354 : : {
4355 [ # # ]: 0 : struct dst_entry *dst = skb_dst(skb);
4356 [ # # ]: 0 : struct net *net = dev_net(dst->dev);
4357 : 0 : struct inet6_dev *idev;
4358 : 0 : int type;
4359 : :
4360 [ # # ]: 0 : if (netif_is_l3_master(skb->dev) &&
4361 [ # # ]: 0 : dst->dev == net->loopback_dev)
4362 : 0 : idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
4363 : : else
4364 : 0 : idev = ip6_dst_idev(dst);
4365 : :
4366 [ # # # ]: 0 : switch (ipstats_mib_noroutes) {
4367 : : case IPSTATS_MIB_INNOROUTES:
4368 : 0 : type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
4369 [ # # ]: 0 : if (type == IPV6_ADDR_ANY) {
4370 [ # # ]: 0 : IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
4371 : : break;
4372 : : }
4373 : : /* FALLTHROUGH */
4374 : : case IPSTATS_MIB_OUTNOROUTES:
4375 [ # # ]: 0 : IP6_INC_STATS(net, idev, ipstats_mib_noroutes);
4376 : : break;
4377 : : }
4378 : :
4379 : : /* Start over by dropping the dst for l3mdev case */
4380 [ # # ]: 0 : if (netif_is_l3_master(skb->dev))
4381 [ # # ]: 0 : skb_dst_drop(skb);
4382 : :
4383 : 0 : icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
4384 : 0 : kfree_skb(skb);
4385 : 0 : return 0;
4386 : : }
4387 : :
4388 : 0 : static int ip6_pkt_discard(struct sk_buff *skb)
4389 : : {
4390 : 0 : return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
4391 : : }
4392 : :
4393 : 0 : static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
4394 : : {
4395 : 0 : skb->dev = skb_dst(skb)->dev;
4396 : 0 : return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
4397 : : }
4398 : :
4399 : 0 : static int ip6_pkt_prohibit(struct sk_buff *skb)
4400 : : {
4401 : 0 : return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
4402 : : }
4403 : :
4404 : 0 : static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
4405 : : {
4406 : 0 : skb->dev = skb_dst(skb)->dev;
4407 : 0 : return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
4408 : : }
4409 : :
4410 : : /*
4411 : : * Allocate a dst for local (unicast / anycast) address.
4412 : : */
4413 : :
4414 : 184 : struct fib6_info *addrconf_f6i_alloc(struct net *net,
4415 : : struct inet6_dev *idev,
4416 : : const struct in6_addr *addr,
4417 : : bool anycast, gfp_t gfp_flags)
4418 : : {
4419 : 184 : struct fib6_config cfg = {
4420 [ - + ]: 184 : .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL,
4421 : 184 : .fc_ifindex = idev->dev->ifindex,
4422 : : .fc_flags = RTF_UP | RTF_NONEXTHOP,
4423 : : .fc_dst = *addr,
4424 : : .fc_dst_len = 128,
4425 : : .fc_protocol = RTPROT_KERNEL,
4426 : : .fc_nlinfo.nl_net = net,
4427 : : .fc_ignore_dev_down = true,
4428 : : };
4429 : 184 : struct fib6_info *f6i;
4430 : :
4431 [ - + ]: 184 : if (anycast) {
4432 : 0 : cfg.fc_type = RTN_ANYCAST;
4433 : 0 : cfg.fc_flags |= RTF_ANYCAST;
4434 : : } else {
4435 : 184 : cfg.fc_type = RTN_LOCAL;
4436 : 184 : cfg.fc_flags |= RTF_LOCAL;
4437 : : }
4438 : :
4439 : 184 : f6i = ip6_route_info_create(&cfg, gfp_flags, NULL);
4440 [ + - ]: 184 : if (!IS_ERR(f6i))
4441 : 184 : f6i->dst_nocount = true;
4442 : 184 : return f6i;
4443 : : }
4444 : :
4445 : : /* remove deleted ip from prefsrc entries */
4446 : : struct arg_dev_net_ip {
4447 : : struct net_device *dev;
4448 : : struct net *net;
4449 : : struct in6_addr *addr;
4450 : : };
4451 : :
4452 : 0 : static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
4453 : : {
4454 : 0 : struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
4455 : 0 : struct net *net = ((struct arg_dev_net_ip *)arg)->net;
4456 : 0 : struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
4457 : :
4458 [ # # ]: 0 : if (!rt->nh &&
4459 [ # # # # ]: 0 : ((void *)rt->fib6_nh->fib_nh_dev == dev || !dev) &&
4460 [ # # # # ]: 0 : rt != net->ipv6.fib6_null_entry &&
4461 : : ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
4462 : 0 : spin_lock_bh(&rt6_exception_lock);
4463 : : /* remove prefsrc entry */
4464 : 0 : rt->fib6_prefsrc.plen = 0;
4465 : 0 : spin_unlock_bh(&rt6_exception_lock);
4466 : : }
4467 : 0 : return 0;
4468 : : }
4469 : :
4470 : 0 : void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
4471 : : {
4472 : 0 : struct net *net = dev_net(ifp->idev->dev);
4473 : 0 : struct arg_dev_net_ip adni = {
4474 : : .dev = ifp->idev->dev,
4475 : : .net = net,
4476 : 0 : .addr = &ifp->addr,
4477 : : };
4478 : 0 : fib6_clean_all(net, fib6_remove_prefsrc, &adni);
4479 : 0 : }
4480 : :
4481 : : #define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT)
4482 : :
4483 : : /* Remove routers and update dst entries when gateway turn into host. */
4484 : 0 : static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
4485 : : {
4486 : 0 : struct in6_addr *gateway = (struct in6_addr *)arg;
4487 : 0 : struct fib6_nh *nh;
4488 : :
4489 : : /* RA routes do not use nexthops */
4490 [ # # ]: 0 : if (rt->nh)
4491 : : return 0;
4492 : :
4493 : 0 : nh = rt->fib6_nh;
4494 [ # # ]: 0 : if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
4495 [ # # # # ]: 0 : nh->fib_nh_gw_family && ipv6_addr_equal(gateway, &nh->fib_nh_gw6))
4496 : : return -1;
4497 : :
4498 : : /* Further clean up cached routes in exception table.
4499 : : * This is needed because cached route may have a different
4500 : : * gateway than its 'parent' in the case of an ip redirect.
4501 : : */
4502 : 0 : fib6_nh_exceptions_clean_tohost(nh, gateway);
4503 : :
4504 : 0 : return 0;
4505 : : }
4506 : :
4507 : 0 : void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
4508 : : {
4509 : 0 : fib6_clean_all(net, fib6_clean_tohost, gateway);
4510 : 0 : }
4511 : :
4512 : : struct arg_netdev_event {
4513 : : const struct net_device *dev;
4514 : : union {
4515 : : unsigned char nh_flags;
4516 : : unsigned long event;
4517 : : };
4518 : : };
4519 : :
4520 : : static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
4521 : : {
4522 : : struct fib6_info *iter;
4523 : : struct fib6_node *fn;
4524 : :
4525 : : fn = rcu_dereference_protected(rt->fib6_node,
4526 : : lockdep_is_held(&rt->fib6_table->tb6_lock));
4527 : : iter = rcu_dereference_protected(fn->leaf,
4528 : : lockdep_is_held(&rt->fib6_table->tb6_lock));
4529 : : while (iter) {
4530 : : if (iter->fib6_metric == rt->fib6_metric &&
4531 : : rt6_qualify_for_ecmp(iter))
4532 : : return iter;
4533 : : iter = rcu_dereference_protected(iter->fib6_next,
4534 : : lockdep_is_held(&rt->fib6_table->tb6_lock));
4535 : : }
4536 : :
4537 : : return NULL;
4538 : : }
4539 : :
4540 : : /* only called for fib entries with builtin fib6_nh */
4541 : 0 : static bool rt6_is_dead(const struct fib6_info *rt)
4542 : : {
4543 [ # # # # : 0 : if (rt->fib6_nh->fib_nh_flags & RTNH_F_DEAD ||
# # ]
4544 [ # # # # : 0 : (rt->fib6_nh->fib_nh_flags & RTNH_F_LINKDOWN &&
# # ]
4545 : : ip6_ignore_linkdown(rt->fib6_nh->fib_nh_dev)))
4546 : : return true;
4547 : :
4548 : : return false;
4549 : : }
4550 : :
4551 : 0 : static int rt6_multipath_total_weight(const struct fib6_info *rt)
4552 : : {
4553 : 0 : struct fib6_info *iter;
4554 : 0 : int total = 0;
4555 : :
4556 [ # # ]: 0 : if (!rt6_is_dead(rt))
4557 : 0 : total += rt->fib6_nh->fib_nh_weight;
4558 : :
4559 [ # # ]: 0 : list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
4560 [ # # ]: 0 : if (!rt6_is_dead(iter))
4561 : 0 : total += iter->fib6_nh->fib_nh_weight;
4562 : : }
4563 : :
4564 : 0 : return total;
4565 : : }
4566 : :
4567 : 0 : static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
4568 : : {
4569 : 0 : int upper_bound = -1;
4570 : :
4571 [ # # ]: 0 : if (!rt6_is_dead(rt)) {
4572 : 0 : *weight += rt->fib6_nh->fib_nh_weight;
4573 : 0 : upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
4574 : 0 : total) - 1;
4575 : : }
4576 : 0 : atomic_set(&rt->fib6_nh->fib_nh_upper_bound, upper_bound);
4577 : 0 : }
4578 : :
4579 : 0 : static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
4580 : : {
4581 : 0 : struct fib6_info *iter;
4582 : 0 : int weight = 0;
4583 : :
4584 : 0 : rt6_upper_bound_set(rt, &weight, total);
4585 : :
4586 [ # # ]: 0 : list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
4587 : 0 : rt6_upper_bound_set(iter, &weight, total);
4588 : 0 : }
4589 : :
4590 : 212 : void rt6_multipath_rebalance(struct fib6_info *rt)
4591 : : {
4592 : 212 : struct fib6_info *first;
4593 : 212 : int total;
4594 : :
4595 : : /* In case the entire multipath route was marked for flushing,
4596 : : * then there is no need to rebalance upon the removal of every
4597 : : * sibling route.
4598 : : */
4599 [ - + - - ]: 212 : if (!rt->fib6_nsiblings || rt->should_flush)
4600 : : return;
4601 : :
4602 : : /* During lookup routes are evaluated in order, so we need to
4603 : : * make sure upper bounds are assigned from the first sibling
4604 : : * onwards.
4605 : : */
4606 : 0 : first = rt6_multipath_first_sibling(rt);
4607 [ # # # # ]: 0 : if (WARN_ON_ONCE(!first))
4608 : : return;
4609 : :
4610 : 0 : total = rt6_multipath_total_weight(first);
4611 : 0 : rt6_multipath_upper_bound_set(first, total);
4612 : : }
4613 : :
4614 : 374 : static int fib6_ifup(struct fib6_info *rt, void *p_arg)
4615 : : {
4616 : 374 : const struct arg_netdev_event *arg = p_arg;
4617 [ + + ]: 374 : struct net *net = dev_net(arg->dev);
4618 : :
4619 [ + + + - ]: 374 : if (rt != net->ipv6.fib6_null_entry && !rt->nh &&
4620 [ + + ]: 268 : rt->fib6_nh->fib_nh_dev == arg->dev) {
4621 : 212 : rt->fib6_nh->fib_nh_flags &= ~arg->nh_flags;
4622 : 212 : fib6_update_sernum_upto_root(net, rt);
4623 : 212 : rt6_multipath_rebalance(rt);
4624 : : }
4625 : :
4626 : 374 : return 0;
4627 : : }
4628 : :
4629 : 106 : void rt6_sync_up(struct net_device *dev, unsigned char nh_flags)
4630 : : {
4631 : 106 : struct arg_netdev_event arg = {
4632 : : .dev = dev,
4633 : : {
4634 : : .nh_flags = nh_flags,
4635 : : },
4636 : : };
4637 : :
4638 [ + - + - ]: 212 : if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
4639 : 106 : arg.nh_flags |= RTNH_F_LINKDOWN;
4640 : :
4641 : 106 : fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
4642 : 106 : }
4643 : :
4644 : : /* only called for fib entries with inline fib6_nh */
4645 : 0 : static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
4646 : : const struct net_device *dev)
4647 : : {
4648 : 0 : struct fib6_info *iter;
4649 : :
4650 : 0 : if (rt->fib6_nh->fib_nh_dev == dev)
4651 : : return true;
4652 [ # # ]: 0 : list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
4653 [ # # ]: 0 : if (iter->fib6_nh->fib_nh_dev == dev)
4654 : : return true;
4655 : :
4656 : : return false;
4657 : : }
4658 : :
4659 : 0 : static void rt6_multipath_flush(struct fib6_info *rt)
4660 : : {
4661 : 0 : struct fib6_info *iter;
4662 : :
4663 : 0 : rt->should_flush = 1;
4664 [ # # ]: 0 : list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
4665 : 0 : iter->should_flush = 1;
4666 : : }
4667 : :
4668 : 0 : static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
4669 : : const struct net_device *down_dev)
4670 : : {
4671 : 0 : struct fib6_info *iter;
4672 : 0 : unsigned int dead = 0;
4673 : :
4674 [ # # ]: 0 : if (rt->fib6_nh->fib_nh_dev == down_dev ||
4675 [ # # ]: 0 : rt->fib6_nh->fib_nh_flags & RTNH_F_DEAD)
4676 : 0 : dead++;
4677 [ # # ]: 0 : list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
4678 [ # # ]: 0 : if (iter->fib6_nh->fib_nh_dev == down_dev ||
4679 [ # # ]: 0 : iter->fib6_nh->fib_nh_flags & RTNH_F_DEAD)
4680 : 0 : dead++;
4681 : :
4682 : 0 : return dead;
4683 : : }
4684 : :
4685 : 0 : static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
4686 : : const struct net_device *dev,
4687 : : unsigned char nh_flags)
4688 : : {
4689 : 0 : struct fib6_info *iter;
4690 : :
4691 : 0 : if (rt->fib6_nh->fib_nh_dev == dev)
4692 : 0 : rt->fib6_nh->fib_nh_flags |= nh_flags;
4693 [ # # ]: 0 : list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
4694 [ # # ]: 0 : if (iter->fib6_nh->fib_nh_dev == dev)
4695 : 0 : iter->fib6_nh->fib_nh_flags |= nh_flags;
4696 : : }
4697 : :
4698 : : /* called with write lock held for table with rt */
4699 : 0 : static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
4700 : : {
4701 : 0 : const struct arg_netdev_event *arg = p_arg;
4702 : 0 : const struct net_device *dev = arg->dev;
4703 [ # # ]: 0 : struct net *net = dev_net(dev);
4704 : :
4705 [ # # # # ]: 0 : if (rt == net->ipv6.fib6_null_entry || rt->nh)
4706 : : return 0;
4707 : :
4708 [ # # # # ]: 0 : switch (arg->event) {
4709 : 0 : case NETDEV_UNREGISTER:
4710 [ # # ]: 0 : return rt->fib6_nh->fib_nh_dev == dev ? -1 : 0;
4711 : 0 : case NETDEV_DOWN:
4712 [ # # ]: 0 : if (rt->should_flush)
4713 : : return -1;
4714 [ # # ]: 0 : if (!rt->fib6_nsiblings)
4715 [ # # ]: 0 : return rt->fib6_nh->fib_nh_dev == dev ? -1 : 0;
4716 [ # # # # ]: 0 : if (rt6_multipath_uses_dev(rt, dev)) {
4717 : 0 : unsigned int count;
4718 : :
4719 : 0 : count = rt6_multipath_dead_count(rt, dev);
4720 [ # # ]: 0 : if (rt->fib6_nsiblings + 1 == count) {
4721 : 0 : rt6_multipath_flush(rt);
4722 : : return -1;
4723 : : }
4724 [ # # ]: 0 : rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4725 : : RTNH_F_LINKDOWN);
4726 : 0 : fib6_update_sernum(net, rt);
4727 : 0 : rt6_multipath_rebalance(rt);
4728 : : }
4729 : : return -2;
4730 : 0 : case NETDEV_CHANGE:
4731 [ # # ]: 0 : if (rt->fib6_nh->fib_nh_dev != dev ||
4732 [ # # ]: 0 : rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
4733 : : break;
4734 : 0 : rt->fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN;
4735 : 0 : rt6_multipath_rebalance(rt);
4736 : 0 : break;
4737 : : }
4738 : :
4739 : 0 : return 0;
4740 : : }
4741 : :
4742 : 0 : void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
4743 : : {
4744 : 0 : struct arg_netdev_event arg = {
4745 : : .dev = dev,
4746 : : {
4747 : : .event = event,
4748 : : },
4749 : : };
4750 [ # # ]: 0 : struct net *net = dev_net(dev);
4751 : :
4752 [ # # ]: 0 : if (net->ipv6.sysctl.skip_notify_on_dev_down)
4753 : 0 : fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
4754 : : else
4755 : 0 : fib6_clean_all(net, fib6_ifdown, &arg);
4756 : 0 : }
4757 : :
4758 : 0 : void rt6_disable_ip(struct net_device *dev, unsigned long event)
4759 : : {
4760 : 0 : rt6_sync_down_dev(dev, event);
4761 : 0 : rt6_uncached_list_flush_dev(dev_net(dev), dev);
4762 : 0 : neigh_ifdown(&nd_tbl, dev);
4763 : 0 : }
4764 : :
4765 : : struct rt6_mtu_change_arg {
4766 : : struct net_device *dev;
4767 : : unsigned int mtu;
4768 : : struct fib6_info *f6i;
4769 : : };
4770 : :
4771 : 0 : static int fib6_nh_mtu_change(struct fib6_nh *nh, void *_arg)
4772 : : {
4773 : 0 : struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *)_arg;
4774 : 0 : struct fib6_info *f6i = arg->f6i;
4775 : :
4776 : : /* For administrative MTU increase, there is no way to discover
4777 : : * IPv6 PMTU increase, so PMTU increase should be updated here.
4778 : : * Since RFC 1981 doesn't include administrative MTU increase
4779 : : * update PMTU increase is a MUST. (i.e. jumbo frame)
4780 : : */
4781 [ # # ]: 0 : if (nh->fib_nh_dev == arg->dev) {
4782 [ # # ]: 0 : struct inet6_dev *idev = __in6_dev_get(arg->dev);
4783 : 0 : u32 mtu = f6i->fib6_pmtu;
4784 : :
4785 [ # # ]: 0 : if (mtu >= arg->mtu ||
4786 [ # # ]: 0 : (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4787 : 0 : fib6_metric_set(f6i, RTAX_MTU, arg->mtu);
4788 : :
4789 : 0 : spin_lock_bh(&rt6_exception_lock);
4790 : 0 : rt6_exceptions_update_pmtu(idev, nh, arg->mtu);
4791 : 0 : spin_unlock_bh(&rt6_exception_lock);
4792 : : }
4793 : :
4794 : 0 : return 0;
4795 : : }
4796 : :
4797 : 0 : static int rt6_mtu_change_route(struct fib6_info *f6i, void *p_arg)
4798 : : {
4799 : 0 : struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4800 : 0 : struct inet6_dev *idev;
4801 : :
4802 : : /* In IPv6 pmtu discovery is not optional,
4803 : : so that RTAX_MTU lock cannot disable it.
4804 : : We still use this lock to block changes
4805 : : caused by addrconf/ndisc.
4806 : : */
4807 : :
4808 [ # # ]: 0 : idev = __in6_dev_get(arg->dev);
4809 [ # # ]: 0 : if (!idev)
4810 : : return 0;
4811 : :
4812 [ # # ]: 0 : if (fib6_metric_locked(f6i, RTAX_MTU))
4813 : : return 0;
4814 : :
4815 : 0 : arg->f6i = f6i;
4816 [ # # ]: 0 : if (f6i->nh) {
4817 : : /* fib6_nh_mtu_change only returns 0, so this is safe */
4818 : 0 : return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_mtu_change,
4819 : : arg);
4820 : : }
4821 : :
4822 : 0 : return fib6_nh_mtu_change(f6i->fib6_nh, arg);
4823 : : }
4824 : :
4825 : 0 : void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
4826 : : {
4827 : 0 : struct rt6_mtu_change_arg arg = {
4828 : : .dev = dev,
4829 : : .mtu = mtu,
4830 : : };
4831 : :
4832 : 0 : fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
4833 : 0 : }
4834 : :
4835 : : static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
4836 : : [RTA_UNSPEC] = { .strict_start_type = RTA_DPORT + 1 },
4837 : : [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
4838 : : [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
4839 : : [RTA_OIF] = { .type = NLA_U32 },
4840 : : [RTA_IIF] = { .type = NLA_U32 },
4841 : : [RTA_PRIORITY] = { .type = NLA_U32 },
4842 : : [RTA_METRICS] = { .type = NLA_NESTED },
4843 : : [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
4844 : : [RTA_PREF] = { .type = NLA_U8 },
4845 : : [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4846 : : [RTA_ENCAP] = { .type = NLA_NESTED },
4847 : : [RTA_EXPIRES] = { .type = NLA_U32 },
4848 : : [RTA_UID] = { .type = NLA_U32 },
4849 : : [RTA_MARK] = { .type = NLA_U32 },
4850 : : [RTA_TABLE] = { .type = NLA_U32 },
4851 : : [RTA_IP_PROTO] = { .type = NLA_U8 },
4852 : : [RTA_SPORT] = { .type = NLA_U16 },
4853 : : [RTA_DPORT] = { .type = NLA_U16 },
4854 : : [RTA_NH_ID] = { .type = NLA_U32 },
4855 : : };
4856 : :
4857 : 0 : static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
4858 : : struct fib6_config *cfg,
4859 : : struct netlink_ext_ack *extack)
4860 : : {
4861 : 0 : struct rtmsg *rtm;
4862 : 0 : struct nlattr *tb[RTA_MAX+1];
4863 : 0 : unsigned int pref;
4864 : 0 : int err;
4865 : :
4866 : 0 : err = nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
4867 : : rtm_ipv6_policy, extack);
4868 [ # # ]: 0 : if (err < 0)
4869 : 0 : goto errout;
4870 : :
4871 : 0 : err = -EINVAL;
4872 [ # # ]: 0 : rtm = nlmsg_data(nlh);
4873 : :
4874 : 0 : *cfg = (struct fib6_config){
4875 : 0 : .fc_table = rtm->rtm_table,
4876 : 0 : .fc_dst_len = rtm->rtm_dst_len,
4877 : 0 : .fc_src_len = rtm->rtm_src_len,
4878 : : .fc_flags = RTF_UP,
4879 : 0 : .fc_protocol = rtm->rtm_protocol,
4880 : 0 : .fc_type = rtm->rtm_type,
4881 : :
4882 : 0 : .fc_nlinfo.portid = NETLINK_CB(skb).portid,
4883 : : .fc_nlinfo.nlh = nlh,
4884 [ # # ]: 0 : .fc_nlinfo.nl_net = sock_net(skb->sk),
4885 : : };
4886 : :
4887 : 0 : if (rtm->rtm_type == RTN_UNREACHABLE ||
4888 : : rtm->rtm_type == RTN_BLACKHOLE ||
4889 [ # # ]: 0 : rtm->rtm_type == RTN_PROHIBIT ||
4890 : : rtm->rtm_type == RTN_THROW)
4891 : 0 : cfg->fc_flags |= RTF_REJECT;
4892 : :
4893 [ # # ]: 0 : if (rtm->rtm_type == RTN_LOCAL)
4894 : 0 : cfg->fc_flags |= RTF_LOCAL;
4895 : :
4896 [ # # ]: 0 : if (rtm->rtm_flags & RTM_F_CLONED)
4897 : 0 : cfg->fc_flags |= RTF_CACHE;
4898 : :
4899 : 0 : cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4900 : :
4901 [ # # ]: 0 : if (tb[RTA_NH_ID]) {
4902 [ # # # # ]: 0 : if (tb[RTA_GATEWAY] || tb[RTA_OIF] ||
4903 [ # # # # ]: 0 : tb[RTA_MULTIPATH] || tb[RTA_ENCAP]) {
4904 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
4905 : : "Nexthop specification and nexthop id are mutually exclusive");
4906 : 0 : goto errout;
4907 : : }
4908 : 0 : cfg->fc_nh_id = nla_get_u32(tb[RTA_NH_ID]);
4909 : : }
4910 : :
4911 [ # # ]: 0 : if (tb[RTA_GATEWAY]) {
4912 : 0 : cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
4913 : 0 : cfg->fc_flags |= RTF_GATEWAY;
4914 : : }
4915 [ # # ]: 0 : if (tb[RTA_VIA]) {
4916 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "IPv6 does not support RTA_VIA attribute");
4917 : 0 : goto errout;
4918 : : }
4919 : :
4920 [ # # ]: 0 : if (tb[RTA_DST]) {
4921 : 0 : int plen = (rtm->rtm_dst_len + 7) >> 3;
4922 : :
4923 [ # # ]: 0 : if (nla_len(tb[RTA_DST]) < plen)
4924 : 0 : goto errout;
4925 : :
4926 : 0 : nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
4927 : : }
4928 : :
4929 [ # # ]: 0 : if (tb[RTA_SRC]) {
4930 : 0 : int plen = (rtm->rtm_src_len + 7) >> 3;
4931 : :
4932 [ # # ]: 0 : if (nla_len(tb[RTA_SRC]) < plen)
4933 : 0 : goto errout;
4934 : :
4935 : 0 : nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
4936 : : }
4937 : :
4938 [ # # ]: 0 : if (tb[RTA_PREFSRC])
4939 : 0 : cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
4940 : :
4941 [ # # ]: 0 : if (tb[RTA_OIF])
4942 : 0 : cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4943 : :
4944 [ # # ]: 0 : if (tb[RTA_PRIORITY])
4945 : 0 : cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4946 : :
4947 [ # # ]: 0 : if (tb[RTA_METRICS]) {
4948 : 0 : cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4949 : 0 : cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
4950 : : }
4951 : :
4952 [ # # ]: 0 : if (tb[RTA_TABLE])
4953 : 0 : cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4954 : :
4955 [ # # ]: 0 : if (tb[RTA_MULTIPATH]) {
4956 : 0 : cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4957 : 0 : cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
4958 : :
4959 : 0 : err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
4960 : : cfg->fc_mp_len, extack);
4961 : 0 : if (err < 0)
4962 : : goto errout;
4963 : : }
4964 : :
4965 [ # # ]: 0 : if (tb[RTA_PREF]) {
4966 [ # # ]: 0 : pref = nla_get_u8(tb[RTA_PREF]);
4967 : 0 : if (pref != ICMPV6_ROUTER_PREF_LOW &&
4968 [ # # ]: 0 : pref != ICMPV6_ROUTER_PREF_HIGH)
4969 : 0 : pref = ICMPV6_ROUTER_PREF_MEDIUM;
4970 : 0 : cfg->fc_flags |= RTF_PREF(pref);
4971 : : }
4972 : :
4973 [ # # ]: 0 : if (tb[RTA_ENCAP])
4974 : 0 : cfg->fc_encap = tb[RTA_ENCAP];
4975 : :
4976 [ # # ]: 0 : if (tb[RTA_ENCAP_TYPE]) {
4977 [ # # ]: 0 : cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4978 : :
4979 [ # # ]: 0 : err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
4980 : 0 : if (err < 0)
4981 : 0 : goto errout;
4982 : : }
4983 : :
4984 [ # # ]: 0 : if (tb[RTA_EXPIRES]) {
4985 [ # # ]: 0 : unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4986 : :
4987 [ # # ]: 0 : if (addrconf_finite_timeout(timeout)) {
4988 : 0 : cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4989 : 0 : cfg->fc_flags |= RTF_EXPIRES;
4990 : : }
4991 : : }
4992 : :
4993 : : err = 0;
4994 : 0 : errout:
4995 : 0 : return err;
4996 : : }
4997 : :
4998 : : struct rt6_nh {
4999 : : struct fib6_info *fib6_info;
5000 : : struct fib6_config r_cfg;
5001 : : struct list_head next;
5002 : : };
5003 : :
5004 : : static int ip6_route_info_append(struct net *net,
5005 : : struct list_head *rt6_nh_list,
5006 : : struct fib6_info *rt,
5007 : : struct fib6_config *r_cfg)
5008 : : {
5009 : : struct rt6_nh *nh;
5010 : : int err = -EEXIST;
5011 : :
5012 : : list_for_each_entry(nh, rt6_nh_list, next) {
5013 : : /* check if fib6_info already exists */
5014 : : if (rt6_duplicate_nexthop(nh->fib6_info, rt))
5015 : : return err;
5016 : : }
5017 : :
5018 : : nh = kzalloc(sizeof(*nh), GFP_KERNEL);
5019 : : if (!nh)
5020 : : return -ENOMEM;
5021 : : nh->fib6_info = rt;
5022 : : memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
5023 : : list_add_tail(&nh->next, rt6_nh_list);
5024 : :
5025 : : return 0;
5026 : : }
5027 : :
5028 : 0 : static void ip6_route_mpath_notify(struct fib6_info *rt,
5029 : : struct fib6_info *rt_last,
5030 : : struct nl_info *info,
5031 : : __u16 nlflags)
5032 : : {
5033 : : /* if this is an APPEND route, then rt points to the first route
5034 : : * inserted and rt_last points to last route inserted. Userspace
5035 : : * wants a consistent dump of the route which starts at the first
5036 : : * nexthop. Since sibling routes are always added at the end of
5037 : : * the list, find the first sibling of the last route appended
5038 : : */
5039 [ # # # # : 0 : if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
# # ]
5040 : 0 : rt = list_first_entry(&rt_last->fib6_siblings,
5041 : : struct fib6_info,
5042 : : fib6_siblings);
5043 : : }
5044 : :
5045 [ # # ]: 0 : if (rt)
5046 : 0 : inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
5047 : 0 : }
5048 : :
5049 : 0 : static bool ip6_route_mpath_should_notify(const struct fib6_info *rt)
5050 : : {
5051 [ # # ]: 0 : bool rt_can_ecmp = rt6_qualify_for_ecmp(rt);
5052 : 0 : bool should_notify = false;
5053 : 0 : struct fib6_info *leaf;
5054 : 0 : struct fib6_node *fn;
5055 : :
5056 : 0 : rcu_read_lock();
5057 [ # # ]: 0 : fn = rcu_dereference(rt->fib6_node);
5058 [ # # ]: 0 : if (!fn)
5059 : 0 : goto out;
5060 : :
5061 [ # # ]: 0 : leaf = rcu_dereference(fn->leaf);
5062 [ # # ]: 0 : if (!leaf)
5063 : 0 : goto out;
5064 : :
5065 [ # # # # ]: 0 : if (rt == leaf ||
5066 [ # # # # ]: 0 : (rt_can_ecmp && rt->fib6_metric == leaf->fib6_metric &&
5067 : : rt6_qualify_for_ecmp(leaf)))
5068 : : should_notify = true;
5069 : 0 : out:
5070 : 0 : rcu_read_unlock();
5071 : :
5072 : 0 : return should_notify;
5073 : : }
5074 : :
5075 : 0 : static int ip6_route_multipath_add(struct fib6_config *cfg,
5076 : : struct netlink_ext_ack *extack)
5077 : : {
5078 : 0 : struct fib6_info *rt_notif = NULL, *rt_last = NULL;
5079 : 0 : struct nl_info *info = &cfg->fc_nlinfo;
5080 : 0 : struct fib6_config r_cfg;
5081 : 0 : struct rtnexthop *rtnh;
5082 : 0 : struct fib6_info *rt;
5083 : 0 : struct rt6_nh *err_nh;
5084 : 0 : struct rt6_nh *nh, *nh_safe;
5085 : 0 : __u16 nlflags;
5086 : 0 : int remaining;
5087 : 0 : int attrlen;
5088 : 0 : int err = 1;
5089 : 0 : int nhn = 0;
5090 [ # # ]: 0 : int replace = (cfg->fc_nlinfo.nlh &&
5091 [ # # ]: 0 : (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
5092 : 0 : LIST_HEAD(rt6_nh_list);
5093 : :
5094 [ # # ]: 0 : nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
5095 [ # # # # ]: 0 : if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
5096 : 0 : nlflags |= NLM_F_APPEND;
5097 : :
5098 : 0 : remaining = cfg->fc_mp_len;
5099 : 0 : rtnh = (struct rtnexthop *)cfg->fc_mp;
5100 : :
5101 : : /* Parse a Multipath Entry and build a list (rt6_nh_list) of
5102 : : * fib6_info structs per nexthop
5103 : : */
5104 [ # # ]: 0 : while (rtnh_ok(rtnh, remaining)) {
5105 : 0 : memcpy(&r_cfg, cfg, sizeof(*cfg));
5106 [ # # ]: 0 : if (rtnh->rtnh_ifindex)
5107 : 0 : r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
5108 : :
5109 [ # # ]: 0 : attrlen = rtnh_attrlen(rtnh);
5110 [ # # ]: 0 : if (attrlen > 0) {
5111 : 0 : struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
5112 : :
5113 : 0 : nla = nla_find(attrs, attrlen, RTA_GATEWAY);
5114 [ # # ]: 0 : if (nla) {
5115 : 0 : r_cfg.fc_gateway = nla_get_in6_addr(nla);
5116 : 0 : r_cfg.fc_flags |= RTF_GATEWAY;
5117 : : }
5118 : 0 : r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
5119 : 0 : nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
5120 [ # # ]: 0 : if (nla)
5121 : 0 : r_cfg.fc_encap_type = nla_get_u16(nla);
5122 : : }
5123 : :
5124 : 0 : r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
5125 : 0 : rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
5126 [ # # ]: 0 : if (IS_ERR(rt)) {
5127 : 0 : err = PTR_ERR(rt);
5128 : 0 : rt = NULL;
5129 : 0 : goto cleanup;
5130 : : }
5131 [ # # # # ]: 0 : if (!rt6_qualify_for_ecmp(rt)) {
5132 : 0 : err = -EINVAL;
5133 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
5134 : : "Device only routes can not be added for IPv6 using the multipath API.");
5135 : 0 : fib6_info_release(rt);
5136 : 0 : goto cleanup;
5137 : : }
5138 : :
5139 : 0 : rt->fib6_nh->fib_nh_weight = rtnh->rtnh_hops + 1;
5140 : :
5141 : 0 : err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
5142 : : rt, &r_cfg);
5143 [ # # ]: 0 : if (err) {
5144 : 0 : fib6_info_release(rt);
5145 : 0 : goto cleanup;
5146 : : }
5147 : :
5148 : 0 : rtnh = rtnh_next(rtnh, &remaining);
5149 : : }
5150 : :
5151 [ # # ]: 0 : if (list_empty(&rt6_nh_list)) {
5152 [ # # ]: 0 : NL_SET_ERR_MSG(extack,
5153 : : "Invalid nexthop configuration - no valid nexthops");
5154 : 0 : return -EINVAL;
5155 : : }
5156 : :
5157 : : /* for add and replace send one notification with all nexthops.
5158 : : * Skip the notification in fib6_add_rt2node and send one with
5159 : : * the full route when done
5160 : : */
5161 : 0 : info->skip_notify = 1;
5162 : :
5163 : : /* For add and replace, send one notification with all nexthops. For
5164 : : * append, send one notification with all appended nexthops.
5165 : : */
5166 : 0 : info->skip_notify_kernel = 1;
5167 : :
5168 : 0 : err_nh = NULL;
5169 [ # # ]: 0 : list_for_each_entry(nh, &rt6_nh_list, next) {
5170 : 0 : err = __ip6_ins_rt(nh->fib6_info, info, extack);
5171 : 0 : fib6_info_release(nh->fib6_info);
5172 : :
5173 [ # # ]: 0 : if (!err) {
5174 : : /* save reference to last route successfully inserted */
5175 : 0 : rt_last = nh->fib6_info;
5176 : :
5177 : : /* save reference to first route for notification */
5178 [ # # ]: 0 : if (!rt_notif)
5179 : 0 : rt_notif = nh->fib6_info;
5180 : : }
5181 : :
5182 : : /* nh->fib6_info is used or freed at this point, reset to NULL*/
5183 : 0 : nh->fib6_info = NULL;
5184 [ # # ]: 0 : if (err) {
5185 [ # # ]: 0 : if (replace && nhn)
5186 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack,
5187 : : "multipath route replace failed (check consistency of installed routes)");
5188 : 0 : err_nh = nh;
5189 : 0 : goto add_errout;
5190 : : }
5191 : :
5192 : : /* Because each route is added like a single route we remove
5193 : : * these flags after the first nexthop: if there is a collision,
5194 : : * we have already failed to add the first nexthop:
5195 : : * fib6_add_rt2node() has rejected it; when replacing, old
5196 : : * nexthops have been replaced by first new, the rest should
5197 : : * be added to it.
5198 : : */
5199 : 0 : cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
5200 : : NLM_F_REPLACE);
5201 : 0 : cfg->fc_nlinfo.nlh->nlmsg_flags |= NLM_F_CREATE;
5202 : 0 : nhn++;
5203 : : }
5204 : :
5205 : : /* An in-kernel notification should only be sent in case the new
5206 : : * multipath route is added as the first route in the node, or if
5207 : : * it was appended to it. We pass 'rt_notif' since it is the first
5208 : : * sibling and might allow us to skip some checks in the replace case.
5209 : : */
5210 [ # # ]: 0 : if (ip6_route_mpath_should_notify(rt_notif)) {
5211 : 0 : enum fib_event_type fib_event;
5212 : :
5213 [ # # ]: 0 : if (rt_notif->fib6_nsiblings != nhn - 1)
5214 : : fib_event = FIB_EVENT_ENTRY_APPEND;
5215 : : else
5216 : 0 : fib_event = FIB_EVENT_ENTRY_REPLACE;
5217 : :
5218 : 0 : err = call_fib6_multipath_entry_notifiers(info->nl_net,
5219 : : fib_event, rt_notif,
5220 : : nhn - 1, extack);
5221 [ # # ]: 0 : if (err) {
5222 : : /* Delete all the siblings that were just added */
5223 : 0 : err_nh = NULL;
5224 : 0 : goto add_errout;
5225 : : }
5226 : : }
5227 : :
5228 : : /* success ... tell user about new route */
5229 : 0 : ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
5230 : 0 : goto cleanup;
5231 : :
5232 : 0 : add_errout:
5233 : : /* send notification for routes that were added so that
5234 : : * the delete notifications sent by ip6_route_del are
5235 : : * coherent
5236 : : */
5237 [ # # ]: 0 : if (rt_notif)
5238 : 0 : ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
5239 : :
5240 : : /* Delete routes that were already added */
5241 [ # # ]: 0 : list_for_each_entry(nh, &rt6_nh_list, next) {
5242 [ # # ]: 0 : if (err_nh == nh)
5243 : : break;
5244 : 0 : ip6_route_del(&nh->r_cfg, extack);
5245 : : }
5246 : :
5247 : 0 : cleanup:
5248 [ # # ]: 0 : list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
5249 [ # # ]: 0 : if (nh->fib6_info)
5250 : 0 : fib6_info_release(nh->fib6_info);
5251 : 0 : list_del(&nh->next);
5252 : 0 : kfree(nh);
5253 : : }
5254 : :
5255 : : return err;
5256 : : }
5257 : :
5258 : 0 : static int ip6_route_multipath_del(struct fib6_config *cfg,
5259 : : struct netlink_ext_ack *extack)
5260 : : {
5261 : 0 : struct fib6_config r_cfg;
5262 : 0 : struct rtnexthop *rtnh;
5263 : 0 : int remaining;
5264 : 0 : int attrlen;
5265 : 0 : int err = 1, last_err = 0;
5266 : :
5267 : 0 : remaining = cfg->fc_mp_len;
5268 : 0 : rtnh = (struct rtnexthop *)cfg->fc_mp;
5269 : :
5270 : : /* Parse a Multipath Entry */
5271 [ # # ]: 0 : while (rtnh_ok(rtnh, remaining)) {
5272 : 0 : memcpy(&r_cfg, cfg, sizeof(*cfg));
5273 [ # # ]: 0 : if (rtnh->rtnh_ifindex)
5274 : 0 : r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
5275 : :
5276 [ # # ]: 0 : attrlen = rtnh_attrlen(rtnh);
5277 [ # # ]: 0 : if (attrlen > 0) {
5278 : 0 : struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
5279 : :
5280 : 0 : nla = nla_find(attrs, attrlen, RTA_GATEWAY);
5281 [ # # ]: 0 : if (nla) {
5282 : 0 : nla_memcpy(&r_cfg.fc_gateway, nla, 16);
5283 : 0 : r_cfg.fc_flags |= RTF_GATEWAY;
5284 : : }
5285 : : }
5286 : 0 : err = ip6_route_del(&r_cfg, extack);
5287 [ # # ]: 0 : if (err)
5288 : 0 : last_err = err;
5289 : :
5290 : 0 : rtnh = rtnh_next(rtnh, &remaining);
5291 : : }
5292 : :
5293 : 0 : return last_err;
5294 : : }
5295 : :
5296 : 0 : static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
5297 : : struct netlink_ext_ack *extack)
5298 : : {
5299 : 0 : struct fib6_config cfg;
5300 : 0 : int err;
5301 : :
5302 : 0 : err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
5303 [ # # ]: 0 : if (err < 0)
5304 : : return err;
5305 : :
5306 [ # # # # ]: 0 : if (cfg.fc_nh_id &&
5307 : 0 : !nexthop_find_by_id(sock_net(skb->sk), cfg.fc_nh_id)) {
5308 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "Nexthop id does not exist");
5309 : 0 : return -EINVAL;
5310 : : }
5311 : :
5312 [ # # ]: 0 : if (cfg.fc_mp)
5313 : 0 : return ip6_route_multipath_del(&cfg, extack);
5314 : : else {
5315 : 0 : cfg.fc_delete_all_nh = 1;
5316 : 0 : return ip6_route_del(&cfg, extack);
5317 : : }
5318 : : }
5319 : :
5320 : 0 : static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
5321 : : struct netlink_ext_ack *extack)
5322 : : {
5323 : 0 : struct fib6_config cfg;
5324 : 0 : int err;
5325 : :
5326 : 0 : err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
5327 [ # # ]: 0 : if (err < 0)
5328 : : return err;
5329 : :
5330 [ # # ]: 0 : if (cfg.fc_metric == 0)
5331 : 0 : cfg.fc_metric = IP6_RT_PRIO_USER;
5332 : :
5333 [ # # ]: 0 : if (cfg.fc_mp)
5334 : 0 : return ip6_route_multipath_add(&cfg, extack);
5335 : : else
5336 : 0 : return ip6_route_add(&cfg, GFP_KERNEL, extack);
5337 : : }
5338 : :
5339 : : /* add the overhead of this fib6_nh to nexthop_len */
5340 : 0 : static int rt6_nh_nlmsg_size(struct fib6_nh *nh, void *arg)
5341 : : {
5342 : 0 : int *nexthop_len = arg;
5343 : :
5344 [ # # ]: 0 : *nexthop_len += nla_total_size(0) /* RTA_MULTIPATH */
5345 : : + NLA_ALIGN(sizeof(struct rtnexthop))
5346 : : + nla_total_size(16); /* RTA_GATEWAY */
5347 : :
5348 [ # # ]: 0 : if (nh->fib_nh_lws) {
5349 : : /* RTA_ENCAP_TYPE */
5350 : 0 : *nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws);
5351 : : /* RTA_ENCAP */
5352 : 0 : *nexthop_len += nla_total_size(2);
5353 : : }
5354 : :
5355 : 0 : return 0;
5356 : : }
5357 : :
5358 : : static size_t rt6_nlmsg_size(struct fib6_info *f6i)
5359 : : {
5360 : : int nexthop_len;
5361 : :
5362 : : if (f6i->nh) {
5363 : : nexthop_len = nla_total_size(4); /* RTA_NH_ID */
5364 : : nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size,
5365 : : &nexthop_len);
5366 : : } else {
5367 : : struct fib6_nh *nh = f6i->fib6_nh;
5368 : :
5369 : : nexthop_len = 0;
5370 : : if (f6i->fib6_nsiblings) {
5371 : : nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
5372 : : + NLA_ALIGN(sizeof(struct rtnexthop))
5373 : : + nla_total_size(16) /* RTA_GATEWAY */
5374 : : + lwtunnel_get_encap_size(nh->fib_nh_lws);
5375 : :
5376 : : nexthop_len *= f6i->fib6_nsiblings;
5377 : : }
5378 : : nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws);
5379 : : }
5380 : :
5381 : : return NLMSG_ALIGN(sizeof(struct rtmsg))
5382 : : + nla_total_size(16) /* RTA_SRC */
5383 : : + nla_total_size(16) /* RTA_DST */
5384 : : + nla_total_size(16) /* RTA_GATEWAY */
5385 : : + nla_total_size(16) /* RTA_PREFSRC */
5386 : : + nla_total_size(4) /* RTA_TABLE */
5387 : : + nla_total_size(4) /* RTA_IIF */
5388 : : + nla_total_size(4) /* RTA_OIF */
5389 : : + nla_total_size(4) /* RTA_PRIORITY */
5390 : : + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
5391 : : + nla_total_size(sizeof(struct rta_cacheinfo))
5392 : : + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
5393 : : + nla_total_size(1) /* RTA_PREF */
5394 : : + nexthop_len;
5395 : : }
5396 : :
5397 : 0 : static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
5398 : : unsigned char *flags)
5399 : : {
5400 [ # # # # ]: 0 : if (nexthop_is_multipath(nh)) {
5401 : 0 : struct nlattr *mp;
5402 : :
5403 : 0 : mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
5404 [ # # ]: 0 : if (!mp)
5405 : 0 : goto nla_put_failure;
5406 : :
5407 [ # # ]: 0 : if (nexthop_mpath_fill_node(skb, nh, AF_INET6))
5408 : 0 : goto nla_put_failure;
5409 : :
5410 : 0 : nla_nest_end(skb, mp);
5411 : : } else {
5412 : 0 : struct fib6_nh *fib6_nh;
5413 : :
5414 [ # # ]: 0 : fib6_nh = nexthop_fib6_nh(nh);
5415 [ # # ]: 0 : if (fib_nexthop_info(skb, &fib6_nh->nh_common, AF_INET6,
5416 : : flags, false) < 0)
5417 : 0 : goto nla_put_failure;
5418 : : }
5419 : :
5420 : : return 0;
5421 : :
5422 : : nla_put_failure:
5423 : : return -EMSGSIZE;
5424 : : }
5425 : :
5426 : : static int rt6_fill_node(struct net *net, struct sk_buff *skb,
5427 : : struct fib6_info *rt, struct dst_entry *dst,
5428 : : struct in6_addr *dest, struct in6_addr *src,
5429 : : int iif, int type, u32 portid, u32 seq,
5430 : : unsigned int flags)
5431 : : {
5432 : : struct rt6_info *rt6 = (struct rt6_info *)dst;
5433 : : struct rt6key *rt6_dst, *rt6_src;
5434 : : u32 *pmetrics, table, rt6_flags;
5435 : : unsigned char nh_flags = 0;
5436 : : struct nlmsghdr *nlh;
5437 : : struct rtmsg *rtm;
5438 : : long expires = 0;
5439 : :
5440 : : nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
5441 : : if (!nlh)
5442 : : return -EMSGSIZE;
5443 : :
5444 : : if (rt6) {
5445 : : rt6_dst = &rt6->rt6i_dst;
5446 : : rt6_src = &rt6->rt6i_src;
5447 : : rt6_flags = rt6->rt6i_flags;
5448 : : } else {
5449 : : rt6_dst = &rt->fib6_dst;
5450 : : rt6_src = &rt->fib6_src;
5451 : : rt6_flags = rt->fib6_flags;
5452 : : }
5453 : :
5454 : : rtm = nlmsg_data(nlh);
5455 : : rtm->rtm_family = AF_INET6;
5456 : : rtm->rtm_dst_len = rt6_dst->plen;
5457 : : rtm->rtm_src_len = rt6_src->plen;
5458 : : rtm->rtm_tos = 0;
5459 : : if (rt->fib6_table)
5460 : : table = rt->fib6_table->tb6_id;
5461 : : else
5462 : : table = RT6_TABLE_UNSPEC;
5463 : : rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT;
5464 : : if (nla_put_u32(skb, RTA_TABLE, table))
5465 : : goto nla_put_failure;
5466 : :
5467 : : rtm->rtm_type = rt->fib6_type;
5468 : : rtm->rtm_flags = 0;
5469 : : rtm->rtm_scope = RT_SCOPE_UNIVERSE;
5470 : : rtm->rtm_protocol = rt->fib6_protocol;
5471 : :
5472 : : if (rt6_flags & RTF_CACHE)
5473 : : rtm->rtm_flags |= RTM_F_CLONED;
5474 : :
5475 : : if (dest) {
5476 : : if (nla_put_in6_addr(skb, RTA_DST, dest))
5477 : : goto nla_put_failure;
5478 : : rtm->rtm_dst_len = 128;
5479 : : } else if (rtm->rtm_dst_len)
5480 : : if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
5481 : : goto nla_put_failure;
5482 : : #ifdef CONFIG_IPV6_SUBTREES
5483 : : if (src) {
5484 : : if (nla_put_in6_addr(skb, RTA_SRC, src))
5485 : : goto nla_put_failure;
5486 : : rtm->rtm_src_len = 128;
5487 : : } else if (rtm->rtm_src_len &&
5488 : : nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
5489 : : goto nla_put_failure;
5490 : : #endif
5491 : : if (iif) {
5492 : : #ifdef CONFIG_IPV6_MROUTE
5493 : : if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
5494 : : int err = ip6mr_get_route(net, skb, rtm, portid);
5495 : :
5496 : : if (err == 0)
5497 : : return 0;
5498 : : if (err < 0)
5499 : : goto nla_put_failure;
5500 : : } else
5501 : : #endif
5502 : : if (nla_put_u32(skb, RTA_IIF, iif))
5503 : : goto nla_put_failure;
5504 : : } else if (dest) {
5505 : : struct in6_addr saddr_buf;
5506 : : if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
5507 : : nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
5508 : : goto nla_put_failure;
5509 : : }
5510 : :
5511 : : if (rt->fib6_prefsrc.plen) {
5512 : : struct in6_addr saddr_buf;
5513 : : saddr_buf = rt->fib6_prefsrc.addr;
5514 : : if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
5515 : : goto nla_put_failure;
5516 : : }
5517 : :
5518 : : pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
5519 : : if (rtnetlink_put_metrics(skb, pmetrics) < 0)
5520 : : goto nla_put_failure;
5521 : :
5522 : : if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
5523 : : goto nla_put_failure;
5524 : :
5525 : : /* For multipath routes, walk the siblings list and add
5526 : : * each as a nexthop within RTA_MULTIPATH.
5527 : : */
5528 : : if (rt6) {
5529 : : if (rt6_flags & RTF_GATEWAY &&
5530 : : nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
5531 : : goto nla_put_failure;
5532 : :
5533 : : if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
5534 : : goto nla_put_failure;
5535 : : } else if (rt->fib6_nsiblings) {
5536 : : struct fib6_info *sibling, *next_sibling;
5537 : : struct nlattr *mp;
5538 : :
5539 : : mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
5540 : : if (!mp)
5541 : : goto nla_put_failure;
5542 : :
5543 : : if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common,
5544 : : rt->fib6_nh->fib_nh_weight, AF_INET6) < 0)
5545 : : goto nla_put_failure;
5546 : :
5547 : : list_for_each_entry_safe(sibling, next_sibling,
5548 : : &rt->fib6_siblings, fib6_siblings) {
5549 : : if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common,
5550 : : sibling->fib6_nh->fib_nh_weight,
5551 : : AF_INET6) < 0)
5552 : : goto nla_put_failure;
5553 : : }
5554 : :
5555 : : nla_nest_end(skb, mp);
5556 : : } else if (rt->nh) {
5557 : : if (nla_put_u32(skb, RTA_NH_ID, rt->nh->id))
5558 : : goto nla_put_failure;
5559 : :
5560 : : if (nexthop_is_blackhole(rt->nh))
5561 : : rtm->rtm_type = RTN_BLACKHOLE;
5562 : :
5563 : : if (rt6_fill_node_nexthop(skb, rt->nh, &nh_flags) < 0)
5564 : : goto nla_put_failure;
5565 : :
5566 : : rtm->rtm_flags |= nh_flags;
5567 : : } else {
5568 : : if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, AF_INET6,
5569 : : &nh_flags, false) < 0)
5570 : : goto nla_put_failure;
5571 : :
5572 : : rtm->rtm_flags |= nh_flags;
5573 : : }
5574 : :
5575 : : if (rt6_flags & RTF_EXPIRES) {
5576 : : expires = dst ? dst->expires : rt->expires;
5577 : : expires -= jiffies;
5578 : : }
5579 : :
5580 : : if (!dst) {
5581 : : if (rt->offload)
5582 : : rtm->rtm_flags |= RTM_F_OFFLOAD;
5583 : : if (rt->trap)
5584 : : rtm->rtm_flags |= RTM_F_TRAP;
5585 : : }
5586 : :
5587 : : if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
5588 : : goto nla_put_failure;
5589 : :
5590 : : if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
5591 : : goto nla_put_failure;
5592 : :
5593 : :
5594 : : nlmsg_end(skb, nlh);
5595 : : return 0;
5596 : :
5597 : : nla_put_failure:
5598 : : nlmsg_cancel(skb, nlh);
5599 : : return -EMSGSIZE;
5600 : : }
5601 : :
5602 : 0 : static int fib6_info_nh_uses_dev(struct fib6_nh *nh, void *arg)
5603 : : {
5604 : 0 : const struct net_device *dev = arg;
5605 : :
5606 [ # # ]: 0 : if (nh->fib_nh_dev == dev)
5607 : 0 : return 1;
5608 : :
5609 : : return 0;
5610 : : }
5611 : :
5612 : 0 : static bool fib6_info_uses_dev(const struct fib6_info *f6i,
5613 : : const struct net_device *dev)
5614 : : {
5615 [ # # ]: 0 : if (f6i->nh) {
5616 : 0 : struct net_device *_dev = (struct net_device *)dev;
5617 : :
5618 : 0 : return !!nexthop_for_each_fib6_nh(f6i->nh,
5619 : : fib6_info_nh_uses_dev,
5620 : : _dev);
5621 : : }
5622 : :
5623 [ # # ]: 0 : if (f6i->fib6_nh->fib_nh_dev == dev)
5624 : : return true;
5625 : :
5626 [ # # ]: 0 : if (f6i->fib6_nsiblings) {
5627 : 0 : struct fib6_info *sibling, *next_sibling;
5628 : :
5629 [ # # ]: 0 : list_for_each_entry_safe(sibling, next_sibling,
5630 : : &f6i->fib6_siblings, fib6_siblings) {
5631 [ # # ]: 0 : if (sibling->fib6_nh->fib_nh_dev == dev)
5632 : : return true;
5633 : : }
5634 : : }
5635 : :
5636 : : return false;
5637 : : }
5638 : :
5639 : : struct fib6_nh_exception_dump_walker {
5640 : : struct rt6_rtnl_dump_arg *dump;
5641 : : struct fib6_info *rt;
5642 : : unsigned int flags;
5643 : : unsigned int skip;
5644 : : unsigned int count;
5645 : : };
5646 : :
5647 : 0 : static int rt6_nh_dump_exceptions(struct fib6_nh *nh, void *arg)
5648 : : {
5649 : 0 : struct fib6_nh_exception_dump_walker *w = arg;
5650 : 0 : struct rt6_rtnl_dump_arg *dump = w->dump;
5651 : 0 : struct rt6_exception_bucket *bucket;
5652 : 0 : struct rt6_exception *rt6_ex;
5653 : 0 : int i, err;
5654 : :
5655 [ # # ]: 0 : bucket = fib6_nh_get_excptn_bucket(nh, NULL);
5656 [ # # ]: 0 : if (!bucket)
5657 : : return 0;
5658 : :
5659 [ # # ]: 0 : for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
5660 [ # # # # : 0 : hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
# # ]
5661 [ # # ]: 0 : if (w->skip) {
5662 : 0 : w->skip--;
5663 : 0 : continue;
5664 : : }
5665 : :
5666 : : /* Expiration of entries doesn't bump sernum, insertion
5667 : : * does. Removal is triggered by insertion, so we can
5668 : : * rely on the fact that if entries change between two
5669 : : * partial dumps, this node is scanned again completely,
5670 : : * see rt6_insert_exception() and fib6_dump_table().
5671 : : *
5672 : : * Count expired entries we go through as handled
5673 : : * entries that we'll skip next time, in case of partial
5674 : : * node dump. Otherwise, if entries expire meanwhile,
5675 : : * we'll skip the wrong amount.
5676 : : */
5677 [ # # ]: 0 : if (rt6_check_expired(rt6_ex->rt6i)) {
5678 : 0 : w->count++;
5679 : 0 : continue;
5680 : : }
5681 : :
5682 : 0 : err = rt6_fill_node(dump->net, dump->skb, w->rt,
5683 : 0 : &rt6_ex->rt6i->dst, NULL, NULL, 0,
5684 : : RTM_NEWROUTE,
5685 : 0 : NETLINK_CB(dump->cb->skb).portid,
5686 : 0 : dump->cb->nlh->nlmsg_seq, w->flags);
5687 [ # # ]: 0 : if (err)
5688 : 0 : return err;
5689 : :
5690 : 0 : w->count++;
5691 : : }
5692 : 0 : bucket++;
5693 : : }
5694 : :
5695 : : return 0;
5696 : : }
5697 : :
5698 : : /* Return -1 if done with node, number of handled routes on partial dump */
5699 : 0 : int rt6_dump_route(struct fib6_info *rt, void *p_arg, unsigned int skip)
5700 : : {
5701 : 0 : struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
5702 : 0 : struct fib_dump_filter *filter = &arg->filter;
5703 : 0 : unsigned int flags = NLM_F_MULTI;
5704 : 0 : struct net *net = arg->net;
5705 : 0 : int count = 0;
5706 : :
5707 [ # # ]: 0 : if (rt == net->ipv6.fib6_null_entry)
5708 : : return -1;
5709 : :
5710 [ # # ]: 0 : if ((filter->flags & RTM_F_PREFIX) &&
5711 [ # # ]: 0 : !(rt->fib6_flags & RTF_PREFIX_RT)) {
5712 : : /* success since this is not a prefix route */
5713 : : return -1;
5714 : : }
5715 [ # # ]: 0 : if (filter->filter_set &&
5716 [ # # # # ]: 0 : ((filter->rt_type && rt->fib6_type != filter->rt_type) ||
5717 [ # # # # ]: 0 : (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) ||
5718 [ # # # # ]: 0 : (filter->protocol && rt->fib6_protocol != filter->protocol))) {
5719 : 0 : return -1;
5720 : : }
5721 : :
5722 [ # # ]: 0 : if (filter->filter_set ||
5723 [ # # # # ]: 0 : !filter->dump_routes || !filter->dump_exceptions) {
5724 : 0 : flags |= NLM_F_DUMP_FILTERED;
5725 : : }
5726 : :
5727 [ # # ]: 0 : if (filter->dump_routes) {
5728 [ # # ]: 0 : if (skip) {
5729 : 0 : skip--;
5730 : : } else {
5731 [ # # ]: 0 : if (rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL,
5732 : : 0, RTM_NEWROUTE,
5733 : 0 : NETLINK_CB(arg->cb->skb).portid,
5734 : 0 : arg->cb->nlh->nlmsg_seq, flags)) {
5735 : : return 0;
5736 : : }
5737 : : count++;
5738 : : }
5739 : : }
5740 : :
5741 [ # # ]: 0 : if (filter->dump_exceptions) {
5742 : 0 : struct fib6_nh_exception_dump_walker w = { .dump = arg,
5743 : : .rt = rt,
5744 : : .flags = flags,
5745 : : .skip = skip,
5746 : : .count = 0 };
5747 : 0 : int err;
5748 : :
5749 : 0 : rcu_read_lock();
5750 [ # # ]: 0 : if (rt->nh) {
5751 : 0 : err = nexthop_for_each_fib6_nh(rt->nh,
5752 : : rt6_nh_dump_exceptions,
5753 : : &w);
5754 : : } else {
5755 : 0 : err = rt6_nh_dump_exceptions(rt->fib6_nh, &w);
5756 : : }
5757 : 0 : rcu_read_unlock();
5758 : :
5759 [ # # ]: 0 : if (err)
5760 : 0 : return count += w.count;
5761 : : }
5762 : :
5763 : : return -1;
5764 : : }
5765 : :
5766 : 0 : static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
5767 : : const struct nlmsghdr *nlh,
5768 : : struct nlattr **tb,
5769 : : struct netlink_ext_ack *extack)
5770 : : {
5771 : 0 : struct rtmsg *rtm;
5772 : 0 : int i, err;
5773 : :
5774 [ # # ]: 0 : if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
5775 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack,
5776 : : "Invalid header for get route request");
5777 : 0 : return -EINVAL;
5778 : : }
5779 : :
5780 [ # # ]: 0 : if (!netlink_strict_get_check(skb))
5781 : 0 : return nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
5782 : : rtm_ipv6_policy, extack);
5783 : :
5784 [ # # ]: 0 : rtm = nlmsg_data(nlh);
5785 [ # # ]: 0 : if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
5786 [ # # ]: 0 : (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
5787 [ # # ]: 0 : rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
5788 : : rtm->rtm_type) {
5789 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
5790 : 0 : return -EINVAL;
5791 : : }
5792 [ # # ]: 0 : if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
5793 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack,
5794 : : "Invalid flags for get route request");
5795 : 0 : return -EINVAL;
5796 : : }
5797 : :
5798 : 0 : err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
5799 : : rtm_ipv6_policy, extack);
5800 [ # # ]: 0 : if (err)
5801 : : return err;
5802 : :
5803 [ # # # # ]: 0 : if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
5804 [ # # # # ]: 0 : (tb[RTA_DST] && !rtm->rtm_dst_len)) {
5805 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
5806 : 0 : return -EINVAL;
5807 : : }
5808 : :
5809 [ # # ]: 0 : for (i = 0; i <= RTA_MAX; i++) {
5810 [ # # ]: 0 : if (!tb[i])
5811 : 0 : continue;
5812 : :
5813 [ # # ]: 0 : switch (i) {
5814 : : case RTA_SRC:
5815 : : case RTA_DST:
5816 : : case RTA_IIF:
5817 : : case RTA_OIF:
5818 : : case RTA_MARK:
5819 : : case RTA_UID:
5820 : : case RTA_SPORT:
5821 : : case RTA_DPORT:
5822 : : case RTA_IP_PROTO:
5823 : : break;
5824 : 0 : default:
5825 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
5826 : : return -EINVAL;
5827 : : }
5828 : : }
5829 : :
5830 : : return 0;
5831 : : }
5832 : :
5833 : 0 : static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
5834 : : struct netlink_ext_ack *extack)
5835 : : {
5836 : 0 : struct net *net = sock_net(in_skb->sk);
5837 : 0 : struct nlattr *tb[RTA_MAX+1];
5838 : 0 : int err, iif = 0, oif = 0;
5839 : 0 : struct fib6_info *from;
5840 : 0 : struct dst_entry *dst;
5841 : 0 : struct rt6_info *rt;
5842 : 0 : struct sk_buff *skb;
5843 : 0 : struct rtmsg *rtm;
5844 : 0 : struct flowi6 fl6 = {};
5845 : 0 : bool fibmatch;
5846 : :
5847 : 0 : err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
5848 [ # # ]: 0 : if (err < 0)
5849 : 0 : goto errout;
5850 : :
5851 : 0 : err = -EINVAL;
5852 [ # # ]: 0 : rtm = nlmsg_data(nlh);
5853 [ # # ]: 0 : fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
5854 : 0 : fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
5855 : :
5856 [ # # ]: 0 : if (tb[RTA_SRC]) {
5857 [ # # ]: 0 : if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
5858 : 0 : goto errout;
5859 : :
5860 : 0 : fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
5861 : : }
5862 : :
5863 [ # # ]: 0 : if (tb[RTA_DST]) {
5864 [ # # ]: 0 : if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
5865 : 0 : goto errout;
5866 : :
5867 : 0 : fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
5868 : : }
5869 : :
5870 [ # # ]: 0 : if (tb[RTA_IIF])
5871 : 0 : iif = nla_get_u32(tb[RTA_IIF]);
5872 : :
5873 [ # # ]: 0 : if (tb[RTA_OIF])
5874 : 0 : oif = nla_get_u32(tb[RTA_OIF]);
5875 : :
5876 [ # # ]: 0 : if (tb[RTA_MARK])
5877 : 0 : fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
5878 : :
5879 [ # # ]: 0 : if (tb[RTA_UID])
5880 : 0 : fl6.flowi6_uid = make_kuid(current_user_ns(),
5881 : : nla_get_u32(tb[RTA_UID]));
5882 : : else
5883 [ # # ]: 0 : fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
5884 : :
5885 [ # # ]: 0 : if (tb[RTA_SPORT])
5886 : 0 : fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
5887 : :
5888 [ # # ]: 0 : if (tb[RTA_DPORT])
5889 : 0 : fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
5890 : :
5891 [ # # ]: 0 : if (tb[RTA_IP_PROTO]) {
5892 : 0 : err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
5893 : : &fl6.flowi6_proto, AF_INET6,
5894 : : extack);
5895 [ # # ]: 0 : if (err)
5896 : 0 : goto errout;
5897 : : }
5898 : :
5899 [ # # ]: 0 : if (iif) {
5900 : 0 : struct net_device *dev;
5901 : 0 : int flags = 0;
5902 : :
5903 : 0 : rcu_read_lock();
5904 : :
5905 : 0 : dev = dev_get_by_index_rcu(net, iif);
5906 [ # # ]: 0 : if (!dev) {
5907 : 0 : rcu_read_unlock();
5908 : 0 : err = -ENODEV;
5909 : 0 : goto errout;
5910 : : }
5911 : :
5912 : 0 : fl6.flowi6_iif = iif;
5913 : :
5914 [ # # ]: 0 : if (!ipv6_addr_any(&fl6.saddr))
5915 : 0 : flags |= RT6_LOOKUP_F_HAS_SADDR;
5916 : :
5917 : 0 : dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
5918 : :
5919 : 0 : rcu_read_unlock();
5920 : : } else {
5921 : 0 : fl6.flowi6_oif = oif;
5922 : :
5923 : 0 : dst = ip6_route_output(net, NULL, &fl6);
5924 : : }
5925 : :
5926 : :
5927 : 0 : rt = container_of(dst, struct rt6_info, dst);
5928 [ # # ]: 0 : if (rt->dst.error) {
5929 : 0 : err = rt->dst.error;
5930 : 0 : ip6_rt_put(rt);
5931 : 0 : goto errout;
5932 : : }
5933 : :
5934 [ # # ]: 0 : if (rt == net->ipv6.ip6_null_entry) {
5935 : 0 : err = rt->dst.error;
5936 : 0 : ip6_rt_put(rt);
5937 : 0 : goto errout;
5938 : : }
5939 : :
5940 : 0 : skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
5941 [ # # ]: 0 : if (!skb) {
5942 : 0 : ip6_rt_put(rt);
5943 : 0 : err = -ENOBUFS;
5944 : 0 : goto errout;
5945 : : }
5946 : :
5947 : 0 : skb_dst_set(skb, &rt->dst);
5948 : :
5949 : 0 : rcu_read_lock();
5950 [ # # ]: 0 : from = rcu_dereference(rt->from);
5951 [ # # ]: 0 : if (from) {
5952 [ # # ]: 0 : if (fibmatch)
5953 : 0 : err = rt6_fill_node(net, skb, from, NULL, NULL, NULL,
5954 : : iif, RTM_NEWROUTE,
5955 : : NETLINK_CB(in_skb).portid,
5956 : : nlh->nlmsg_seq, 0);
5957 : : else
5958 : 0 : err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5959 : : &fl6.saddr, iif, RTM_NEWROUTE,
5960 : : NETLINK_CB(in_skb).portid,
5961 : : nlh->nlmsg_seq, 0);
5962 : : } else {
5963 : : err = -ENETUNREACH;
5964 : : }
5965 : 0 : rcu_read_unlock();
5966 : :
5967 [ # # ]: 0 : if (err < 0) {
5968 : 0 : kfree_skb(skb);
5969 : 0 : goto errout;
5970 : : }
5971 : :
5972 : 0 : err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
5973 : 0 : errout:
5974 : 0 : return err;
5975 : : }
5976 : :
5977 : 240 : void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
5978 : : unsigned int nlm_flags)
5979 : : {
5980 : 240 : struct sk_buff *skb;
5981 : 240 : struct net *net = info->nl_net;
5982 : 240 : u32 seq;
5983 : 240 : int err;
5984 : :
5985 : 240 : err = -ENOBUFS;
5986 [ - + ]: 240 : seq = info->nlh ? info->nlh->nlmsg_seq : 0;
5987 : :
5988 [ - + ]: 240 : skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
5989 [ - + ]: 240 : if (!skb)
5990 : 0 : goto errout;
5991 : :
5992 : 240 : err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
5993 : : event, info->portid, seq, nlm_flags);
5994 [ - + ]: 240 : if (err < 0) {
5995 : : /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
5996 [ # # ]: 0 : WARN_ON(err == -EMSGSIZE);
5997 : 0 : kfree_skb(skb);
5998 : 0 : goto errout;
5999 : : }
6000 [ - + ]: 240 : rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
6001 : : info->nlh, gfp_any());
6002 : 240 : return;
6003 : : errout:
6004 : 0 : if (err < 0)
6005 : 0 : rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
6006 : : }
6007 : :
6008 : 0 : void fib6_rt_update(struct net *net, struct fib6_info *rt,
6009 : : struct nl_info *info)
6010 : : {
6011 [ # # ]: 0 : u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
6012 : 0 : struct sk_buff *skb;
6013 : 0 : int err = -ENOBUFS;
6014 : :
6015 : : /* call_fib6_entry_notifiers will be removed when in-kernel notifier
6016 : : * is implemented and supported for nexthop objects
6017 : : */
6018 : 0 : call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, rt, NULL);
6019 : :
6020 [ # # ]: 0 : skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
6021 [ # # ]: 0 : if (!skb)
6022 : 0 : goto errout;
6023 : :
6024 : 0 : err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
6025 : : RTM_NEWROUTE, info->portid, seq, NLM_F_REPLACE);
6026 [ # # ]: 0 : if (err < 0) {
6027 : : /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
6028 [ # # ]: 0 : WARN_ON(err == -EMSGSIZE);
6029 : 0 : kfree_skb(skb);
6030 : 0 : goto errout;
6031 : : }
6032 [ # # ]: 0 : rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
6033 : : info->nlh, gfp_any());
6034 : 0 : return;
6035 : : errout:
6036 : 0 : if (err < 0)
6037 : 0 : rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
6038 : : }
6039 : :
6040 : 550 : static int ip6_route_dev_notify(struct notifier_block *this,
6041 : : unsigned long event, void *ptr)
6042 : : {
6043 [ + + ]: 550 : struct net_device *dev = netdev_notifier_info_to_dev(ptr);
6044 [ + + ]: 550 : struct net *net = dev_net(dev);
6045 : :
6046 [ + + ]: 550 : if (!(dev->flags & IFF_LOOPBACK))
6047 : : return NOTIFY_OK;
6048 : :
6049 [ + + ]: 234 : if (event == NETDEV_REGISTER) {
6050 : 78 : net->ipv6.fib6_null_entry->fib6_nh->fib_nh_dev = dev;
6051 : 78 : net->ipv6.ip6_null_entry->dst.dev = dev;
6052 : 156 : net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
6053 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6054 : : net->ipv6.ip6_prohibit_entry->dst.dev = dev;
6055 : : net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
6056 : : net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
6057 : : net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
6058 : : #endif
6059 [ - + ]: 156 : } else if (event == NETDEV_UNREGISTER &&
6060 [ # # ]: 0 : dev->reg_state != NETREG_UNREGISTERED) {
6061 : : /* NETDEV_UNREGISTER could be fired for multiple times by
6062 : : * netdev_wait_allrefs(). Make sure we only call this once.
6063 : : */
6064 [ # # ]: 0 : in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
6065 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6066 : : in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
6067 : : in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
6068 : : #endif
6069 : : }
6070 : :
6071 : : return NOTIFY_OK;
6072 : : }
6073 : :
6074 : : /*
6075 : : * /proc
6076 : : */
6077 : :
6078 : : #ifdef CONFIG_PROC_FS
6079 : 0 : static int rt6_stats_seq_show(struct seq_file *seq, void *v)
6080 : : {
6081 : 0 : struct net *net = (struct net *)seq->private;
6082 : 0 : seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
6083 : : net->ipv6.rt6_stats->fib_nodes,
6084 : 0 : net->ipv6.rt6_stats->fib_route_nodes,
6085 : 0 : atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
6086 : : net->ipv6.rt6_stats->fib_rt_entries,
6087 : 0 : net->ipv6.rt6_stats->fib_rt_cache,
6088 : : dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
6089 : 0 : net->ipv6.rt6_stats->fib_discarded_routes);
6090 : :
6091 : 0 : return 0;
6092 : : }
6093 : : #endif /* CONFIG_PROC_FS */
6094 : :
6095 : : #ifdef CONFIG_SYSCTL
6096 : :
6097 : : static
6098 : 0 : int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
6099 : : void __user *buffer, size_t *lenp, loff_t *ppos)
6100 : : {
6101 : 0 : struct net *net;
6102 : 0 : int delay;
6103 : 0 : int ret;
6104 [ # # ]: 0 : if (!write)
6105 : : return -EINVAL;
6106 : :
6107 : 0 : net = (struct net *)ctl->extra1;
6108 : 0 : delay = net->ipv6.sysctl.flush_delay;
6109 : 0 : ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
6110 [ # # ]: 0 : if (ret)
6111 : : return ret;
6112 : :
6113 : 0 : fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
6114 : 0 : return 0;
6115 : : }
6116 : :
6117 : : static struct ctl_table ipv6_route_table_template[] = {
6118 : : {
6119 : : .procname = "flush",
6120 : : .data = &init_net.ipv6.sysctl.flush_delay,
6121 : : .maxlen = sizeof(int),
6122 : : .mode = 0200,
6123 : : .proc_handler = ipv6_sysctl_rtcache_flush
6124 : : },
6125 : : {
6126 : : .procname = "gc_thresh",
6127 : : .data = &ip6_dst_ops_template.gc_thresh,
6128 : : .maxlen = sizeof(int),
6129 : : .mode = 0644,
6130 : : .proc_handler = proc_dointvec,
6131 : : },
6132 : : {
6133 : : .procname = "max_size",
6134 : : .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
6135 : : .maxlen = sizeof(int),
6136 : : .mode = 0644,
6137 : : .proc_handler = proc_dointvec,
6138 : : },
6139 : : {
6140 : : .procname = "gc_min_interval",
6141 : : .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
6142 : : .maxlen = sizeof(int),
6143 : : .mode = 0644,
6144 : : .proc_handler = proc_dointvec_jiffies,
6145 : : },
6146 : : {
6147 : : .procname = "gc_timeout",
6148 : : .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
6149 : : .maxlen = sizeof(int),
6150 : : .mode = 0644,
6151 : : .proc_handler = proc_dointvec_jiffies,
6152 : : },
6153 : : {
6154 : : .procname = "gc_interval",
6155 : : .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
6156 : : .maxlen = sizeof(int),
6157 : : .mode = 0644,
6158 : : .proc_handler = proc_dointvec_jiffies,
6159 : : },
6160 : : {
6161 : : .procname = "gc_elasticity",
6162 : : .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
6163 : : .maxlen = sizeof(int),
6164 : : .mode = 0644,
6165 : : .proc_handler = proc_dointvec,
6166 : : },
6167 : : {
6168 : : .procname = "mtu_expires",
6169 : : .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
6170 : : .maxlen = sizeof(int),
6171 : : .mode = 0644,
6172 : : .proc_handler = proc_dointvec_jiffies,
6173 : : },
6174 : : {
6175 : : .procname = "min_adv_mss",
6176 : : .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
6177 : : .maxlen = sizeof(int),
6178 : : .mode = 0644,
6179 : : .proc_handler = proc_dointvec,
6180 : : },
6181 : : {
6182 : : .procname = "gc_min_interval_ms",
6183 : : .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
6184 : : .maxlen = sizeof(int),
6185 : : .mode = 0644,
6186 : : .proc_handler = proc_dointvec_ms_jiffies,
6187 : : },
6188 : : {
6189 : : .procname = "skip_notify_on_dev_down",
6190 : : .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
6191 : : .maxlen = sizeof(int),
6192 : : .mode = 0644,
6193 : : .proc_handler = proc_dointvec_minmax,
6194 : : .extra1 = SYSCTL_ZERO,
6195 : : .extra2 = SYSCTL_ONE,
6196 : : },
6197 : : { }
6198 : : };
6199 : :
6200 : 78 : struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
6201 : : {
6202 : 78 : struct ctl_table *table;
6203 : :
6204 : 78 : table = kmemdup(ipv6_route_table_template,
6205 : : sizeof(ipv6_route_table_template),
6206 : : GFP_KERNEL);
6207 : :
6208 [ + - ]: 78 : if (table) {
6209 : 78 : table[0].data = &net->ipv6.sysctl.flush_delay;
6210 : 78 : table[0].extra1 = net;
6211 : 78 : table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
6212 : 78 : table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
6213 : 78 : table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
6214 : 78 : table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
6215 : 78 : table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
6216 : 78 : table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
6217 : 78 : table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
6218 : 78 : table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
6219 : 78 : table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
6220 : 78 : table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
6221 : :
6222 : : /* Don't export sysctls to unprivileged users */
6223 [ - + ]: 78 : if (net->user_ns != &init_user_ns)
6224 : 0 : table[0].procname = NULL;
6225 : : }
6226 : :
6227 : 78 : return table;
6228 : : }
6229 : : #endif
6230 : :
6231 : 78 : static int __net_init ip6_route_net_init(struct net *net)
6232 : : {
6233 : 78 : int ret = -ENOMEM;
6234 : :
6235 : 78 : memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
6236 : : sizeof(net->ipv6.ip6_dst_ops));
6237 : :
6238 [ - + ]: 78 : if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
6239 : 0 : goto out_ip6_dst_ops;
6240 : :
6241 : 78 : net->ipv6.fib6_null_entry = fib6_info_alloc(GFP_KERNEL, true);
6242 [ - + ]: 78 : if (!net->ipv6.fib6_null_entry)
6243 : 0 : goto out_ip6_dst_entries;
6244 : 78 : memcpy(net->ipv6.fib6_null_entry, &fib6_null_entry_template,
6245 : : sizeof(*net->ipv6.fib6_null_entry));
6246 : :
6247 : 78 : net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
6248 : : sizeof(*net->ipv6.ip6_null_entry),
6249 : : GFP_KERNEL);
6250 [ - + ]: 78 : if (!net->ipv6.ip6_null_entry)
6251 : 0 : goto out_fib6_null_entry;
6252 : 78 : net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
6253 : 78 : dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
6254 : : ip6_template_metrics, true);
6255 : 78 : INIT_LIST_HEAD(&net->ipv6.ip6_null_entry->rt6i_uncached);
6256 : :
6257 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6258 : : net->ipv6.fib6_has_custom_rules = false;
6259 : : net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
6260 : : sizeof(*net->ipv6.ip6_prohibit_entry),
6261 : : GFP_KERNEL);
6262 : : if (!net->ipv6.ip6_prohibit_entry)
6263 : : goto out_ip6_null_entry;
6264 : : net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
6265 : : dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
6266 : : ip6_template_metrics, true);
6267 : : INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached);
6268 : :
6269 : : net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
6270 : : sizeof(*net->ipv6.ip6_blk_hole_entry),
6271 : : GFP_KERNEL);
6272 : : if (!net->ipv6.ip6_blk_hole_entry)
6273 : : goto out_ip6_prohibit_entry;
6274 : : net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
6275 : : dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
6276 : : ip6_template_metrics, true);
6277 : : INIT_LIST_HEAD(&net->ipv6.ip6_blk_hole_entry->rt6i_uncached);
6278 : : #ifdef CONFIG_IPV6_SUBTREES
6279 : : net->ipv6.fib6_routes_require_src = 0;
6280 : : #endif
6281 : : #endif
6282 : :
6283 : 78 : net->ipv6.sysctl.flush_delay = 0;
6284 : 78 : net->ipv6.sysctl.ip6_rt_max_size = 4096;
6285 : 78 : net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
6286 : 78 : net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
6287 : 78 : net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
6288 : 78 : net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
6289 : 78 : net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
6290 : 78 : net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
6291 : 78 : net->ipv6.sysctl.skip_notify_on_dev_down = 0;
6292 : :
6293 : 78 : net->ipv6.ip6_rt_gc_expire = 30*HZ;
6294 : :
6295 : 78 : ret = 0;
6296 : 78 : out:
6297 : 78 : return ret;
6298 : :
6299 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6300 : : out_ip6_prohibit_entry:
6301 : : kfree(net->ipv6.ip6_prohibit_entry);
6302 : : out_ip6_null_entry:
6303 : : kfree(net->ipv6.ip6_null_entry);
6304 : : #endif
6305 : : out_fib6_null_entry:
6306 : 0 : kfree(net->ipv6.fib6_null_entry);
6307 : 0 : out_ip6_dst_entries:
6308 : 0 : dst_entries_destroy(&net->ipv6.ip6_dst_ops);
6309 : 0 : out_ip6_dst_ops:
6310 : 0 : goto out;
6311 : : }
6312 : :
6313 : 0 : static void __net_exit ip6_route_net_exit(struct net *net)
6314 : : {
6315 : 0 : kfree(net->ipv6.fib6_null_entry);
6316 : 0 : kfree(net->ipv6.ip6_null_entry);
6317 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6318 : : kfree(net->ipv6.ip6_prohibit_entry);
6319 : : kfree(net->ipv6.ip6_blk_hole_entry);
6320 : : #endif
6321 : 0 : dst_entries_destroy(&net->ipv6.ip6_dst_ops);
6322 : 0 : }
6323 : :
6324 : 78 : static int __net_init ip6_route_net_init_late(struct net *net)
6325 : : {
6326 : : #ifdef CONFIG_PROC_FS
6327 : 78 : proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
6328 : : sizeof(struct ipv6_route_iter));
6329 : 78 : proc_create_net_single("rt6_stats", 0444, net->proc_net,
6330 : : rt6_stats_seq_show, NULL);
6331 : : #endif
6332 : 78 : return 0;
6333 : : }
6334 : :
6335 : 0 : static void __net_exit ip6_route_net_exit_late(struct net *net)
6336 : : {
6337 : : #ifdef CONFIG_PROC_FS
6338 : 0 : remove_proc_entry("ipv6_route", net->proc_net);
6339 : 0 : remove_proc_entry("rt6_stats", net->proc_net);
6340 : : #endif
6341 : 0 : }
6342 : :
6343 : : static struct pernet_operations ip6_route_net_ops = {
6344 : : .init = ip6_route_net_init,
6345 : : .exit = ip6_route_net_exit,
6346 : : };
6347 : :
6348 : 78 : static int __net_init ipv6_inetpeer_init(struct net *net)
6349 : : {
6350 : 78 : struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
6351 : :
6352 [ + - ]: 78 : if (!bp)
6353 : : return -ENOMEM;
6354 : 78 : inet_peer_base_init(bp);
6355 : 78 : net->ipv6.peers = bp;
6356 : 78 : return 0;
6357 : : }
6358 : :
6359 : 0 : static void __net_exit ipv6_inetpeer_exit(struct net *net)
6360 : : {
6361 : 0 : struct inet_peer_base *bp = net->ipv6.peers;
6362 : :
6363 : 0 : net->ipv6.peers = NULL;
6364 : 0 : inetpeer_invalidate_tree(bp);
6365 : 0 : kfree(bp);
6366 : 0 : }
6367 : :
6368 : : static struct pernet_operations ipv6_inetpeer_ops = {
6369 : : .init = ipv6_inetpeer_init,
6370 : : .exit = ipv6_inetpeer_exit,
6371 : : };
6372 : :
6373 : : static struct pernet_operations ip6_route_net_late_ops = {
6374 : : .init = ip6_route_net_init_late,
6375 : : .exit = ip6_route_net_exit_late,
6376 : : };
6377 : :
6378 : : static struct notifier_block ip6_route_dev_notifier = {
6379 : : .notifier_call = ip6_route_dev_notify,
6380 : : .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
6381 : : };
6382 : :
6383 : 78 : void __init ip6_route_init_special_entries(void)
6384 : : {
6385 : : /* Registering of the loopback is done before this portion of code,
6386 : : * the loopback reference in rt6_info will not be taken, do it
6387 : : * manually for init_net */
6388 : 78 : init_net.ipv6.fib6_null_entry->fib6_nh->fib_nh_dev = init_net.loopback_dev;
6389 : 78 : init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
6390 : 78 : init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
6391 : : #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6392 : : init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
6393 : : init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
6394 : : init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
6395 : : init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
6396 : : #endif
6397 : 78 : }
6398 : :
6399 : 78 : int __init ip6_route_init(void)
6400 : : {
6401 : 78 : int ret;
6402 : 78 : int cpu;
6403 : :
6404 : 78 : ret = -ENOMEM;
6405 : 156 : ip6_dst_ops_template.kmem_cachep =
6406 : 78 : kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
6407 : : SLAB_HWCACHE_ALIGN, NULL);
6408 [ - + ]: 78 : if (!ip6_dst_ops_template.kmem_cachep)
6409 : 0 : goto out;
6410 : :
6411 : 78 : ret = dst_entries_init(&ip6_dst_blackhole_ops);
6412 [ - + ]: 78 : if (ret)
6413 : 0 : goto out_kmem_cache;
6414 : :
6415 : 78 : ret = register_pernet_subsys(&ipv6_inetpeer_ops);
6416 [ - + ]: 78 : if (ret)
6417 : 0 : goto out_dst_entries;
6418 : :
6419 : 78 : ret = register_pernet_subsys(&ip6_route_net_ops);
6420 [ - + ]: 78 : if (ret)
6421 : 0 : goto out_register_inetpeer;
6422 : :
6423 : 78 : ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
6424 : :
6425 : 78 : ret = fib6_init();
6426 [ - + ]: 78 : if (ret)
6427 : 0 : goto out_register_subsys;
6428 : :
6429 : 78 : ret = xfrm6_init();
6430 [ - + ]: 78 : if (ret)
6431 : 0 : goto out_fib6_init;
6432 : :
6433 : 78 : ret = fib6_rules_init();
6434 : 78 : if (ret)
6435 : : goto xfrm6_init;
6436 : :
6437 : 78 : ret = register_pernet_subsys(&ip6_route_net_late_ops);
6438 [ - + ]: 78 : if (ret)
6439 : 0 : goto fib6_rules_init;
6440 : :
6441 : 78 : ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
6442 : : inet6_rtm_newroute, NULL, 0);
6443 [ - + ]: 78 : if (ret < 0)
6444 : 0 : goto out_register_late_subsys;
6445 : :
6446 : 78 : ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
6447 : : inet6_rtm_delroute, NULL, 0);
6448 [ - + ]: 78 : if (ret < 0)
6449 : 0 : goto out_register_late_subsys;
6450 : :
6451 : 78 : ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
6452 : : inet6_rtm_getroute, NULL,
6453 : : RTNL_FLAG_DOIT_UNLOCKED);
6454 [ - + ]: 78 : if (ret < 0)
6455 : 0 : goto out_register_late_subsys;
6456 : :
6457 : 78 : ret = register_netdevice_notifier(&ip6_route_dev_notifier);
6458 [ + - ]: 78 : if (ret)
6459 : 0 : goto out_register_late_subsys;
6460 : :
6461 [ + + ]: 156 : for_each_possible_cpu(cpu) {
6462 : 78 : struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
6463 : :
6464 : 78 : INIT_LIST_HEAD(&ul->head);
6465 : 156 : spin_lock_init(&ul->lock);
6466 : : }
6467 : :
6468 : 78 : out:
6469 : 78 : return ret;
6470 : :
6471 : 0 : out_register_late_subsys:
6472 : 0 : rtnl_unregister_all(PF_INET6);
6473 : 0 : unregister_pernet_subsys(&ip6_route_net_late_ops);
6474 : 0 : fib6_rules_init:
6475 : 0 : fib6_rules_cleanup();
6476 : : xfrm6_init:
6477 : 0 : xfrm6_fini();
6478 : 0 : out_fib6_init:
6479 : 0 : fib6_gc_cleanup();
6480 : 0 : out_register_subsys:
6481 : 0 : unregister_pernet_subsys(&ip6_route_net_ops);
6482 : 0 : out_register_inetpeer:
6483 : 0 : unregister_pernet_subsys(&ipv6_inetpeer_ops);
6484 : 0 : out_dst_entries:
6485 : 0 : dst_entries_destroy(&ip6_dst_blackhole_ops);
6486 : 0 : out_kmem_cache:
6487 : 0 : kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
6488 : 0 : goto out;
6489 : : }
6490 : :
6491 : 0 : void ip6_route_cleanup(void)
6492 : : {
6493 : 0 : unregister_netdevice_notifier(&ip6_route_dev_notifier);
6494 : 0 : unregister_pernet_subsys(&ip6_route_net_late_ops);
6495 : 0 : fib6_rules_cleanup();
6496 : 0 : xfrm6_fini();
6497 : 0 : fib6_gc_cleanup();
6498 : 0 : unregister_pernet_subsys(&ipv6_inetpeer_ops);
6499 : 0 : unregister_pernet_subsys(&ip6_route_net_ops);
6500 : 0 : dst_entries_destroy(&ip6_dst_blackhole_ops);
6501 : 0 : kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
6502 : 0 : }
|