How to calculate TCP Checksum in XDP/eBPF

124 Views Asked by At

The following code should calculate the TCP Checksum, but for unknown reasons, it doesn't calculate it correctly.

#define MAX_CSUM_WORDS 750

static __always_inline __u32 sum16(const void* data, __u32 size, const void* data_end) {
    __u32 s = 0;
    #pragma unroll
    for (__u32 i = 0; i < MAX_CSUM_WORDS; i++) {
        if (2*i >= size) {
            return s; /* normal exit */
        }
        if (data + 2*i + 1 + 1 > data_end) {
            return 0; /* should be unreachable */
        }
        s += ((const __u16*)data)[i];

        if (2*i + 1 == size) {
             if (data + (i*2+2) > data_end) {
                return 0;
            }else{
                s += ((const __u8*)data)[i*2+1];
                return s;
            }
        }

    }
    return s;
}

static __always_inline __u32 sum16_32(__u32 v) {
    return (v >> 16) + (v & 0xffff);
}
static __always_inline __u16 carry(__u32 csum) {
    csum = (csum & 0xffff) + (csum >> 16);
    csum = (csum & 0xffff) + (csum >> 16); // loop
    return ~csum;
}
// Inside the main code
unsigned int payload_len = ntohs(iph->tot_len) - (iph->ihl * 4 + tcph->doff * 4);

__u32 tcp_csum = 0;
tcp_csum += sum16_32(iph->saddr);
tcp_csum += sum16_32(iph->daddr);
tcp_csum += 0x0600;
tcp_csum += (uint16_t)(((tcph->doff * 4) + payload_len));
tcph->check = 0;
tcp_csum += sum16(tcph, ((tcph->doff * 4) + payload_len), data_end);
tcph->check = carry(tcp_csum);

The payload length of the packet I'm testing on is 125 byte.

carry and sum16_32 and sum16 are copied from an XDP SYN Cookie project. I just have edited sum16 to handle odd-byte cases.

Thank you for helping in advance.

0

There are 0 best solutions below