Working checksum computation
This commit is contained in:
parent
1ee8439ed8
commit
4b9bd48053
2 changed files with 35 additions and 52 deletions
57
xdp/test.c
57
xdp/test.c
|
@ -20,40 +20,30 @@ char pkt3[] = { 0x50,0x9a,0x4c,0x24,0x1a,0x72,0x04,0xf0,0x21,0x65,0x18,0x12,0x08
|
||||||
|
|
||||||
char csDesired[] = { 0x38, 0xf1 };
|
char csDesired[] = { 0x38, 0xf1 };
|
||||||
|
|
||||||
// Checksum utilities
|
static __always_inline __u16 csum_fold_helper(__u32 csum)
|
||||||
__attribute__((__always_inline__))
|
{
|
||||||
static inline __u16 csum_fold_helper(__u64 csum) {
|
return ~((csum & 0xffff) + (csum >> 16));
|
||||||
int i;
|
}
|
||||||
#pragma unroll
|
static __always_inline void ipv4_csum(void *data_start, int data_size, __u32 *csum) {
|
||||||
for (i = 0; i < 4; i ++) {
|
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
|
||||||
if (csum >> 16)
|
*csum = csum_fold_helper(*csum);
|
||||||
csum = (csum & 0xffff) + (csum >> 16);
|
|
||||||
}
|
|
||||||
return ~csum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update checksum following RFC 1624 (Eqn. 3): https://tools.ietf.org/html/rfc1624
|
int checksum(__u16* ipbuf, __u32 len) {
|
||||||
// HC' = ~(~HC + ~m + m')
|
// https://tools.ietf.org/html/rfc1071
|
||||||
// Where :
|
__u32 sum = 0;
|
||||||
// HC - old checksum in header
|
for (int i = 0; i < sizeof(struct iphdr)/2; i++) {
|
||||||
// HC' - new checksum in header
|
sum += ipbuf[i];
|
||||||
// m - old value
|
}
|
||||||
// m' - new value
|
|
||||||
__attribute__((__always_inline__))
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
static inline void update_csum(__u64 *csum, __be32 old_flag,__be32 new_flag ) {
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
// ~HC
|
|
||||||
*csum = ~*csum;
|
return ~sum;
|
||||||
*csum = *csum & 0xffff;
|
|
||||||
// + ~m
|
|
||||||
__u32 tmp;
|
|
||||||
tmp = ~old_addr;
|
|
||||||
*csum += tmp;
|
|
||||||
// + m
|
|
||||||
*csum += new_addr;
|
|
||||||
// then fold and complement result !
|
|
||||||
*csum = csum_fold_helper(*csum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO: Implement https://tools.ietf.org/html/rfc1624 instead
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
void *data = pkt3;
|
void *data = pkt3;
|
||||||
|
@ -62,10 +52,9 @@ int main(void) {
|
||||||
struct ethhdr *eth = data; //structure ethernet from if_ether.h
|
struct ethhdr *eth = data; //structure ethernet from if_ether.h
|
||||||
struct iphdr *ip = (struct iphdr*)(eth + 1);
|
struct iphdr *ip = (struct iphdr*)(eth + 1);
|
||||||
printf("%#06x\n", bpf_ntohs(ip->check));
|
printf("%#06x\n", bpf_ntohs(ip->check));
|
||||||
__u64 cs = iph->check;
|
ip->check = 0;
|
||||||
update_csum(&cs, old_addr, new_addr);
|
ip->check = checksum((__u16*)ip, sizeof(*ip));
|
||||||
iph->check = cs;
|
printf("%#06x\n", bpf_ntohs(ip->check));
|
||||||
printf("new cs: %x\n", ip->check);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main2(void) {
|
int main2(void) {
|
||||||
|
|
|
@ -32,24 +32,18 @@
|
||||||
##__VA_ARGS__); \
|
##__VA_ARGS__); \
|
||||||
})
|
})
|
||||||
|
|
||||||
static inline unsigned short checksum(unsigned short *buf, int bufsz) {
|
static __always_inline int checksum_ipv4(__u16* ipbuf) {
|
||||||
unsigned long sum = 0;
|
// https://tools.ietf.org/html/rfc1071
|
||||||
|
__u32 sum = 0;
|
||||||
|
for (int i = 0; i < sizeof(struct iphdr)/2; i++) {
|
||||||
|
sum += ipbuf[i];
|
||||||
|
}
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|
||||||
while (bufsz > 1) {
|
return ~sum;
|
||||||
sum += *buf;
|
|
||||||
buf++;
|
|
||||||
bufsz -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufsz == 1) {
|
|
||||||
sum += *(unsigned char *)buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
|
||||||
|
|
||||||
return ~sum;
|
|
||||||
}
|
}
|
||||||
|
// @TODO: Implement https://tools.ietf.org/html/rfc1624 instead
|
||||||
|
|
||||||
SEC("xdp_udp")
|
SEC("xdp_udp")
|
||||||
int xdp_udp_func(struct xdp_md *ctx)
|
int xdp_udp_func(struct xdp_md *ctx)
|
||||||
|
@ -74,8 +68,8 @@ int xdp_udp_func(struct xdp_md *ctx)
|
||||||
|
|
||||||
if(ip->protocol == IPPROTO_UDP) {
|
if(ip->protocol == IPPROTO_UDP) {
|
||||||
ip->frag_off |= bpf_htons(0x4000); //Set the DF flag to 1 -> 0b 0100 0000 0000 0000
|
ip->frag_off |= bpf_htons(0x4000); //Set the DF flag to 1 -> 0b 0100 0000 0000 0000
|
||||||
ip->check = 0x0000;
|
ip->check = 0;
|
||||||
ip->check = checksum((unsigned short*)ip, sizeof(ip));
|
ip->check = checksum_ipv4((__u16*)ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return XDP_PASS;
|
return XDP_PASS;
|
||||||
|
|
Loading…
Reference in a new issue