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