mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-25 14:13:01 -04:00
ipv6: Fix dst_entry refcnt bugs in ip6_tunnel
Problems in the current dst_entry cache in the ip6_tunnel:
1. ip6_tnl_dst_set is racy. There is no lock to protect it:
- One major problem is that the dst refcnt gets messed up. F.e.
the same dst_cache can be released multiple times and then
triggering the infamous dst refcnt < 0 warning message.
- Another issue is the inconsistency between dst_cache and
dst_cookie.
It can be reproduced by adding and removing the ip6gre tunnel
while running a super_netperf TCP_CRR test.
2. ip6_tnl_dst_get does not take the dst refcnt before returning
the dst.
This patch:
1. Create a percpu dst_entry cache in ip6_tnl
2. Use a spinlock to protect the dst_cache operations
3. ip6_tnl_dst_get always takes the dst refcnt before returning
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f230d1e891
commit
cdf3464e6c
3 changed files with 123 additions and 48 deletions
|
|
@ -32,6 +32,12 @@ struct __ip6_tnl_parm {
|
|||
__be32 o_key;
|
||||
};
|
||||
|
||||
struct ip6_tnl_dst {
|
||||
spinlock_t lock;
|
||||
struct dst_entry *dst;
|
||||
u32 cookie;
|
||||
};
|
||||
|
||||
/* IPv6 tunnel */
|
||||
struct ip6_tnl {
|
||||
struct ip6_tnl __rcu *next; /* next tunnel in list */
|
||||
|
|
@ -39,8 +45,7 @@ struct ip6_tnl {
|
|||
struct net *net; /* netns for packet i/o */
|
||||
struct __ip6_tnl_parm parms; /* tunnel configuration parameters */
|
||||
struct flowi fl; /* flowi template for xmit */
|
||||
struct dst_entry *dst_cache; /* cached dst */
|
||||
u32 dst_cookie;
|
||||
struct ip6_tnl_dst __percpu *dst_cache; /* cached dst */
|
||||
|
||||
int err_count;
|
||||
unsigned long err_time;
|
||||
|
|
@ -61,6 +66,8 @@ struct ipv6_tlv_tnl_enc_lim {
|
|||
} __packed;
|
||||
|
||||
struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t);
|
||||
int ip6_tnl_dst_init(struct ip6_tnl *t);
|
||||
void ip6_tnl_dst_destroy(struct ip6_tnl *t);
|
||||
void ip6_tnl_dst_reset(struct ip6_tnl *t);
|
||||
void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst);
|
||||
int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
|
||||
|
|
|
|||
Loading…
Reference in a new issue