Other Parts Discussed in Thread: SK-AM62
Tool/software:
Hi experts,
my primary issue was a reproducable timeout when trying to downloading a large file using tftp from AM625 linux user space. Interestingly, this works via an IPv4 connection to the tftp server (my laptop computer), but now I'm trying to do it via an IPv6 link-local connection. Note that my setup uses UDP over IPv6.
When debugging with Wireshark running on the tftp server, I noticed that the download timed out at the time when the checksum of the UDP package sent from AM625 to my laptop, hit zero. (The UDP package contents were some ACK messages with package IDs counting up, hence the UDP checksum counted down from some initial value towards zero.) It seems, that my Laptop discarded the ACK response with UDP checksum 0, as mandated by RFC 2460, which describes UDP over IPv6:
o Unlike IPv4, when UDP packets are originated by an IPv6 node, the UDP checksum is not optional. That is, whenever originating a UDP packet, an IPv6 node must compute a UDP checksum over the packet and the pseudo-header, and, if that computation yields a result of zero, it must be changed to hex FFFF for placement in the UDP header. IPv6 receivers must discard UDP packets containing a zero checksum, and should log the error. [emphasis mine]
Temporarily I could solve the issue with
ethtool --offload eth0 tx offbefore the tftp download; but, if I understand correctly, this will burden the CPU with all Internet checksum calculations later on in production, for all TCP and UDP traffic.
To verify the issue, I wrote a small python script sending a small certain UDP package, adapted to result in an UDP checksum of zero (with some trial and error).
import socket from time import sleep from itertools import cycle ip6 = "fe80::443a:64c4:2cd8:fd26" dev = "eth0" addr = f"{ip6}%{dev}" port = 8648 family, type_, proto, canonname, sockaddr = socket.getaddrinfo( addr, port, family=socket.AF_INET6, type=socket.SOCK_DGRAM, proto=socket.IPPROTO_UDP, ).pop() sock_send = socket.socket(family=family, type=type_, proto=proto) sock_send.sendto(b"t0z-\r\n", sockaddr) # effects UDP_checksum == 0
Indeed, the Hardware offloading logic seems to handle the zero case incorrectly (it should substitute 0x0000 by 0xffff). Insead, the UDP package got send with UDP checksum zero, as indicated on the receiving side via Wireshark:
Question: Did we miss some configuration of the AM625 hardware, that changes the calculation of the IPv6-UDP-checksum in the special case (0 --> 0xffff)? Or is this a hardware bug, and we must resort to software-calculated UDP-checksums?
Thanks in advance and Best Regards,
Lukas Rauber