summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/network_helpers.h
blob: ebec8a8d6f81e9d079a3b087127a37885c656856 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NETWORK_HELPERS_H
#define __NETWORK_HELPERS_H
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/types.h>
typedef __u16 __sum16;
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <linux/err.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <bpf/bpf_endian.h>
#include <net/if.h>

#define MAGIC_VAL 0x1234
#define NUM_ITER 100000
#define VIP_NUM 5
#define MAGIC_BYTES 123

struct network_helper_opts {
	int timeout_ms;
	int proto;
	/* +ve: Passed to listen() as-is.
	 *   0: Default when the test does not set
	 *      a particular value during the struct init.
	 *      It is changed to 1 before passing to listen().
	 *      Most tests only have one on-going connection.
	 * -ve: It is changed to 0 before passing to listen().
	 *      It is useful to force syncookie without
	 *	changing the "tcp_syncookies" sysctl from 1 to 2.
	 */
	int backlog;
	int (*post_socket_cb)(int fd, void *opts);
	void *cb_opts;
};

/* ipv4 test vector */
struct ipv4_packet {
	struct ethhdr eth;
	struct iphdr iph;
	struct tcphdr tcp;
} __packed;
extern struct ipv4_packet pkt_v4;

/* ipv6 test vector */
struct ipv6_packet {
	struct ethhdr eth;
	struct ipv6hdr iph;
	struct tcphdr tcp;
} __packed;
extern struct ipv6_packet pkt_v6;

int settimeo(int fd, int timeout_ms);
int start_server_str(int family, int type, const char *addr_str, __u16 port,
		     const struct network_helper_opts *opts);
int start_server(int family, int type, const char *addr, __u16 port,
		 int timeout_ms);
int *start_reuseport_server(int family, int type, const char *addr_str,
			    __u16 port, int timeout_ms,
			    unsigned int nr_listens);
int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t len,
		      const struct network_helper_opts *opts);
void free_fds(int *fds, unsigned int nr_close_fds);
int client_socket(int family, int type,
		  const struct network_helper_opts *opts);
int connect_to_addr(int type, const struct sockaddr_storage *addr, socklen_t len,
		    const struct network_helper_opts *opts);
int connect_to_addr_str(int family, int type, const char *addr_str, __u16 port,
			const struct network_helper_opts *opts);
int connect_to_fd(int server_fd, int timeout_ms);
int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts);
int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms);
int fastopen_connect(int server_fd, const char *data, unsigned int data_len,
		     int timeout_ms);
int make_sockaddr(int family, const char *addr_str, __u16 port,
		  struct sockaddr_storage *addr, socklen_t *len);
char *ping_command(int family);
int get_socket_local_port(int sock_fd);
int get_hw_ring_size(char *ifname, struct ethtool_ringparam *ring_param);
int set_hw_ring_size(char *ifname, struct ethtool_ringparam *ring_param);

struct nstoken;
/**
 * open_netns() - Switch to specified network namespace by name.
 *
 * Returns token with which to restore the original namespace
 * using close_netns().
 */
struct nstoken *open_netns(const char *name);
void close_netns(struct nstoken *token);
int send_recv_data(int lfd, int fd, uint32_t total_bytes);
int make_netns(const char *name);
int remove_netns(const char *name);

static __u16 csum_fold(__u32 csum)
{
	csum = (csum & 0xffff) + (csum >> 16);
	csum = (csum & 0xffff) + (csum >> 16);

	return (__u16)~csum;
}

static __wsum csum_partial(const void *buf, int len, __wsum sum)
{
	__u16 *p = (__u16 *)buf;
	int num_u16 = len >> 1;
	int i;

	for (i = 0; i < num_u16; i++)
		sum += p[i];

	return sum;
}

static inline __sum16 build_ip_csum(struct iphdr *iph)
{
	__u32 sum = 0;
	__u16 *p;

	iph->check = 0;
	p = (void *)iph;
	sum = csum_partial(p, iph->ihl << 2, 0);

	return csum_fold(sum);
}

/**
 * csum_tcpudp_magic - compute IP pseudo-header checksum
 *
 * Compute the IPv4 pseudo header checksum. The helper can take a
 * accumulated sum from the transport layer to accumulate it and directly
 * return the transport layer
 *
 * @saddr: IP source address
 * @daddr: IP dest address
 * @len: IP data size
 * @proto: transport layer protocol
 * @csum: The accumulated partial sum to add to the computation
 *
 * Returns the folded sum
 */
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
					__u32 len, __u8 proto,
					__wsum csum)
{
	__u64 s = csum;

	s += (__u32)saddr;
	s += (__u32)daddr;
	s += htons(proto + len);
	s = (s & 0xffffffff) + (s >> 32);
	s = (s & 0xffffffff) + (s >> 32);

	return csum_fold((__u32)s);
}

/**
 * csum_ipv6_magic - compute IPv6 pseudo-header checksum
 *
 * Compute the ipv6 pseudo header checksum. The helper can take a
 * accumulated sum from the transport layer to accumulate it and directly
 * return the transport layer
 *
 * @saddr: IPv6 source address
 * @daddr: IPv6 dest address
 * @len: IPv6 data size
 * @proto: transport layer protocol
 * @csum: The accumulated partial sum to add to the computation
 *
 * Returns the folded sum
 */
static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
				      const struct in6_addr *daddr,
					__u32 len, __u8 proto,
					__wsum csum)
{
	__u64 s = csum;
	int i;

	for (i = 0; i < 4; i++)
		s += (__u32)saddr->s6_addr32[i];
	for (i = 0; i < 4; i++)
		s += (__u32)daddr->s6_addr32[i];
	s += htons(proto + len);
	s = (s & 0xffffffff) + (s >> 32);
	s = (s & 0xffffffff) + (s >> 32);

	return csum_fold((__u32)s);
}

/**
 * build_udp_v4_csum - compute UDP checksum for UDP over IPv4
 *
 * Compute the checksum to embed in UDP header, composed of the sum of IP
 * pseudo-header checksum, UDP header checksum and UDP data checksum
 * @iph IP header
 * @udph UDP header, which must be immediately followed by UDP data
 *
 * Returns the total checksum
 */

static inline __sum16 build_udp_v4_csum(const struct iphdr *iph,
					const struct udphdr *udph)
{
	unsigned long sum;

	sum = csum_partial(udph, ntohs(udph->len), 0);
	return csum_tcpudp_magic(iph->saddr, iph->daddr, ntohs(udph->len),
				 IPPROTO_UDP, sum);
}

/**
 * build_udp_v6_csum - compute UDP checksum for UDP over IPv6
 *
 * Compute the checksum to embed in UDP header, composed of the sum of IPv6
 * pseudo-header checksum, UDP header checksum and UDP data checksum
 * @ip6h IPv6 header
 * @udph UDP header, which must be immediately followed by UDP data
 *
 * Returns the total checksum
 */
static inline __sum16 build_udp_v6_csum(const struct ipv6hdr *ip6h,
					const struct udphdr *udph)
{
	unsigned long sum;

	sum = csum_partial(udph, ntohs(udph->len), 0);
	return csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ntohs(udph->len),
			       IPPROTO_UDP, sum);
}

struct tmonitor_ctx;

#ifdef TRAFFIC_MONITOR
struct tmonitor_ctx *traffic_monitor_start(const char *netns, const char *test_name,
					   const char *subtest_name);
void traffic_monitor_stop(struct tmonitor_ctx *ctx);
#else
static inline struct tmonitor_ctx *traffic_monitor_start(const char *netns, const char *test_name,
							 const char *subtest_name)
{
	return NULL;
}

static inline void traffic_monitor_stop(struct tmonitor_ctx *ctx)
{
}
#endif

#endif