diff options
author | Martin KaFai Lau <kafai@fb.com> | 2016-04-11 18:29:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-14 16:29:53 -0400 |
commit | e646b657f6983017783914a951039e323120dc55 (patch) | |
tree | 4e761d6859d0784b6e24fb1f30cc85467053eba2 /net | |
parent | 33c162a980fe03498fcecb917f618ad7e7c55e61 (diff) |
ipv6: udp: Do a route lookup and update during release_cb
This patch adds a release_cb for UDPv6. It does a route lookup
and updates sk->sk_dst_cache if it is needed. It picks up the
left-over job from ip6_sk_update_pmtu() if the sk was owned
by user during the pmtu update.
It takes a rcu_read_lock to protect the __sk_dst_get() operations
because another thread may do ip6_dst_store() without taking the
sk lock (e.g. sendmsg).
Fixes: 45e4fd26683c ("ipv6: Only create RTF_CACHE routes after encountering pmtu exception")
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Reported-by: Wei Wang <weiwan@google.com>
Cc: Cong Wang <xiyou.wangcong@gmail.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Wei Wang <weiwan@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/datagram.c | 20 | ||||
-rw-r--r-- | net/ipv6/udp.c | 1 |
2 files changed, 21 insertions, 0 deletions
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 59e01f27db9f..9dd3882fe6bf 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -119,6 +119,26 @@ out: | |||
119 | return err; | 119 | return err; |
120 | } | 120 | } |
121 | 121 | ||
122 | void ip6_datagram_release_cb(struct sock *sk) | ||
123 | { | ||
124 | struct dst_entry *dst; | ||
125 | |||
126 | if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) | ||
127 | return; | ||
128 | |||
129 | rcu_read_lock(); | ||
130 | dst = __sk_dst_get(sk); | ||
131 | if (!dst || !dst->obsolete || | ||
132 | dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) { | ||
133 | rcu_read_unlock(); | ||
134 | return; | ||
135 | } | ||
136 | rcu_read_unlock(); | ||
137 | |||
138 | ip6_datagram_dst_update(sk, false); | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(ip6_datagram_release_cb); | ||
141 | |||
122 | static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 142 | static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
123 | { | 143 | { |
124 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 144 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8125931106be..6bc5c664fa46 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -1539,6 +1539,7 @@ struct proto udpv6_prot = { | |||
1539 | .sendmsg = udpv6_sendmsg, | 1539 | .sendmsg = udpv6_sendmsg, |
1540 | .recvmsg = udpv6_recvmsg, | 1540 | .recvmsg = udpv6_recvmsg, |
1541 | .backlog_rcv = __udpv6_queue_rcv_skb, | 1541 | .backlog_rcv = __udpv6_queue_rcv_skb, |
1542 | .release_cb = ip6_datagram_release_cb, | ||
1542 | .hash = udp_lib_hash, | 1543 | .hash = udp_lib_hash, |
1543 | .unhash = udp_lib_unhash, | 1544 | .unhash = udp_lib_unhash, |
1544 | .rehash = udp_v6_rehash, | 1545 | .rehash = udp_v6_rehash, |