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:
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:
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:
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:
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);
}
}