# Checksum calculation when adding payload to syn packet

**URL:** <https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96>\
**Category:** Getting Started with P4\
**Created:** [August 4, 2021, 10:21am UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96 "2021-08-04T10:21:37Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sarahshakeri](https://avatars.discourse-cdn.com/v4/letter/s/e495f1/32.png) [@sarahshakeri](https://forum.p4.org/u/sarahshakeri)\
**Post date:** [August 4, 2021, 10:21am UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96/1 "2021-08-04T10:21:37Z")

</div>

Hello, In my P4 code I am adding some information to the Syn packet of every TCP connection. It works and I receive the packets with added information. However, the checksum is incorrect.

I know by adding new information (to the payload) of the TCP Syn packet, IP TotalLength and TCP length should be updated for recalculating the checksum. However, still my code does not work! Here is the code:

```auto
header ethernet_t {
    macAddr_t dstAddr;
    macAddr_t srcAddr;
    bit<16> etherType;
}

header ipv4_t {
    bit<4> version;
    bit<4> ihl;
    bit<8> diffserv;
    bit<16> totalLen;
    bit<16> identification;
    bit<3> flags;
    bit<13> fragOffset;
    bit<8> ttl;
    bit<8> protocol;
    bit<16> hdrChecksum;
    ip4Addr_t srcAddr;
    ip4Addr_t dstAddr;
    varbit<320> options;
}
header tcp_t {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<32> seqNo;
    bit<32> ackNo;
    bit<4> dataOffset;
    bit<4> res;
    bit<1> cwr;
    bit<1> ecn;
    bit<1> urg;
    bit<1> ack;
    bit<1> psh;
    bit<1> rst;
    bit<1> syn;
    bit<1> fin;
    bit<16> window;
    bit<16> checksum; // Includes Pseudo Hdr + TCP segment (hdr + payload)
    bit<16> urgentPtr;
    varbit<320> options;
}
header udp_t {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<16> length_;
    bit<16> checksum;
}

header myTunnel_t {
    bit<16> proto_id;
    bit<16> dst_id;
}
header IPv4_up_to_ihl_only_h {
    bit<4> version;
    bit<4> ihl;
}
header tcp_upto_data_offset_only_h {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<32> seqNo;
    bit<32> ackNo;
    // dataOffset in TCP hdr uses 4 bits but needs padding.
    // If 4 bits are used for it, p4c-bm2-ss complains the header
    // is not a multiple of 8 bits.
    bit<4> dataOffset;
    bit<4> dontCare;
}
struct headers {
    ethernet_t ethernet;
    ipv4_t ipv4;
    tcp_t tcp;
    myTunnel_t my_tunnel;
}

struct metadata {
    mystruct1_t mystruct1;
    bit<16> l4Len; // includes TCP hdr len + TCP payload len in bytes.
}

```

Adding fields and updating length of the packet:

```auto
action syn_client_send (bit<48> src_mac, bit<48> dst_mac, bit<32> src_ip, bit<9> port){
    ........
	hdr.my_tunnel.setValid();
        hdr.my_tunnel.proto_id=6;
        hdr.my_tunnel.dst_id=3;
	hdr.ipv4.totalLen=hdr.ipv4.totalLen + TUNNEL_HDR_SIZE; //Updating headerLen cause we are adding hdr.my_tunnel.
        meta.l4Len = hdr.ipv4.totalLen - (bit<16>)(hdr.ipv4.ihl)*4;

```

Checksum calculation:

```auto
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
     apply {
	update_checksum(
	    hdr.ipv4.isValid(),
            { hdr.ipv4.version,
	      hdr.ipv4.ihl,
              hdr.ipv4.diffserv,
              hdr.ipv4.totalLen,
              hdr.ipv4.identification,
              hdr.ipv4.flags,
              hdr.ipv4.fragOffset,
              hdr.ipv4.ttl,
              hdr.ipv4.protocol,
              hdr.ipv4.srcAddr,
              hdr.ipv4.dstAddr },
            hdr.ipv4.hdrChecksum,
            HashAlgorithm.csum16);
	     update_checksum_with_payload(hdr.tcp.isValid(),
            { hdr.ipv4.srcAddr,
                hdr.ipv4.dstAddr,
                8w0,
                hdr.ipv4.protocol,
                meta.l4Len,
                hdr.tcp.srcPort,
                hdr.tcp.dstPort,
                hdr.tcp.seqNo,
                hdr.tcp.ackNo,
                hdr.tcp.dataOffset,
                hdr.tcp.res,
                hdr.tcp.ecn,
                hdr.tcp.urg,
                hdr.tcp.ack,
                hdr.tcp.psh,
                hdr.tcp.rst,
                hdr.tcp.syn,
                hdr.tcp.fin,
                hdr.tcp.window,
                16w0,
                hdr.tcp.urgentPtr,
                hdr.tcp.options
            },
            hdr.tcp.checksum, HashAlgorithm.csum16);      
    }
}

```

Deparsing the packet:

```auto
control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.ipv4);
        packet.emit(hdr.tcp);
        packet.emit(hdr.my_tunnel);
    }
}

```

---

<div class="post-metadata">

**Author:** ![ederollora](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.p4.org/ederollora/32/21_2.png) [@ederollora](https://forum.p4.org/u/ederollora)\
**Post date:** [August 4, 2021, 11:33am UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96/2 "2021-08-04T11:33:35Z")

</div>

Hi Sara,

This is Eder from Slack. I am checking again your questionand I have a some comments.

- Have you tried removing the `varbit<320>` option field (for now)? If you don’t need the options for anything I recommend that you don’t parse them. It should ease the process. This is because I am not sure how varbits behave when it comes to calculating the checksum. If you still need the options, I would recommend defining **exactly** which options you parse (therefore create specific headers for them) in your test case and then feed the function with those “static” option headers. In this way, you could be sure that varbits are not causing the issue. In summary, I would remove the option field for now and try to calculate the checksum using the most simple use case, which is with the typical TCP fields (no options) and the `mytunnel_t` fields (see next point).

- Also, compared to yesterday I see that you now add a `mytunnel_t` header. As far as I understand 🤔, this should also be put into the checksum calculation function because `mytunnel_t` is payload too as long as the TCP header is concerned. Since you are setting it valid, I guess you have to feed the function with the `mytunnel_t` fields too.

- Be sure that `TUNNEL_HDR_SIZE` is ~~12~~ 4 bytes.

Let’s see if that works 🙂

PD: If anyone knows more about this topic or if I was wrong in anything please comment 🤜 🤛

Cheers,

---

<div class="post-metadata">

**Author:** ![sarahshakeri](https://avatars.discourse-cdn.com/v4/letter/s/e495f1/32.png) [@sarahshakeri](https://forum.p4.org/u/sarahshakeri)\
**Post date:** [August 4, 2021, 5:51pm UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96/3 "2021-08-04T17:51:44Z")

</div>

Hello ederollora,  
Thanks for your reply.  
As you recommended, I removed the TCP option but still, the checksum is not correct, and I am sure that `TUNNEL_HDR_SIZE` is 4.  
How can I put mytunnel\_t into checksum calculation? I just change the meta.l4Len when adding the new header, and it is being used in tcp checksum calculation function. I am wondering what other items should I take into account in checksum function when using mytunnel header?

---

<div class="post-metadata">

**Author:** ![ederollora](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.p4.org/ederollora/32/21_2.png) [@ederollora](https://forum.p4.org/u/ederollora)\
**Post date:** [August 4, 2021, 11:15pm UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96/4 "2021-08-04T23:15:17Z")

</div>

Hi Sara,

I found your error. I think it works for me let’s see if you have the same error.

The main mistake I found is that you miss a field. This one:

```auto
bit<1> cwr;

```

So your function should be:

```auto
(...)
hdr.tcp.res,
hdr.tcp.cwr, //missing field
hdr.tcp.ecn,
(...)

```

Now, if you want to add `my_tunnel` to your packet, you have to run the following checksum function:

```auto
//In your action
    hdr.ipv4.totalLen=hdr.ipv4.totalLen + TUNNEL_HDR_SIZE;
    meta.tcpLength = hdr.ipv4.totalLen - (bit<16>)(hdr.ipv4.ihl)*4

//In your checksum computation
    update_checksum_with_payload(hdr.tcp.isValid(),
        { hdr.ipv4.srcAddr,
            hdr.ipv4.dstAddr,
            8w0,
            hdr.ipv4.protocol,
            meta.tcpLength, //I changed this name, so change it back to yours
            hdr.tcp.srcPort,
            hdr.tcp.dstPort,
            hdr.tcp.seqNo,
            hdr.tcp.ackNo,
            hdr.tcp.dataOffset,
            hdr.tcp.res,
            hdr.tcp.cwr,
            hdr.tcp.ecn,
            hdr.tcp.urg,
            hdr.tcp.ack,
            hdr.tcp.psh,
            hdr.tcp.rst,
            hdr.tcp.syn,
            hdr.tcp.fin,
            hdr.tcp.window,
            16w0,
            hdr.tcp.urgentPtr,
            hdr.my_tunnel.proto_id,
            hdr.my_tunnel.dst_id},
        hdr.tcp.checksum, HashAlgorithm.csum16);
    }

```

The problem at this point is to add TCP options. Why? you might ask. Well, a few reasons:

1. If you use options defined as a `varbit` field… I have no idea how they behave. So… you will have to test the `update_checksum_with_payload` function again with TCP options ar `varbit` 🙂
2. If you do not parse TCP options then `my_tunnel` will remain between the TCP header and the options. If that works for you then you are fine.
3. Also, be aware that if the packet has IPv4 options, my code does not account for that right now. If your use case can does not include options… then much better.

I remember this file from Andy Fingerhut ([here](https://github.com/jafingerhut/p4-guide/tree/master/tcp-options-parser)) in which he defines options as “typical” without `varbit` fields. He shared two parsers there so check if any works for you (in one of them he uses a stack). Still, it is going to be a little challenge to calculate the TCP checksum IF you need to parse TCP options mandatorily. I will let you investigate that.

I hope it helps.

Cheers,

---

<div class="post-metadata">

**Author:** ![sarahshakeri](https://avatars.discourse-cdn.com/v4/letter/s/e495f1/32.png) [@sarahshakeri](https://forum.p4.org/u/sarahshakeri)\
**Post date:** [August 5, 2021, 8:07pm UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96/5 "2021-08-05T20:07:56Z")

</div>

Hello ederollora,

Thanks a lot, it works. I had to add my\_tunnel header in the checksum calculation. And, I am now running it with options varbit and it works fine with no problem.

Thanks again for your help:)

---

<div class="post-metadata">

**Author:** ![ederollora](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.p4.org/ederollora/32/21_2.png) [@ederollora](https://forum.p4.org/u/ederollora)\
**Post date:** [August 5, 2021, 8:19pm UTC](https://forum.p4.org/t/checksum-calculation-when-adding-payload-to-syn-packet/96/6 "2021-08-05T20:19:11Z")

</div>

I am happy it works 🙂

Regards,
