ipv6: udp: set dst cache for a connected sk if current not valid
authorAlexey Kodanev <alexey.kodanev@oracle.com>
Tue, 3 Apr 2018 12:00:10 +0000 (15:00 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Apr 2018 15:31:57 +0000 (11:31 -0400)
A new RTF_CACHE route can be created between ip6_sk_dst_lookup_flow()
and ip6_dst_store() calls in udpv6_sendmsg(), when datagram sending
results to ICMPV6_PKT_TOOBIG error:

    udp_v6_send_skb(), for example with vti6 tunnel:
        vti6_xmit(), get ICMPV6_PKT_TOOBIG error
            skb_dst_update_pmtu(), can create a RTF_CACHE clone
            icmpv6_send()
    ...
    udpv6_err()
        ip6_sk_update_pmtu()
           ip6_update_pmtu(), can create a RTF_CACHE clone
           ...
           ip6_datagram_dst_update()
                ip6_dst_store()

And after commit 33c162a980fe ("ipv6: datagram: Update dst cache of
a connected datagram sk during pmtu update"), the UDPv6 error handler
can update socket's dst cache, but it can happen before the update in
the end of udpv6_sendmsg(), preventing getting the new dst cache on
the next udpv6_sendmsg() calls.

In order to fix it, save dst in a connected socket only if the current
socket's dst cache is invalid.

The previous patch prepared ip6_sk_dst_lookup_flow() to do that with
the new argument, and this patch enables it in udpv6_sendmsg().

Fixes: 33c162a980fe ("ipv6: datagram: Update dst cache of a connected datagram sk during pmtu update")
Fixes: 45e4fd26683c ("ipv6: Only create RTF_CACHE routes after encountering pmtu exception")
Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/udp.c

index 94861abbea60b68adede67f9fd02b3485175af2f..4ec76a87aeb869050022d71c8095d840526cef70 100644 (file)
@@ -1308,7 +1308,7 @@ do_udp_sendmsg:
 
        fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
 
-       dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, false);
+       dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, connected);
        if (IS_ERR(dst)) {
                err = PTR_ERR(dst);
                dst = NULL;
@@ -1333,7 +1333,7 @@ back_from_confirm:
                err = PTR_ERR(skb);
                if (!IS_ERR_OR_NULL(skb))
                        err = udp_v6_send_skb(skb, &fl6);
-               goto release_dst;
+               goto out;
        }
 
        lock_sock(sk);
@@ -1367,23 +1367,6 @@ do_append_data:
                err = np->recverr ? net_xmit_errno(err) : 0;
        release_sock(sk);
 
-release_dst:
-       if (dst) {
-               if (connected) {
-                       ip6_dst_store(sk, dst,
-                                     ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ?
-                                     &sk->sk_v6_daddr : NULL,
-#ifdef CONFIG_IPV6_SUBTREES
-                                     ipv6_addr_equal(&fl6.saddr, &np->saddr) ?
-                                     &np->saddr :
-#endif
-                                     NULL);
-               } else {
-                       dst_release(dst);
-               }
-               dst = NULL;
-       }
-
 out:
        dst_release(dst);
        fl6_sock_release(flowlabel);