Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f858c56 authored by Alexey Kodanev's avatar Alexey Kodanev Committed by David S. Miller
Browse files

ipv6: udp: set dst cache for a connected sk if current not valid



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 33c162a9 ("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: 33c162a9 ("ipv6: datagram: Update dst cache of a connected datagram sk during pmtu update")
Fixes: 45e4fd26 ("ipv6: Only create RTF_CACHE routes after encountering pmtu exception")
Signed-off-by: default avatarAlexey Kodanev <alexey.kodanev@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9f542f61
Loading
Loading
Loading
Loading
+2 −19
Original line number Diff line number Diff line
@@ -1308,7 +1308,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)

	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 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
		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 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
		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);