UDP checksum calculation with QUIC header

Hi, I’m trying to calculate UDP checksum with QUIC header using update_checksum_with_payload.
However, the checksum computed is incorrect.
Here is my declaration of relevant headers:

header udp_t {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<16> length_;
    bit<16> checksum;
}

header udpQuic_t {
    bit<1> hdr_type;
    bit<1> fixed;
    bit<2> pkt_type;
    bit<4> version;
}

header quicLong_t{
    bit<32> version;
    bit<8> dcid_length;
    bit<8> dcid_first_byte;
    bit<8> app_idx;
    bit<48> cookie;
    bit<8> scid_length;
    bit<64> src_cid;
}

header quicShort_t{
    bit<8> dcid_first_byte;
    bit<16> cookie;
    bit<40> dcid_residue;
}

and here is my checksum computation:

update_checksum_with_payload((hdr.udp.isValid() && !hdr.udpQuic.isValid()),
        { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                meta.l4Len,
                hdr.udp.srcPort,
                hdr.udp.dstPort,
                hdr.udp.length_,
                16w0
            },
            hdr.udp.checksum, HashAlgorithm.csum16);

update_checksum_with_payload(hdr.quicLong.isValid(),
            { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                meta.l4Len,
                hdr.udp.srcPort,
                hdr.udp.dstPort,
                hdr.udp.length_,
                16w0,
                hdr.udpQuic.hdr_type,
                hdr.udpQuic.fixed,
                hdr.udpQuic.pkt_type,
                hdr.udpQuic.version,
                hdr.quicLong.version,
                hdr.quicLong.dcid_length,
                hdr.quicLong.dcid_first_byte,
                hdr.quicLong.app_idx,
                hdr.quicLong.cookie,
                hdr.quicLong.scid_length,
                hdr.quicLong.src_cid
            },
            hdr.udp.checksum, HashAlgorithm.csum16);

        update_checksum_with_payload(hdr.quicShort.isValid(),
            { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                meta.l4Len,
                hdr.udp.srcPort,
                hdr.udp.dstPort,
                hdr.udp.length_,
                16w0,
                hdr.udpQuic.hdr_type,
                hdr.udpQuic.fixed,
                hdr.udpQuic.pkt_type,
                hdr.udpQuic.version,
                hdr.quicShort.dcid_first_byte,
                hdr.quicShort.cookie,
                hdr.quicShort.dcid_residue
            },
            hdr.udp.checksum, HashAlgorithm.csum16);
     }

Any advice would be appreciated.

I think that the problem might be in the udpQuic header, since it is only 8 bits long, but you insert 16 bits of padding in the front of it. Maybe you wanted to insert 8 bits instead?

Happy hacking,
Vladimir

Thanks for your reply. I insert 8w0 instead before hdr.udpQuic as you recommended but still, the checksum is not correct. In Wireshark, the error info is:

Checksum: 0xbe93 incorrect, should be 0x3312 (maybe caused by "UDP checksum offload"?)
Checksum: 0xabb4 incorrect, should be 0x53ff (maybe caused by "UDP checksum offload"?)
Checksum: 0xbfc5 incorrect, should be 0x6513 (maybe caused by "UDP checksum offload"?)
...

and I really have no idea about how to fix it :sob:
Now my checksum is like:

update_checksum_with_payload(hdr.quicLong.isValid(),
            { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                meta.l4Len,
                hdr.udp.srcPort,
                hdr.udp.dstPort,
                hdr.udp.length_,
                8w0,
                hdr.udpQuic.hdr_type,
                hdr.udpQuic.fixed,
                hdr.udpQuic.pkt_type,
                hdr.udpQuic.version,
                hdr.quicLong.version,
                hdr.quicLong.dcid_length,
                hdr.quicLong.dcid_first_byte,
                hdr.quicLong.app_idx,
                hdr.quicLong.cookie,
                hdr.quicLong.scid_length,
                hdr.quicLong.src_cid
            },
            hdr.udp.checksum, HashAlgorithm.csum16);

and same modification to quicShort checksum computation.

Is meta.l4Len equal to hdr.udp.length_ always? If I remember correctly, for UDP checksum they need to be.

In general, if anyone has a working v1model architecture example that uses an update_checksum_with_payload call for updating a full UDP header and payload, it would be useful if they could respond to this with a pointer to that code, if it is public. I have not used it before.

I concur with @andyfingerhut – make sure that hdr.udp.length_ and meta.l4Len have the same value. This is important, indeed.

If you want to debug the issue, the recommendation is to send packets with the key fields (i.e. the ones that participate in checksum calculation) consisting mostly of zeroes and then add fields here and there – this will help you to narrow down the problem pretty quickly. In this case, it would also help to make sure that the rest of the packet also consists of zeroes.

Tanks for your help. now my checksum works well!
Here is my current code:

update_checksum_with_payload(hdr.quicLong.isValid(),
            { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                hdr.udp.length_,
                hdr.udp.srcPort,
                hdr.udp.dstPort,
                hdr.udp.length_,
                16w0,
                hdr.udpQuic.hdr_type,
                hdr.udpQuic.fixed,
                hdr.udpQuic.pkt_type,
                hdr.udpQuic.version,
		        16w0,
                hdr.quicLong.version,
                hdr.quicLong.dcid_length,
                hdr.quicLong.dcid_first_byte,
                hdr.quicLong.app_idx,
                hdr.quicLong.cookie,
                hdr.quicLong.scid_length,
                hdr.quicLong.src_cid
            },
            hdr.udp.checksum, HashAlgorithm.csum16);

        update_checksum_with_payload(hdr.quicShort.isValid(),
            { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                hdr.udp.length_,
                hdr.udp.srcPort,
                hdr.udp.dstPort,
                hdr.udp.length_,
                16w0,
                hdr.udpQuic.hdr_type,
                hdr.udpQuic.fixed,
                hdr.udpQuic.pkt_type,
                hdr.udpQuic.version,
		        16w0,
                hdr.quicShort.dcid_first_byte,
                hdr.quicShort.cookie,
                hdr.quicShort.dcid_residue
            },
            hdr.udp.checksum, HashAlgorithm.csum16);

I tried several paddings and it works out of my expectation. But I just cannot explain it.

1 Like