diff options
author | David Ahern <dsahern@gmail.com> | 2018-04-20 15:38:02 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-21 16:06:14 -0400 |
commit | a68886a691804d3f6d479ebf6825480fbafb6a00 (patch) | |
tree | 2240cab921badf927268bcd687b8b2743179e86c /include/net/ip6_fib.h | |
parent | 5bcaa41b964ba2cda6dde64a126bfb7da1bd88f8 (diff) | |
download | linux-a68886a691804d3f6d479ebf6825480fbafb6a00.tar.bz2 |
net/ipv6: Make from in rt6_info rcu protected
When a dst entry is created from a fib entry, the 'from' in rt6_info
is set to the fib entry. The 'from' reference is used most notably for
cookie checking - making sure stale dst entries are updated if the
fib entry is changed.
When a fib entry is deleted, the pcpu routes on it are walked releasing
the fib6_info reference. This is needed for the fib6_info cleanup to
happen and to make sure all device references are released in a timely
manner.
There is a race window when a FIB entry is deleted and the 'from' on the
pcpu route is dropped and the pcpu route hits a cookie check. Handle
this race using rcu on from.
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/ip6_fib.h')
-rw-r--r-- | include/net/ip6_fib.h | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index dc3505fb62b3..1af450d4e923 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -174,7 +174,7 @@ struct fib6_info { struct rt6_info { struct dst_entry dst; - struct fib6_info *from; + struct fib6_info __rcu *from; struct rt6key rt6i_dst; struct rt6key rt6i_src; @@ -248,13 +248,15 @@ static inline bool fib6_get_cookie_safe(const struct fib6_info *f6i, static inline u32 rt6_get_cookie(const struct rt6_info *rt) { + struct fib6_info *from; u32 cookie = 0; rcu_read_lock(); - if (rt->rt6i_flags & RTF_PCPU || - (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from)) - fib6_get_cookie_safe(rt->from, &cookie); + from = rcu_dereference(rt->from); + if (from && (rt->rt6i_flags & RTF_PCPU || + unlikely(!list_empty(&rt->rt6i_uncached)))) + fib6_get_cookie_safe(from, &cookie); rcu_read_unlock(); |