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