Implementing Checksum for IPv4 Headers with Options in P4 without Extern functions

Hello Sandeep,

The Internet checksum algorithm is well-defined (RFC 1071 → RFC1141 → RFC1624). In short, you need to do the following:

  • Split the required data into 16-bit chunks C1, C2, …., Cn.
  • Compute the sum of these chunks using 1-complement arithmetic.

The splitting can be accomplished relatively easily as long as you The Internet checksum algorithm is well-defined (RFC 1071 → RFC1141 → RFC1624). In short, you need to do the following:
Split the required data into 16-bit chunks C1, C2, …., Cn.
Compute the sum of these chunks using 1-complement arithmetic.

The splitting can be accomplished relatively easily as long as you do not use varbit to represent IPv4 options but use individual headers instead. For example, if you use these definitions for IPv4 header and option words:

header ipv4_h {
    bit<4>       version;
    bit<4>       ihl;
    bit<8>       diffserv;
    bit<16>      total_len;
    bit<16>      identification;
    bit<3>       flags;
    bit<13>      frag_offset;
    bit<8>       ttl;
    ip_proto_t   protocol;
    bit<16>      hdr_checksum;
    ipv4_addr_t  src_addr;
    ipv4_addr_t  dst_addr;
}
 
header ipv4_option_word_h {
    bit<32>      data;
}
 
struct headers_h {
    . . .
    ipv4_h                  ipv4;
    ipv4_option_word_h[10]  ipv4_options;
}

then your chunks can be defined as follows:

bit<16> c1  = h.ipv4.version ++ h.ipv.ihl ++ h.ipv4.diffserv;
bit<16> c2  = h.ipv4.total_len;
bit<16> c3  = h.ipv4.identification;
bit<16> c4  = h.ipv4.flags ++ h.ipv4_frag_offset;
bit<16> c5  = h.ipv4.ttl ++ h.ipv4.protocol;
bit<16> c6  = h.ipv4.hdr_checksum;
bit<16> c7  = h.ipv4.src_addr[31:16];
bit<16> c8  = h.ipv4.src_addr[15:0];
bit<16> c9  = h.ipv4.src_addr[31:16];
bit<16> c10 = h.ipv4.src_addr[15:0];
bit<16> c11 = h.ipv4_options[0].data[31:16];
bit<16> c12 = h.ipv4_options[0].data[15:0];
. . .
bit<16> c29 = h.ipv4_options[9].data[31:16];
bit<16> c30 = h.ipv4_options[9].data[15:0];

Obviously, you need to take care of header validity by predicating those assignments accordingly and writing 0 into these chunks in case the corresponding header is not valid. I assume you know how to do that.

After that, the algorithm is pretty easy, and follows the way 1-complement arithmetic is supposed to be done using the standard 2-complement one. Specifically, you need to compute the sum and add the carry back:

bit<32> sum = (bit<32>)c1 + (bit<32>)c2 + ... + (bit<32>)c30;
bit<16> internet_checksum = sum[15:0] + sum[31:16];

If you are trying to verify IPv4 checksum, you need to add together all the chunks and the result has to be equal to 0x0000 or 0xFFFF. If you are trying to recompute the IPv4 checksum, you need to add together all the chunks except c6, invert the value and then write it into h.ipv4.hdr_checksum.

Unfortunately, I am not familiar with your specific target, so this general algorithm might need to be coded in a way that works for it. For example, it is highly likely that you might need to split the expression to compute the sum into many individual additions in a tree-like fashion. I hope, you do know how to do that as well. It might also be better to declare c1c30 as bit<32> and perform the casts when they are initialized, etc. etc., but the algorithm itself is simple and requires no loops.

Looking at your code, I can see that you are using varbit to represent IPv4 options. This is a problem, because as of today, P4_16 does not allow you to extract data from varbit types and copy it, say, into bit<16> (or other types). This is the first issue that needs to be fixed if you want to be able to compute the checksum for an IPv4 packet with IPv4 options while staying within the core language.

There might be other problems – I can’t tell since you the code you attached does not include anything that would show how exactly have you tried to compute the checksum.

Last, but not least, I wonder why are you trying to compute the checksum without the extern? It is quite expensive to do it without it. Is this just some sort of a school assignment?

Happy hacking,
Vladimir