summaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c29
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
2418struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, 2418struct 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}
2449EXPORT_SYMBOL_GPL(ip6_route_output_flags_noref);
2450
2451struct 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}
2446EXPORT_SYMBOL_GPL(ip6_route_output_flags); 2471EXPORT_SYMBOL_GPL(ip6_route_output_flags);
2447 2472
2448struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) 2473struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)