Home | History | Annotate | Line # | Download | only in dist
xdp-util.h revision 1.1
      1 /*
      2  * xdp-util.h -- set of xdp related helpers
      3  *
      4  * Copyright (c) 2024, NLnet Labs. All rights reserved.
      5  *
      6  * See LICENSE for the license.
      7  *
      8  */
      9 
     10 #ifndef XDP_UTIL_H
     11 #define XDP_UTIL_H
     12 
     13 #include <linux/ip.h>
     14 #include <linux/ipv6.h>
     15 #include <linux/types.h>
     16 #include <linux/udp.h>
     17 
     18 /*
     19  * Get number of combined or rx queues available on ifname.
     20  */
     21 int ethtool_channels_get(char const *ifname);
     22 
     23 /*
     24  * Set capabilities to only include the ones needed for using AF_XDP/
     25  */
     26 void set_caps(int unset_setid_caps);
     27 
     28 /*
     29  * Add u16 to checksum value and preserve one's complement sum.
     30  */
     31 static inline __sum16 csum16_add(__sum16 csum, __be16 addend) {
     32 	uint16_t res = (uint16_t)csum;
     33 
     34 	res += (__u16)addend;
     35 	return (__sum16)(res + (res < (__u16)addend));
     36 }
     37 
     38 /*
     39  * Subtract u16 from checksum value and preserve one's complement sum.
     40  */
     41 static inline __sum16 csum16_sub(__sum16 csum, __be16 addend) {
     42 	return csum16_add(csum, ~addend);
     43 }
     44 
     45 /*
     46  * Replace u16 from checksum value and preserve one's complement sum.
     47  */
     48 static inline void csum16_replace(__sum16 *sum, __be16 old, __be16 new) {
     49 	*sum = ~csum16_add(csum16_sub(~(*sum), old), new);
     50 }
     51 
     52 /*
     53  * Sum up _data_len amount of 16-bit words in _data and add to result.
     54  */
     55 static inline void csum_add_data(uint32_t *result,
     56                           const void *_data,
     57                           uint32_t len) {
     58 	const uint16_t *data = _data;
     59 	while (len > 1) {
     60 		*result += *data++;
     61 		len -= 2;
     62 	}
     63 	if (len)
     64 		*result += *data & 0xff;
     65 		// *result += *(uint8_t *)data;
     66 }
     67 
     68 /*
     69  * Add single 16-bit words to result.
     70  */
     71 static inline void csum_add_u16(uint32_t *result, uint16_t x) { *result += x; }
     72 
     73 /*
     74  * Apply one's complement to result.
     75  */
     76 static inline void csum_reduce(uint32_t *result) {
     77 	while (*result >> 16)
     78 		*result = (*result & 0xffff) + (*result >> 16);
     79 }
     80 
     81 /*
     82  * Calculate UDP checksum with IPv6 pseudo-header
     83  */
     84 static inline uint16_t calc_csum_udp6(struct udphdr *udp, struct ipv6hdr *ipv6) {
     85 	uint32_t sum = 0;
     86 	sum += udp->len;
     87 	sum += htons(IPPROTO_UDP);
     88 	csum_add_data(&sum, &ipv6->saddr, sizeof(ipv6->saddr));
     89 	csum_add_data(&sum, &ipv6->daddr, sizeof(ipv6->daddr));
     90 
     91 	udp->check = 0;
     92 	csum_add_data(&sum, udp, ntohs(udp->len));
     93 	/* maybe restore previous checksum to remove side effects? */
     94 
     95 	// reduces sum to 16bit
     96 	csum_reduce(&sum);
     97 
     98 	if (sum != 0xffff)
     99 		return (uint16_t) ~sum;
    100 	else
    101 		return (uint16_t) sum;
    102 }
    103 
    104 /*
    105  * Calculate UDP checksum with IPv4 pseudo-header
    106  */
    107 static inline uint16_t calc_csum_udp4(struct udphdr *udp, struct iphdr *ipv4) {
    108 	uint32_t sum = 0;
    109 	sum += udp->len;
    110 	sum += htons(IPPROTO_UDP);
    111 	csum_add_data(&sum, &ipv4->saddr, sizeof(ipv4->saddr));
    112 	csum_add_data(&sum, &ipv4->daddr, sizeof(ipv4->daddr));
    113 
    114 	udp->check = 0;
    115 	csum_add_data(&sum, udp, ntohs(udp->len));
    116 	/* maybe restore previous checksum to remove side effects? */
    117 
    118 	// reduces sum to 16bit
    119 	csum_reduce(&sum);
    120 
    121 	if (sum != 0xffff)
    122 		return (uint16_t) ~sum;
    123 	else
    124 		return (uint16_t) sum;
    125 }
    126 
    127 #endif /* XDP_UTIL_H */
    128