From: "Benoît Monin" <benoit.monin@gmx.fr>
To: "David S. Miller" <davem@davemloft.net>,
David Ahern <dsahern@kernel.org>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: PROBLEM: invalid udp checksum with ip6gre-in-udp
Date: Thu, 12 Sep 2024 16:04:51 +0200 [thread overview]
Message-ID: <2147205.9o76ZdvQCi@benoit.monin> (raw)
In-Reply-To: <26548921.1r3eYUQgxm@benoit.monin>
Hi again,
05/09/2024 Benoît Monin :
> Hi all,
>
> I am having issue with GRE-in-UDP (GRE with fou encapsulation) over
> IPv6: the outer UDP checksum is only valid if an inner checksum is
> present and valid. This problem is only present over IPv6, not IPv4,
> and reproducible with different kernel versions and cpu architecture.
>
> Here is the test setup I used:
>
> +----------+ +------------+
> | | fd00::2/64 fd00::1/64 | |
> | tester | 10.0.0.33/24 10.0.0.11/24 | DUT |
> | |------------------------------------| |
> +----------+ +------------+
>
> Two machines are connected with an ethernet cable, and each side is
> setup with an ipv4 and an ipv6 address.
>
> On the device under test, two GRE-in-UDP tunnels are setup, one over
> ipv6 and one over ipv4, aimed at the tester. Each tunnel is configured
> with an ipv4 address:
>
> modprobe -a fou fou6
>
> ip link add gre6 type ip6gre local fd00::1 remote fd00::2 encap fou encap-sport 1234 encap-dport 4567
> ip link set up gre6
> ip address add 172.20.6.1/24 dev gre6
>
> ip link add gre4 type gre local 10.0.0.11 remote 10.0.0.33 encap fou encap-sport 3456 encap-dport 6789 encap-csum
> ip link set up gre4
> ip address add 172.20.4.1/24 dev gre4
>
> On the tester, no setup is done, it is only running tcpdump to capture
> the traffic emitted by the DUT.
>
> The following commands are used on the device under test to send
> packets via the tunnels:
>
> ping -c1 -W0.1 172.20.6.2
> ./send_udp 172.20.6.2 5555 "ip6gre-in-udp with inner udp csum"
> SO_NO_CHECK=1 ./send_udp 172.20.6.2 5555 "ip6gre-in-udp without inner udp csum"
> ping -c1 -W0.1 172.20.4.2
> ./send_udp 172.20.4.2 5555 "gre-in-udp with inner udp csum"
> SO_NO_CHECK=1 ./send_udp 172.20.4.2 5555 "gre-in-udp without inner udp csum"
>
> Three packets are sent in each GRE tunnels :
> * One ICMP echo request
> * One UDP packet with a valid checksum
> * One UDP packet with the checksum set to 0
>
> Here is a link to the pcap containing the six packets generated by the
> previous commands:
> https://onaip.mooo.com/pub/tmp/bug_ip6gre-in-udp.pcap
>
> Some details about the captured packets:
> IP6 fd00::1 > fd00::2: 1234 > 4567: [bad udp cksum 0xfa75 -> 0xe680!]
> IP6 fd00::1 > fd00::2: 1234 > 4567: [udp sum ok]
> IP6 fd00::1 > fd00::2: 1234 > 4567: [bad udp cksum 0xfa62 -> 0xb57c!]
> IP 10.0.0.11.3456 > 10.0.0.33.6789: [udp sum ok]
> IP 10.0.0.11.3456 > 10.0.0.33.6789: [udp sum ok]
> IP 10.0.0.11.3456 > 10.0.0.33.6789: [udp sum ok]
>
> For the tunnel over ipv6, only the UDP packet sent with a valid
> checksum get encapsulated with a valid checksum. For the ping and the
> UDP packet with a zero checksum, the outer UDP checksum matches the
> partial checksum of the pseudo-header.
>
> For ipv4, the UDP checksum of the encapsulation are all valid.
>
> The device under test used for the capture is an x86-64 machine with a
> realtek ethernet adapter (r8169 driver) running a 6.10.7 kernel.
>
> The problem was also seen on an arm64 board (freescale ls1046) with
> dpaa ethernet driver running a 4.14 kernel. on this hardware, the
> packets that would have an invalid checksum are not emitted and the tx
> error counter of the ethernet interface increases.
>
> In all cases, disabling hardware checksumming for ipv6 with ethtool can
> be used as a work-around:
>
> ethtool -K eth0 tx-checksum-ipv6 off
>
> This and the partial checksum value seems to point to an error in the
> handling of hardware checksumming in the particular case of fou6
> encapsulation, but I have not been able to figure out what could be
> causing it.
>
> Did I miss a configuration parameter for ip6gre-in-udp? Any advise on
> how to debug that would be appreciated.
>
I did some more digging with 6.11-rc7, and it is not a problem in the
common code or udp encapsulation, I just got "lucky" with my tests...
First in fou6.c, fou6_build_udp constructs the upd header and calls
udp6_set_csum. If the inner packet has a valid checksum, the outer udp
get computed by reusing it, otherwise the partial checksum is set.
Next the outer ipv6 is built in ip6tunnel.c:ip6_tnl_xmit. With the
default value of encaplimit (4), an destination options header is
inserted to pass that value. This means that ipv6_hdr(skb)->nexthdr is
set to 60 (NEXTHDR_DEST), not 17 (IPPROTO_UDP).
So when sending a packet without a valid checksum in a ip6gre-in-udp,
we pass a skb with a partial udp checksum and an ipv6 header with an
extension to ndo_start_xmit.
Finally, what are the odds of testing two different hardware and
finding two similar bugs?
For the LS1046 platform, the Tx checksum is done in
dpaa_enable_tx_csum. For ipv6, the layer 4 protocol is extracted from
the skb with l4_proto = ipv6h->nexthdr. Since the value does not match
IPPROTO_UDP nor IPPROTO_TCP, the function errors out and the packet is
discarded.
For the PC with a realtek 8169 card, the code is similar in
rtl8169_tso_csum_v2, with ip_protocol = ipv6_hdr(skb)->nexthdr. The
error case then triggers a WARN_ON_ONCE(1) and the packet is still sent
on the wire with a partial udp checksum.
There seems to be quite a few places in drivers/net/ethernet that use
ipv6_hdr(skb)->nexthdr as the IP protocol, with only some of them
calling ipv6_skip_exthdr afterward to take care of the extension
headers. So my proposal is to add a small helper (ipv6_protocol?) and
fix the drivers where needed.
I'll try to come up with a patch set, unless someone has a better idea.
--
Benoît
next prev parent reply other threads:[~2024-09-12 14:05 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-05 15:22 PROBLEM: invalid udp checksum with ip6gre-in-udp Benoît Monin
2024-09-12 14:04 ` Benoît Monin [this message]
2024-09-20 12:10 ` Benoît Monin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2147205.9o76ZdvQCi@benoit.monin \
--to=benoit.monin@gmx.fr \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.