Message ID | 1465391614-8961-1-git-send-email-jkbs@redhat.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: Jakub Sitnicki <jkbs@redhat.com> Date: Wed, 8 Jun 2016 15:13:34 +0200 > At present we perform an xfrm_lookup() for each UDPv6 message we > send. The lookup involves querying the flow cache (flow_cache_lookup) > and, in case of a cache miss, creating an XFRM bundle. > > If we miss the flow cache, we can end up creating a new bundle and > deriving the path MTU (xfrm_init_pmtu) from on an already transformed > dst_entry, which we pass from the socket cache (sk->sk_dst_cache) down > to xfrm_lookup(). This can happen only if we're caching the dst_entry > in the socket, that is when we're using a connected UDP socket. > > To put it another way, the path MTU shrinks each time we miss the flow > cache, which later on leads to incorrectly fragmented payload. It can > be observed with ESPv6 in transport mode: ... > To prevent the recreation of an XFRM bundle, avoid an XFRM lookup > altogether whenever we already have a destination entry cached in the > socket. This prevents the path MTU shrinkage and brings us on par with > UDPv4. > > The fix also benefits connected PINGv6 sockets, another user of > ip6_sk_dst_lookup_flow(), who also suffer messages being transformed > twice. > > Joint work with Hannes Frederic Sowa. > > Reported-by: Jan Tluka <jtluka@redhat.com> > Signed-off-by: Jakub Sitnicki <jkbs@redhat.com> > Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Applied and queued up for -stable, thanks.
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 6b2f60a..fd32175 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1071,17 +1071,12 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst) { struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); - int err; dst = ip6_sk_dst_check(sk, dst, fl6); + if (!dst) + dst = ip6_dst_lookup_flow(sk, fl6, final_dst); - err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6); - if (err) - return ERR_PTR(err); - if (final_dst) - fl6->daddr = *final_dst; - - return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); + return dst; } EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);