diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 66fc69ef5909..3975ae8e2440 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -2415,8 +2415,9 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, | |||
2415 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags); | 2415 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags); |
2416 | } | 2416 | } |
2417 | 2417 | ||
2418 | struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, | 2418 | struct dst_entry *ip6_route_output_flags_noref(struct net *net, |
2419 | struct flowi6 *fl6, int flags) | 2419 | const struct sock *sk, |
2420 | struct flowi6 *fl6, int flags) | ||
2420 | { | 2421 | { |
2421 | bool any_src; | 2422 | bool any_src; |
2422 | 2423 | ||
@@ -2424,6 +2425,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, | |||
2424 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) { | 2425 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) { |
2425 | struct dst_entry *dst; | 2426 | struct dst_entry *dst; |
2426 | 2427 | ||
2428 | /* This function does not take refcnt on the dst */ | ||
2427 | dst = l3mdev_link_scope_lookup(net, fl6); | 2429 | dst = l3mdev_link_scope_lookup(net, fl6); |
2428 | if (dst) | 2430 | if (dst) |
2429 | return dst; | 2431 | return dst; |
@@ -2431,6 +2433,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, | |||
2431 | 2433 | ||
2432 | fl6->flowi6_iif = LOOPBACK_IFINDEX; | 2434 | fl6->flowi6_iif = LOOPBACK_IFINDEX; |
2433 | 2435 | ||
2436 | flags |= RT6_LOOKUP_F_DST_NOREF; | ||
2434 | any_src = ipv6_addr_any(&fl6->saddr); | 2437 | any_src = ipv6_addr_any(&fl6->saddr); |
2435 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) || | 2438 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) || |
2436 | (fl6->flowi6_oif && any_src)) | 2439 | (fl6->flowi6_oif && any_src)) |
@@ -2443,6 +2446,28 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, | |||
2443 | 2446 | ||
2444 | return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output); | 2447 | return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output); |
2445 | } | 2448 | } |
2449 | EXPORT_SYMBOL_GPL(ip6_route_output_flags_noref); | ||
2450 | |||
2451 | struct dst_entry *ip6_route_output_flags(struct net *net, | ||
2452 | const struct sock *sk, | ||
2453 | struct flowi6 *fl6, | ||
2454 | int flags) | ||
2455 | { | ||
2456 | struct dst_entry *dst; | ||
2457 | struct rt6_info *rt6; | ||
2458 | |||
2459 | rcu_read_lock(); | ||
2460 | dst = ip6_route_output_flags_noref(net, sk, fl6, flags); | ||
2461 | rt6 = (struct rt6_info *)dst; | ||
2462 | /* For dst cached in uncached_list, refcnt is already taken. */ | ||
2463 | if (list_empty(&rt6->rt6i_uncached) && !dst_hold_safe(dst)) { | ||
2464 | dst = &net->ipv6.ip6_null_entry->dst; | ||
2465 | dst_hold(dst); | ||
2466 | } | ||
2467 | rcu_read_unlock(); | ||
2468 | |||
2469 | return dst; | ||
2470 | } | ||
2446 | EXPORT_SYMBOL_GPL(ip6_route_output_flags); | 2471 | EXPORT_SYMBOL_GPL(ip6_route_output_flags); |
2447 | 2472 | ||
2448 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) | 2473 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) |