On Sat, Jun 21, 2025 at 06:46:00AM -0700, Jakub Kicinski wrote:
On Fri, 20 Jun 2025 12:53:23 +0200 Oleksij Rempel wrote:
quoted
quoted
What device are you talking about? How is this a problem with
the selftest and not with the stack? If the test is flaky I'd
think real traffic will suffer too. We pass these selftest packets
thru xmit validation AFAICT, so the stack should compute checksum
for the if the device can't.
Let me first describe the setup where this issue was observed and my findings.
The problem occurs on a system utilizing a Microchip DSA driver with an STMMAC
Ethernet controller attached to the CPU port.
In the current selftest implementation, the TCP checksum validation fails,
while the UDP test passes. The existing code prepares the skb for hardware
checksum offload by setting skb->ip_summed = CHECKSUM_PARTIAL. For TCP, it sets
the thdr->check field to the complement of the pseudo-header checksum, and for
UDP, it uses udp4_hwcsum. If I understand it correct, this configuration tells
the kernel that the hardware should perform the checksum calculation.
However, during testing, I noticed that "rx-checksumming" is enabled by default
on the CPU port, and this leads to the TCP test failure. Only after disabling
"rx-checksumming" on the CPU port did the selftest pass. This suggests that the
issue is specifically related to the hardware checksum offload mechanism in
this particular setup. The behavior indicates that something on the path
recalculated the checksum incorrectly.
Interesting, that sounds like the smoking gun. When rx-checksumming
is enabled the packet still reaches the stack right?
No. It looks like this packets are just silently dropped, before they was
seen by the stack. The only counter which confirms presence of this
frames is HW specific mmc_rx_tcp_err. But it will be increasing even if
rx-checksumming is disabled and packets are forwarded to the stack.
If so does the frame enter the stack with CHECKSUM_COMPLETE or
UNNECESSARY?
If rx-checksumming is enabled and packet has supported ethertype,
then CHECKSUM_UNNECESSARY will be set. Otherwise CHECKSUM_NONE.
quoted
When examining the loopbacked frames, I observed that the TCP checksum was
incorrect. Upon further investigation, the xmit helper in net/dsa/tag_ksz.c
includes the following:
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
return NULL;
I assume skb_checksum_help() is intended to calculate the proper checksum when
CHECKSUM_PARTIAL is set, indicating that the software should complete the
checksum before handing it to the hardware. My understanding is that the STMMAC
hardware then calculates the checksum for egress frames if CHECKSUM_PARTIAL is
used.
stmmac shouldn't touch the frame, note that skb_checksum_help() sets
skb->ip_summed = CHECKSUM_NONE; so the skb should no longer be considered
for csum offload.
It looks like skb_checksum_help(), which is used in tag_ksz.c, generates
a TCP checksum without accounting for the IP pseudo-header. The
resulting checksum is then incorrect and is filtered out by the STMMAC
HW on ingress
If I generate the checksum manually by combining the result of
skb_checksum() with the csum_tcpudp_magic() function - I get a different
checksum from the skb_checksum_help() result, which is then not dropped
by STMMAC on ingress.
Should tag_ksz.c use a different helper function instead of
skb_checksum_help()?
Best Regards,
Oleksij
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |