Commit d64a1f57 authored by Wei Wang's avatar Wei Wang Committed by David S. Miller

ipv6: honor RT6_LOOKUP_F_DST_NOREF in rule lookup logic

This patch specifically converts the rule lookup logic to honor this
flag and not release refcnt when traversing each rule and calling
lookup() on each routing table.
Similar to previous patch, we also need some special handling of dst
entries in uncached list because there is always 1 refcnt taken for them
even if RT6_LOOKUP_F_DST_NOREF flag is set.
Signed-off-by: default avatarWei Wang <weiwan@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 74109218
...@@ -94,6 +94,16 @@ static inline struct dst_entry *ip6_route_output(struct net *net, ...@@ -94,6 +94,16 @@ static inline struct dst_entry *ip6_route_output(struct net *net,
return ip6_route_output_flags(net, sk, fl6, 0); return ip6_route_output_flags(net, sk, fl6, 0);
} }
/* Only conditionally release dst if flags indicates
* !RT6_LOOKUP_F_DST_NOREF or dst is in uncached_list.
*/
static inline void ip6_rt_put_flags(struct rt6_info *rt, int flags)
{
if (!(flags & RT6_LOOKUP_F_DST_NOREF) ||
!list_empty(&rt->rt6i_uncached))
ip6_rt_put(rt);
}
struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
const struct sk_buff *skb, int flags); const struct sk_buff *skb, int flags);
struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
......
...@@ -113,14 +113,15 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, ...@@ -113,14 +113,15 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
rt = lookup(net, net->ipv6.fib6_local_tbl, fl6, skb, flags); rt = lookup(net, net->ipv6.fib6_local_tbl, fl6, skb, flags);
if (rt != net->ipv6.ip6_null_entry && rt->dst.error != -EAGAIN) if (rt != net->ipv6.ip6_null_entry && rt->dst.error != -EAGAIN)
return &rt->dst; return &rt->dst;
ip6_rt_put(rt); ip6_rt_put_flags(rt, flags);
rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags); rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags);
if (rt->dst.error != -EAGAIN) if (rt->dst.error != -EAGAIN)
return &rt->dst; return &rt->dst;
ip6_rt_put(rt); ip6_rt_put_flags(rt, flags);
} }
dst_hold(&net->ipv6.ip6_null_entry->dst); if (!(flags & RT6_LOOKUP_F_DST_NOREF))
dst_hold(&net->ipv6.ip6_null_entry->dst);
return &net->ipv6.ip6_null_entry->dst; return &net->ipv6.ip6_null_entry->dst;
} }
...@@ -237,13 +238,14 @@ static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp, ...@@ -237,13 +238,14 @@ static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
goto out; goto out;
} }
again: again:
ip6_rt_put(rt); ip6_rt_put_flags(rt, flags);
err = -EAGAIN; err = -EAGAIN;
rt = NULL; rt = NULL;
goto out; goto out;
discard_pkt: discard_pkt:
dst_hold(&rt->dst); if (!(flags & RT6_LOOKUP_F_DST_NOREF))
dst_hold(&rt->dst);
out: out:
res->rt6 = rt; res->rt6 = rt;
return err; return err;
......
...@@ -316,9 +316,10 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, ...@@ -316,9 +316,10 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags); rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags);
if (rt->dst.error == -EAGAIN) { if (rt->dst.error == -EAGAIN) {
ip6_rt_put(rt); ip6_rt_put_flags(rt, flags);
rt = net->ipv6.ip6_null_entry; rt = net->ipv6.ip6_null_entry;
dst_hold(&rt->dst); if (!(flags | RT6_LOOKUP_F_DST_NOREF))
dst_hold(&rt->dst);
} }
return &rt->dst; return &rt->dst;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment