Closed sarashakeri closed 4 years ago
First, the UDP checksum is defined in this RFC: https://tools.ietf.org/html/rfc768 UDP uses the same checksum at TCP.
Pseudo code for the checksum algorithm can be leveraged from the PSA specification.
https://p4.org/p4-spec/docs/PSA.html#appendix-internetchecksum-implementation
Thanks for your reply. What I was looking for, is the already tested example of calculating TCP checksum especially in the V1model ( like what there is for IP header), but it seems there is not a complete and available code for that, right? So, I have to write the code?
I poked around (not hard enough) the p4lang/behavioral-model repo for simple_switch and do not see a checksum computation. Also, since you are looking for a checksum computation, this issue does not belong to p4c, a compiler. You should file an issue with p4lang/behavioral-model,
What the PSA specification has for checksum computation is correct and the code can be used.
In general you don't compute the checksum, you incrementally update it, which should be much easier.
The update_checksum is a simple API you can apply for updating layer-4 checksum.
https://github.com/p4lang/p4c/blob/master/p4include/v1model.p4#L465
There are several example uses in p4c/testdata/p4_16_sample/*.p4
for update_checksum. Even though, the example use IPv4 header, you can replace such data with layer-4 data.
I tried to add something like there is for IPv4 checksum update for TCP header as below, however, it is not working. Any idea about the reason?
` //Calculating tcp length
state parse_ipv4 {
packet.extract(hd.ipv4);
verify(hd.ipv4.version == 4w4, error.IPv4IncorrectVersion);
verify(hd.ipv4.ihl == 4w5, error.IPv4OptionsNotSupported);
meta.tcpLength = hd.ipv4.total_len - 20;
transition accept;
}
//Updating checksum
control my_compute_checksum(inout headers_t hdr,
inout metadata_t meta)
{
apply {
update_checksum(
hdr.ipv4.isValid(),
{ hdr.ipv4.version,
hdr.ipv4.ihl,
hdr.ipv4.diffserv,
hdr.ipv4.total_len,
hdr.ipv4.identification,
hdr.ipv4.flags,
hdr.ipv4.frag_offset,
hdr.ipv4.ttl,
hdr.ipv4.protocol,
hdr.ipv4.src_addr,
hdr.ipv4.dst_addr },
hdr.ipv4.hdr_checksum,
HashAlgorithm.csum16);
update_checksum(
hdr.tcp.isValid(),
{ hdr.ipv4.src_addr,
hdr.ipv4.dst_addr,
8w0,
meta.tcpLength,
hdr.ipv4.protocol,
hdr.tcp.src,
hdr.tcp.dst,
hdr.tcp.seq,
hdr.tcp.ack,
hdr.tcp.offset,
hdr.tcp.resrv,
hdr.tcp.ecn,
hdr.tcp.ctrl,
hdr.tcp.window,
hdr.tcp.urgent,
},
hdr.tcp.checksum,
HashAlgorithm.csum16);
}
}`
I also found the PSA code for incremental checksum update but I have no idea how to write it for v1model.
The code you have shown will calculate a checksum based upon the explicitly listed fields you show in the arguments to the call, but does not include the TCP payload data, which by the TCP RFC should be included for a correct TCP checksum.
It might be that replacing your second update_checksum
call with update_checksum_with_payload
instead will calculate a correct TCP checksum. I have not verified that myself.
@jafingerhut, Thanks for your reply. I changed it to "update_checksum_with_payload", it changed the checksum comparing to when I use "update_checksum", but still the checksum is marked ad unverified (in Wireshark).
If Wireshark says "unverified" most likely that is because you have not enabled Wireshark to ever check TCP checksums, i.e. "unverified" means "it might be correct, or it might be incorrect. I (Wireshark) have been configured not to check it."
I do not know if the GUI has changed much between different versions of Wireshark, but at least with version 2.6.10 installed on a Linux system of mine, I can change it using these steps in the GUI:
There are similar options for UDP checksums and IPv4 checksums, which you must find those protocols in the long list of protocols, and click on them, to reveal the check boxes to enable/disable those options.
Thanks for the reply. I enabled Wireshark to check TCP checksum, and now it says "Checksum: 0x3509 incorrect, should be 0x3609(maybe caused by "TCP checksum offload"?)", the thing is that just the second 4 bit of the checksum is incorrect in all packets. Any idea about it?
Checksum: 0x3118 incorrect, should be 0x3218(maybe caused by "TCP checksum offload"?)
Checksum: 0x2938 incorrect, should be 0x2a38(maybe caused by "TCP checksum offload"?)
Checksum: 0x18b8 incorrect, should be 0x19b8(maybe caused by "TCP checksum offload"?)
and about the offloading, the TCP checksum offloading is off in my system, so I think that is not the reason.
I would recommend that you very carefully check the order of fields that you provided to the update_checksum_verify_payload
call against what is in RFC 793.
After hdr.tcp.window
, there is a missing hdr.checksum
which is a zeroed out value. This is the statement from RFC 793:
While computing the checksum, the checksum field itself is replaced with zeros.
That isn't the problem, I am nearly certain. Including or leaving out a 16-bit aligned 16-bit word of 0s should have absolutely no effect on the checksum value calculated.
And I should add that this entire conversation isn't really an issue with the p4c compiler, so would be better if it took place elsewhere, e.g. the p4-dev email list http://lists.p4.org/mailman/listinfo/p4-dev_lists.p4.org
or the P4 Slack channels, which you can join by going to https://p4.org then click on Community near the top right, and in the menu that appears select "Slack".
I checked everything and still no success. Sure, I'll ask my question somewhere more related. Thanks for all your help.
@sarashakeri Then, please close this issue.
Hi, Not sure if this problem is solved. But here is how I got it working. Yes the order of the ipv4 contents is important,if this order changes then csum will differ.
Corrected solution: update_checksum_with_payload( hdr.tcp.isValid(), { hdr.ipv4.src_addr, hdr.ipv4.dst_addr, 8w0, hdr.ipv4.protocol, meta.tcpLength, hdr.tcp.src, hdr.tcp.dst, hdr.tcp.seq, hdr.tcp.ack, hdr.tcp.offset, hdr.tcp.resrv, hdr.tcp.ecn, hdr.tcp.ctrl, hdr.tcp.window, hdr.tcp.urgent, }, hdr.tcp.checksum, HashAlgorithm.csum16);
Hence it was not working for you above and you need to include the payload as well.
-sandesh
Hi,
I am using a P4 switch for implementing nat between two network namespaces and as I am changing the IP addresses I want to calculate l3 and l4 checksum. There is no problem with calculating l3, however, I did not find any example of calculating l4 checksum. Currently, I am using the v1model, but don't have any limitation for the p4 switch model. Is there any way to implement tcp or udp checksum in P4 switch?