| From foo@baz Fri Jan 15 09:43:29 AM CET 2021 |
| From: Florian Westphal <fw@strlen.de> |
| Date: Wed, 6 Jan 2021 00:15:22 +0100 |
| Subject: net: fix pmtu check in nopmtudisc mode |
| |
| From: Florian Westphal <fw@strlen.de> |
| |
| [ Upstream commit 50c661670f6a3908c273503dfa206dfc7aa54c07 ] |
| |
| For some reason ip_tunnel insist on setting the DF bit anyway when the |
| inner header has the DF bit set, EVEN if the tunnel was configured with |
| 'nopmtudisc'. |
| |
| This means that the script added in the previous commit |
| cannot be made to work by adding the 'nopmtudisc' flag to the |
| ip tunnel configuration. Doing so breaks connectivity even for the |
| without-conntrack/netfilter scenario. |
| |
| When nopmtudisc is set, the tunnel will skip the mtu check, so no |
| icmp error is sent to client. Then, because inner header has DF set, |
| the outer header gets added with DF bit set as well. |
| |
| IP stack then sends an error to itself because the packet exceeds |
| the device MTU. |
| |
| Fixes: 23a3647bc4f93 ("ip_tunnels: Use skb-len to PMTU check.") |
| Cc: Stefano Brivio <sbrivio@redhat.com> |
| Signed-off-by: Florian Westphal <fw@strlen.de> |
| Acked-by: Pablo Neira Ayuso <pablo@netfilter.org> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/ip_tunnel.c | 10 +++++----- |
| 1 file changed, 5 insertions(+), 5 deletions(-) |
| |
| --- a/net/ipv4/ip_tunnel.c |
| +++ b/net/ipv4/ip_tunnel.c |
| @@ -743,7 +743,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, |
| goto tx_error; |
| } |
| |
| - if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph)) { |
| + df = tnl_params->frag_off; |
| + if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df) |
| + df |= (inner_iph->frag_off & htons(IP_DF)); |
| + |
| + if (tnl_update_pmtu(dev, skb, rt, df, inner_iph)) { |
| ip_rt_put(rt); |
| goto tx_error; |
| } |
| @@ -771,10 +775,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, |
| ttl = ip4_dst_hoplimit(&rt->dst); |
| } |
| |
| - df = tnl_params->frag_off; |
| - if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df) |
| - df |= (inner_iph->frag_off&htons(IP_DF)); |
| - |
| max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) |
| + rt->dst.header_len + ip_encap_hlen(&tunnel->encap); |
| if (max_headroom > dev->needed_headroom) |