Commit b40c5f4f authored by Ansis Atteka's avatar Ansis Atteka Committed by David S. Miller

udp: disable inner UDP checksum offloads in IPsec case

Otherwise, UDP checksum offloads could corrupt ESP packets by attempting
to calculate UDP checksum when this inner UDP packet is already protected
by IPsec.

One way to reproduce this bug is to have a VM with virtio_net driver (UFO
set to ON in the guest VM); and then encapsulate all guest's Ethernet
frames in Geneve; and then further encrypt Geneve with IPsec.  In this
case following symptoms are observed:
1. If using ixgbe NIC, then it will complain with following error message:
   ixgbe 0000:01:00.1: partial checksum but l4 proto=32!
2. Receiving IPsec stack will drop all the corrupted ESP packets and
   increase XfrmInStateProtoError counter in /proc/net/xfrm_stat.
3. iperf UDP test from the VM with packet sizes above MTU will not work at
   all.
4. iperf TCP test from the VM will get ridiculously low performance because.
Signed-off-by: default avatarAnsis Atteka <aatteka@ovn.org>
Co-authored-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4d6fa57b
...@@ -29,6 +29,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, ...@@ -29,6 +29,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
u16 mac_len = skb->mac_len; u16 mac_len = skb->mac_len;
int udp_offset, outer_hlen; int udp_offset, outer_hlen;
__wsum partial; __wsum partial;
bool need_ipsec;
if (unlikely(!pskb_may_pull(skb, tnl_hlen))) if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
goto out; goto out;
...@@ -62,8 +63,10 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, ...@@ -62,8 +63,10 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
need_ipsec = skb_dst(skb) && dst_xfrm(skb_dst(skb));
/* Try to offload checksum if possible */ /* Try to offload checksum if possible */
offload_csum = !!(need_csum && offload_csum = !!(need_csum &&
!need_ipsec &&
(skb->dev->features & (skb->dev->features &
(is_ipv6 ? (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM) : (is_ipv6 ? (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM) :
(NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)))); (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM))));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment