116962b24SJohn Fastabend // SPDX-License-Identifier: GPL-2.0
216962b24SJohn Fastabend // Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io
316962b24SJohn Fastabend #include <stdio.h>
416962b24SJohn Fastabend #include <stdlib.h>
516962b24SJohn Fastabend #include <sys/socket.h>
616962b24SJohn Fastabend #include <sys/ioctl.h>
716962b24SJohn Fastabend #include <sys/select.h>
816962b24SJohn Fastabend #include <netinet/in.h>
916962b24SJohn Fastabend #include <arpa/inet.h>
1016962b24SJohn Fastabend #include <unistd.h>
1116962b24SJohn Fastabend #include <string.h>
1216962b24SJohn Fastabend #include <errno.h>
1316962b24SJohn Fastabend #include <stdbool.h>
1416962b24SJohn Fastabend #include <signal.h>
1516962b24SJohn Fastabend #include <fcntl.h>
1616962b24SJohn Fastabend #include <sys/wait.h>
1716962b24SJohn Fastabend #include <time.h>
1816962b24SJohn Fastabend #include <sched.h>
1916962b24SJohn Fastabend 
2016962b24SJohn Fastabend #include <sys/time.h>
2116962b24SJohn Fastabend #include <sys/resource.h>
2216962b24SJohn Fastabend #include <sys/types.h>
2316962b24SJohn Fastabend #include <sys/sendfile.h>
2416962b24SJohn Fastabend 
2516962b24SJohn Fastabend #include <linux/netlink.h>
2616962b24SJohn Fastabend #include <linux/socket.h>
2716962b24SJohn Fastabend #include <linux/sock_diag.h>
2816962b24SJohn Fastabend #include <linux/bpf.h>
2916962b24SJohn Fastabend #include <linux/if_link.h>
30421f4292SDaniel Borkmann #include <linux/tls.h>
3116962b24SJohn Fastabend #include <assert.h>
3216962b24SJohn Fastabend #include <libgen.h>
3316962b24SJohn Fastabend 
3416962b24SJohn Fastabend #include <getopt.h>
3516962b24SJohn Fastabend 
3616962b24SJohn Fastabend #include <bpf/bpf.h>
3716962b24SJohn Fastabend #include <bpf/libbpf.h>
3816962b24SJohn Fastabend 
3916962b24SJohn Fastabend #include "bpf_util.h"
4016962b24SJohn Fastabend #include "bpf_rlimit.h"
4116962b24SJohn Fastabend #include "cgroup_helpers.h"
4216962b24SJohn Fastabend 
4316962b24SJohn Fastabend int running;
4416962b24SJohn Fastabend static void running_handler(int a);
4516962b24SJohn Fastabend 
46421f4292SDaniel Borkmann #ifndef TCP_ULP
47421f4292SDaniel Borkmann # define TCP_ULP 31
48421f4292SDaniel Borkmann #endif
49421f4292SDaniel Borkmann #ifndef SOL_TLS
50421f4292SDaniel Borkmann # define SOL_TLS 282
51421f4292SDaniel Borkmann #endif
52421f4292SDaniel Borkmann 
5316962b24SJohn Fastabend /* randomly selected ports for testing on lo */
5416962b24SJohn Fastabend #define S1_PORT 10000
5516962b24SJohn Fastabend #define S2_PORT 10001
5616962b24SJohn Fastabend 
57b8b394faSJohn Fastabend #define BPF_SOCKMAP_FILENAME  "test_sockmap_kern.o"
58b8b394faSJohn Fastabend #define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o"
5916962b24SJohn Fastabend #define CG_PATH "/sockmap"
6016962b24SJohn Fastabend 
6116962b24SJohn Fastabend /* global sockets */
6216962b24SJohn Fastabend int s1, s2, c1, c2, p1, p2;
6316962b24SJohn Fastabend int test_cnt;
6416962b24SJohn Fastabend int passed;
6516962b24SJohn Fastabend int failed;
66463bac5fSJohn Fastabend int map_fd[9];
67463bac5fSJohn Fastabend struct bpf_map *maps[9];
6816962b24SJohn Fastabend int prog_fd[11];
6916962b24SJohn Fastabend 
7016962b24SJohn Fastabend int txmsg_pass;
7116962b24SJohn Fastabend int txmsg_redir;
7216962b24SJohn Fastabend int txmsg_drop;
7316962b24SJohn Fastabend int txmsg_apply;
7416962b24SJohn Fastabend int txmsg_cork;
7516962b24SJohn Fastabend int txmsg_start;
7616962b24SJohn Fastabend int txmsg_end;
7784fbfe02SJohn Fastabend int txmsg_start_push;
7884fbfe02SJohn Fastabend int txmsg_end_push;
791ade9abaSJohn Fastabend int txmsg_start_pop;
801ade9abaSJohn Fastabend int txmsg_pop;
8116962b24SJohn Fastabend int txmsg_ingress;
82463bac5fSJohn Fastabend int txmsg_redir_skb;
83463bac5fSJohn Fastabend int txmsg_ktls_skb;
84463bac5fSJohn Fastabend int txmsg_ktls_skb_drop;
85463bac5fSJohn Fastabend int txmsg_ktls_skb_redir;
86e9dd9047SJohn Fastabend int ktls;
87753fb2eeSJohn Fastabend int peek_flag;
8853792fa4SJohn Fastabend int skb_use_parser;
8916962b24SJohn Fastabend 
9016962b24SJohn Fastabend static const struct option long_options[] = {
9116962b24SJohn Fastabend 	{"help",	no_argument,		NULL, 'h' },
9216962b24SJohn Fastabend 	{"cgroup",	required_argument,	NULL, 'c' },
9316962b24SJohn Fastabend 	{"rate",	required_argument,	NULL, 'r' },
94b98ca90cSJohn Fastabend 	{"verbose",	optional_argument,	NULL, 'v' },
9516962b24SJohn Fastabend 	{"iov_count",	required_argument,	NULL, 'i' },
9616962b24SJohn Fastabend 	{"length",	required_argument,	NULL, 'l' },
9716962b24SJohn Fastabend 	{"test",	required_argument,	NULL, 't' },
9816962b24SJohn Fastabend 	{"data_test",   no_argument,		NULL, 'd' },
9916962b24SJohn Fastabend 	{"txmsg",		no_argument,	&txmsg_pass,  1  },
10016962b24SJohn Fastabend 	{"txmsg_redir",		no_argument,	&txmsg_redir, 1  },
10116962b24SJohn Fastabend 	{"txmsg_drop",		no_argument,	&txmsg_drop, 1 },
10216962b24SJohn Fastabend 	{"txmsg_apply",	required_argument,	NULL, 'a'},
10316962b24SJohn Fastabend 	{"txmsg_cork",	required_argument,	NULL, 'k'},
10416962b24SJohn Fastabend 	{"txmsg_start", required_argument,	NULL, 's'},
10516962b24SJohn Fastabend 	{"txmsg_end",	required_argument,	NULL, 'e'},
10684fbfe02SJohn Fastabend 	{"txmsg_start_push", required_argument,	NULL, 'p'},
10784fbfe02SJohn Fastabend 	{"txmsg_end_push",   required_argument,	NULL, 'q'},
1081ade9abaSJohn Fastabend 	{"txmsg_start_pop",  required_argument,	NULL, 'w'},
1091ade9abaSJohn Fastabend 	{"txmsg_pop",	     required_argument,	NULL, 'x'},
11016962b24SJohn Fastabend 	{"txmsg_ingress", no_argument,		&txmsg_ingress, 1 },
111463bac5fSJohn Fastabend 	{"txmsg_redir_skb", no_argument,	&txmsg_redir_skb, 1 },
112e9dd9047SJohn Fastabend 	{"ktls", no_argument,			&ktls, 1 },
113753fb2eeSJohn Fastabend 	{"peek", no_argument,			&peek_flag, 1 },
114065a74cbSJohn Fastabend 	{"whitelist", required_argument,	NULL, 'n' },
115a7238f7cSJohn Fastabend 	{"blacklist", required_argument,	NULL, 'b' },
11616962b24SJohn Fastabend 	{0, 0, NULL, 0 }
11716962b24SJohn Fastabend };
11816962b24SJohn Fastabend 
119328aa08aSJohn Fastabend struct test_env {
120328aa08aSJohn Fastabend 	const char *type;
121328aa08aSJohn Fastabend 	const char *subtest;
12296586dd9SJohn Fastabend 	const char *prepend;
123328aa08aSJohn Fastabend 
124328aa08aSJohn Fastabend 	int test_num;
125328aa08aSJohn Fastabend 	int subtest_num;
126328aa08aSJohn Fastabend 
127328aa08aSJohn Fastabend 	int succ_cnt;
128328aa08aSJohn Fastabend 	int fail_cnt;
129328aa08aSJohn Fastabend 	int fail_last;
130328aa08aSJohn Fastabend };
131328aa08aSJohn Fastabend 
132328aa08aSJohn Fastabend struct test_env env;
133328aa08aSJohn Fastabend 
13496586dd9SJohn Fastabend struct sockmap_options {
13596586dd9SJohn Fastabend 	int verbose;
13696586dd9SJohn Fastabend 	bool base;
13796586dd9SJohn Fastabend 	bool sendpage;
13896586dd9SJohn Fastabend 	bool data_test;
13996586dd9SJohn Fastabend 	bool drop_expected;
14096586dd9SJohn Fastabend 	int iov_count;
14196586dd9SJohn Fastabend 	int iov_length;
14296586dd9SJohn Fastabend 	int rate;
14396586dd9SJohn Fastabend 	char *map;
14496586dd9SJohn Fastabend 	char *whitelist;
14596586dd9SJohn Fastabend 	char *blacklist;
14696586dd9SJohn Fastabend 	char *prepend;
14796586dd9SJohn Fastabend };
14896586dd9SJohn Fastabend 
14996586dd9SJohn Fastabend struct _test {
15096586dd9SJohn Fastabend 	char *title;
15196586dd9SJohn Fastabend 	void (*tester)(int cg_fd, struct sockmap_options *opt);
15296586dd9SJohn Fastabend };
15396586dd9SJohn Fastabend 
154328aa08aSJohn Fastabend static void test_start(void)
155328aa08aSJohn Fastabend {
156328aa08aSJohn Fastabend 	env.subtest_num++;
157328aa08aSJohn Fastabend }
158328aa08aSJohn Fastabend 
159328aa08aSJohn Fastabend static void test_fail(void)
160328aa08aSJohn Fastabend {
161328aa08aSJohn Fastabend 	env.fail_cnt++;
162328aa08aSJohn Fastabend }
163328aa08aSJohn Fastabend 
164328aa08aSJohn Fastabend static void test_pass(void)
165328aa08aSJohn Fastabend {
166328aa08aSJohn Fastabend 	env.succ_cnt++;
167328aa08aSJohn Fastabend }
168328aa08aSJohn Fastabend 
169328aa08aSJohn Fastabend static void test_reset(void)
170328aa08aSJohn Fastabend {
171328aa08aSJohn Fastabend 	txmsg_start = txmsg_end = 0;
172328aa08aSJohn Fastabend 	txmsg_start_pop = txmsg_pop = 0;
173328aa08aSJohn Fastabend 	txmsg_start_push = txmsg_end_push = 0;
174328aa08aSJohn Fastabend 	txmsg_pass = txmsg_drop = txmsg_redir = 0;
175328aa08aSJohn Fastabend 	txmsg_apply = txmsg_cork = 0;
176463bac5fSJohn Fastabend 	txmsg_ingress = txmsg_redir_skb = 0;
177463bac5fSJohn Fastabend 	txmsg_ktls_skb = txmsg_ktls_skb_drop = txmsg_ktls_skb_redir = 0;
17853792fa4SJohn Fastabend 	skb_use_parser = 0;
179328aa08aSJohn Fastabend }
180328aa08aSJohn Fastabend 
18196586dd9SJohn Fastabend static int test_start_subtest(const struct _test *t, struct sockmap_options *o)
182328aa08aSJohn Fastabend {
18396586dd9SJohn Fastabend 	env.type = o->map;
18496586dd9SJohn Fastabend 	env.subtest = t->title;
18596586dd9SJohn Fastabend 	env.prepend = o->prepend;
186328aa08aSJohn Fastabend 	env.test_num++;
187328aa08aSJohn Fastabend 	env.subtest_num = 0;
188328aa08aSJohn Fastabend 	env.fail_last = env.fail_cnt;
189328aa08aSJohn Fastabend 	test_reset();
190328aa08aSJohn Fastabend 	return 0;
191328aa08aSJohn Fastabend }
192328aa08aSJohn Fastabend 
193328aa08aSJohn Fastabend static void test_end_subtest(void)
194328aa08aSJohn Fastabend {
195328aa08aSJohn Fastabend 	int error = env.fail_cnt - env.fail_last;
196328aa08aSJohn Fastabend 	int type = strcmp(env.type, BPF_SOCKMAP_FILENAME);
197328aa08aSJohn Fastabend 
198328aa08aSJohn Fastabend 	if (!error)
199328aa08aSJohn Fastabend 		test_pass();
200328aa08aSJohn Fastabend 
20196586dd9SJohn Fastabend 	fprintf(stdout, "#%2d/%2d %8s:%s:%s:%s\n",
202328aa08aSJohn Fastabend 		env.test_num, env.subtest_num,
203328aa08aSJohn Fastabend 		!type ? "sockmap" : "sockhash",
20496586dd9SJohn Fastabend 		env.prepend ? : "",
205328aa08aSJohn Fastabend 		env.subtest, error ? "FAIL" : "OK");
206328aa08aSJohn Fastabend }
207328aa08aSJohn Fastabend 
208328aa08aSJohn Fastabend static void test_print_results(void)
209328aa08aSJohn Fastabend {
210328aa08aSJohn Fastabend 	fprintf(stdout, "Pass: %d Fail: %d\n",
211328aa08aSJohn Fastabend 		env.succ_cnt, env.fail_cnt);
212328aa08aSJohn Fastabend }
213328aa08aSJohn Fastabend 
21416962b24SJohn Fastabend static void usage(char *argv[])
21516962b24SJohn Fastabend {
21616962b24SJohn Fastabend 	int i;
21716962b24SJohn Fastabend 
21816962b24SJohn Fastabend 	printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
21916962b24SJohn Fastabend 	printf(" options:\n");
22016962b24SJohn Fastabend 	for (i = 0; long_options[i].name != 0; i++) {
22116962b24SJohn Fastabend 		printf(" --%-12s", long_options[i].name);
22216962b24SJohn Fastabend 		if (long_options[i].flag != NULL)
22316962b24SJohn Fastabend 			printf(" flag (internal value:%d)\n",
22416962b24SJohn Fastabend 				*long_options[i].flag);
22516962b24SJohn Fastabend 		else
22616962b24SJohn Fastabend 			printf(" -%c\n", long_options[i].val);
22716962b24SJohn Fastabend 	}
22816962b24SJohn Fastabend 	printf("\n");
22916962b24SJohn Fastabend }
23016962b24SJohn Fastabend 
231e9dd9047SJohn Fastabend char *sock_to_string(int s)
232e9dd9047SJohn Fastabend {
233e9dd9047SJohn Fastabend 	if (s == c1)
234e9dd9047SJohn Fastabend 		return "client1";
235e9dd9047SJohn Fastabend 	else if (s == c2)
236e9dd9047SJohn Fastabend 		return "client2";
237e9dd9047SJohn Fastabend 	else if (s == s1)
238e9dd9047SJohn Fastabend 		return "server1";
239e9dd9047SJohn Fastabend 	else if (s == s2)
240e9dd9047SJohn Fastabend 		return "server2";
241e9dd9047SJohn Fastabend 	else if (s == p1)
242e9dd9047SJohn Fastabend 		return "peer1";
243e9dd9047SJohn Fastabend 	else if (s == p2)
244e9dd9047SJohn Fastabend 		return "peer2";
245e9dd9047SJohn Fastabend 	else
246e9dd9047SJohn Fastabend 		return "unknown";
247e9dd9047SJohn Fastabend }
248e9dd9047SJohn Fastabend 
249e9dd9047SJohn Fastabend static int sockmap_init_ktls(int verbose, int s)
250e9dd9047SJohn Fastabend {
251e9dd9047SJohn Fastabend 	struct tls12_crypto_info_aes_gcm_128 tls_tx = {
252e9dd9047SJohn Fastabend 		.info = {
253e9dd9047SJohn Fastabend 			.version     = TLS_1_2_VERSION,
254e9dd9047SJohn Fastabend 			.cipher_type = TLS_CIPHER_AES_GCM_128,
255e9dd9047SJohn Fastabend 		},
256e9dd9047SJohn Fastabend 	};
257e9dd9047SJohn Fastabend 	struct tls12_crypto_info_aes_gcm_128 tls_rx = {
258e9dd9047SJohn Fastabend 		.info = {
259e9dd9047SJohn Fastabend 			.version     = TLS_1_2_VERSION,
260e9dd9047SJohn Fastabend 			.cipher_type = TLS_CIPHER_AES_GCM_128,
261e9dd9047SJohn Fastabend 		},
262e9dd9047SJohn Fastabend 	};
263e9dd9047SJohn Fastabend 	int so_buf = 6553500;
264e9dd9047SJohn Fastabend 	int err;
265e9dd9047SJohn Fastabend 
266e9dd9047SJohn Fastabend 	err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls"));
267e9dd9047SJohn Fastabend 	if (err) {
268e9dd9047SJohn Fastabend 		fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err);
269e9dd9047SJohn Fastabend 		return -EINVAL;
270e9dd9047SJohn Fastabend 	}
271e9dd9047SJohn Fastabend 	err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx));
272e9dd9047SJohn Fastabend 	if (err) {
273e9dd9047SJohn Fastabend 		fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err);
274e9dd9047SJohn Fastabend 		return -EINVAL;
275e9dd9047SJohn Fastabend 	}
276e9dd9047SJohn Fastabend 	err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx));
277e9dd9047SJohn Fastabend 	if (err) {
278e9dd9047SJohn Fastabend 		fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err);
279e9dd9047SJohn Fastabend 		return -EINVAL;
280e9dd9047SJohn Fastabend 	}
281e9dd9047SJohn Fastabend 	err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf));
282e9dd9047SJohn Fastabend 	if (err) {
283e9dd9047SJohn Fastabend 		fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err);
284e9dd9047SJohn Fastabend 		return -EINVAL;
285e9dd9047SJohn Fastabend 	}
286e9dd9047SJohn Fastabend 	err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf));
287e9dd9047SJohn Fastabend 	if (err) {
288e9dd9047SJohn Fastabend 		fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err);
289e9dd9047SJohn Fastabend 		return -EINVAL;
290e9dd9047SJohn Fastabend 	}
291e9dd9047SJohn Fastabend 
292e9dd9047SJohn Fastabend 	if (verbose)
293e9dd9047SJohn Fastabend 		fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s));
294e9dd9047SJohn Fastabend 	return 0;
295e9dd9047SJohn Fastabend }
29616962b24SJohn Fastabend static int sockmap_init_sockets(int verbose)
29716962b24SJohn Fastabend {
29816962b24SJohn Fastabend 	int i, err, one = 1;
29916962b24SJohn Fastabend 	struct sockaddr_in addr;
30016962b24SJohn Fastabend 	int *fds[4] = {&s1, &s2, &c1, &c2};
30116962b24SJohn Fastabend 
30216962b24SJohn Fastabend 	s1 = s2 = p1 = p2 = c1 = c2 = 0;
30316962b24SJohn Fastabend 
30416962b24SJohn Fastabend 	/* Init sockets */
30516962b24SJohn Fastabend 	for (i = 0; i < 4; i++) {
30616962b24SJohn Fastabend 		*fds[i] = socket(AF_INET, SOCK_STREAM, 0);
30716962b24SJohn Fastabend 		if (*fds[i] < 0) {
30816962b24SJohn Fastabend 			perror("socket s1 failed()");
30916962b24SJohn Fastabend 			return errno;
31016962b24SJohn Fastabend 		}
31116962b24SJohn Fastabend 	}
31216962b24SJohn Fastabend 
31316962b24SJohn Fastabend 	/* Allow reuse */
31416962b24SJohn Fastabend 	for (i = 0; i < 2; i++) {
31516962b24SJohn Fastabend 		err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
31616962b24SJohn Fastabend 				 (char *)&one, sizeof(one));
31716962b24SJohn Fastabend 		if (err) {
31816962b24SJohn Fastabend 			perror("setsockopt failed()");
31916962b24SJohn Fastabend 			return errno;
32016962b24SJohn Fastabend 		}
32116962b24SJohn Fastabend 	}
32216962b24SJohn Fastabend 
32316962b24SJohn Fastabend 	/* Non-blocking sockets */
32416962b24SJohn Fastabend 	for (i = 0; i < 2; i++) {
32516962b24SJohn Fastabend 		err = ioctl(*fds[i], FIONBIO, (char *)&one);
32616962b24SJohn Fastabend 		if (err < 0) {
32716962b24SJohn Fastabend 			perror("ioctl s1 failed()");
32816962b24SJohn Fastabend 			return errno;
32916962b24SJohn Fastabend 		}
33016962b24SJohn Fastabend 	}
33116962b24SJohn Fastabend 
33216962b24SJohn Fastabend 	/* Bind server sockets */
33316962b24SJohn Fastabend 	memset(&addr, 0, sizeof(struct sockaddr_in));
33416962b24SJohn Fastabend 	addr.sin_family = AF_INET;
33516962b24SJohn Fastabend 	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
33616962b24SJohn Fastabend 
33716962b24SJohn Fastabend 	addr.sin_port = htons(S1_PORT);
33816962b24SJohn Fastabend 	err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
33916962b24SJohn Fastabend 	if (err < 0) {
340e5dc9dd3SJakub Kicinski 		perror("bind s1 failed()");
34116962b24SJohn Fastabend 		return errno;
34216962b24SJohn Fastabend 	}
34316962b24SJohn Fastabend 
34416962b24SJohn Fastabend 	addr.sin_port = htons(S2_PORT);
34516962b24SJohn Fastabend 	err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
34616962b24SJohn Fastabend 	if (err < 0) {
347e5dc9dd3SJakub Kicinski 		perror("bind s2 failed()");
34816962b24SJohn Fastabend 		return errno;
34916962b24SJohn Fastabend 	}
35016962b24SJohn Fastabend 
35116962b24SJohn Fastabend 	/* Listen server sockets */
35216962b24SJohn Fastabend 	addr.sin_port = htons(S1_PORT);
35316962b24SJohn Fastabend 	err = listen(s1, 32);
35416962b24SJohn Fastabend 	if (err < 0) {
355e5dc9dd3SJakub Kicinski 		perror("listen s1 failed()");
35616962b24SJohn Fastabend 		return errno;
35716962b24SJohn Fastabend 	}
35816962b24SJohn Fastabend 
35916962b24SJohn Fastabend 	addr.sin_port = htons(S2_PORT);
36016962b24SJohn Fastabend 	err = listen(s2, 32);
36116962b24SJohn Fastabend 	if (err < 0) {
362e5dc9dd3SJakub Kicinski 		perror("listen s1 failed()");
36316962b24SJohn Fastabend 		return errno;
36416962b24SJohn Fastabend 	}
36516962b24SJohn Fastabend 
36616962b24SJohn Fastabend 	/* Initiate Connect */
36716962b24SJohn Fastabend 	addr.sin_port = htons(S1_PORT);
36816962b24SJohn Fastabend 	err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
36916962b24SJohn Fastabend 	if (err < 0 && errno != EINPROGRESS) {
370e5dc9dd3SJakub Kicinski 		perror("connect c1 failed()");
37116962b24SJohn Fastabend 		return errno;
37216962b24SJohn Fastabend 	}
37316962b24SJohn Fastabend 
37416962b24SJohn Fastabend 	addr.sin_port = htons(S2_PORT);
37516962b24SJohn Fastabend 	err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
37616962b24SJohn Fastabend 	if (err < 0 && errno != EINPROGRESS) {
377e5dc9dd3SJakub Kicinski 		perror("connect c2 failed()");
37816962b24SJohn Fastabend 		return errno;
37916962b24SJohn Fastabend 	} else if (err < 0) {
38016962b24SJohn Fastabend 		err = 0;
38116962b24SJohn Fastabend 	}
38216962b24SJohn Fastabend 
38316962b24SJohn Fastabend 	/* Accept Connecrtions */
38416962b24SJohn Fastabend 	p1 = accept(s1, NULL, NULL);
38516962b24SJohn Fastabend 	if (p1 < 0) {
386e5dc9dd3SJakub Kicinski 		perror("accept s1 failed()");
38716962b24SJohn Fastabend 		return errno;
38816962b24SJohn Fastabend 	}
38916962b24SJohn Fastabend 
39016962b24SJohn Fastabend 	p2 = accept(s2, NULL, NULL);
39116962b24SJohn Fastabend 	if (p2 < 0) {
392e5dc9dd3SJakub Kicinski 		perror("accept s1 failed()");
39316962b24SJohn Fastabend 		return errno;
39416962b24SJohn Fastabend 	}
39516962b24SJohn Fastabend 
396b98ca90cSJohn Fastabend 	if (verbose > 1) {
39716962b24SJohn Fastabend 		printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
39816962b24SJohn Fastabend 		printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
39916962b24SJohn Fastabend 			c1, s1, c2, s2);
40016962b24SJohn Fastabend 	}
40116962b24SJohn Fastabend 	return 0;
40216962b24SJohn Fastabend }
40316962b24SJohn Fastabend 
40416962b24SJohn Fastabend struct msg_stats {
40516962b24SJohn Fastabend 	size_t bytes_sent;
40616962b24SJohn Fastabend 	size_t bytes_recvd;
40716962b24SJohn Fastabend 	struct timespec start;
40816962b24SJohn Fastabend 	struct timespec end;
40916962b24SJohn Fastabend };
41016962b24SJohn Fastabend 
41116962b24SJohn Fastabend static int msg_loop_sendpage(int fd, int iov_length, int cnt,
41216962b24SJohn Fastabend 			     struct msg_stats *s,
41316962b24SJohn Fastabend 			     struct sockmap_options *opt)
41416962b24SJohn Fastabend {
41516962b24SJohn Fastabend 	bool drop = opt->drop_expected;
41616962b24SJohn Fastabend 	unsigned char k = 0;
41716962b24SJohn Fastabend 	FILE *file;
41816962b24SJohn Fastabend 	int i, fp;
41916962b24SJohn Fastabend 
420c31dbb1eSLorenz Bauer 	file = tmpfile();
4214b67c515SJakub Kicinski 	if (!file) {
4224b67c515SJakub Kicinski 		perror("create file for sendpage");
4234b67c515SJakub Kicinski 		return 1;
4244b67c515SJakub Kicinski 	}
42516962b24SJohn Fastabend 	for (i = 0; i < iov_length * cnt; i++, k++)
42616962b24SJohn Fastabend 		fwrite(&k, sizeof(char), 1, file);
42716962b24SJohn Fastabend 	fflush(file);
42816962b24SJohn Fastabend 	fseek(file, 0, SEEK_SET);
42916962b24SJohn Fastabend 
430c31dbb1eSLorenz Bauer 	fp = fileno(file);
4314b67c515SJakub Kicinski 
43216962b24SJohn Fastabend 	clock_gettime(CLOCK_MONOTONIC, &s->start);
43316962b24SJohn Fastabend 	for (i = 0; i < cnt; i++) {
434248aba1dSJohn Fastabend 		int sent;
435248aba1dSJohn Fastabend 
436248aba1dSJohn Fastabend 		errno = 0;
437248aba1dSJohn Fastabend 		sent = sendfile(fd, fp, NULL, iov_length);
43816962b24SJohn Fastabend 
43916962b24SJohn Fastabend 		if (!drop && sent < 0) {
440248aba1dSJohn Fastabend 			perror("sendpage loop error");
441c31dbb1eSLorenz Bauer 			fclose(file);
44216962b24SJohn Fastabend 			return sent;
44316962b24SJohn Fastabend 		} else if (drop && sent >= 0) {
444248aba1dSJohn Fastabend 			printf("sendpage loop error expected: %i errno %i\n",
445248aba1dSJohn Fastabend 			       sent, errno);
446c31dbb1eSLorenz Bauer 			fclose(file);
44716962b24SJohn Fastabend 			return -EIO;
44816962b24SJohn Fastabend 		}
44916962b24SJohn Fastabend 
45016962b24SJohn Fastabend 		if (sent > 0)
45116962b24SJohn Fastabend 			s->bytes_sent += sent;
45216962b24SJohn Fastabend 	}
45316962b24SJohn Fastabend 	clock_gettime(CLOCK_MONOTONIC, &s->end);
454c31dbb1eSLorenz Bauer 	fclose(file);
45516962b24SJohn Fastabend 	return 0;
45616962b24SJohn Fastabend }
45716962b24SJohn Fastabend 
458753fb2eeSJohn Fastabend static void msg_free_iov(struct msghdr *msg)
45916962b24SJohn Fastabend {
460753fb2eeSJohn Fastabend 	int i;
461753fb2eeSJohn Fastabend 
462753fb2eeSJohn Fastabend 	for (i = 0; i < msg->msg_iovlen; i++)
463753fb2eeSJohn Fastabend 		free(msg->msg_iov[i].iov_base);
464753fb2eeSJohn Fastabend 	free(msg->msg_iov);
465753fb2eeSJohn Fastabend 	msg->msg_iov = NULL;
466753fb2eeSJohn Fastabend 	msg->msg_iovlen = 0;
467753fb2eeSJohn Fastabend }
468753fb2eeSJohn Fastabend 
469753fb2eeSJohn Fastabend static int msg_alloc_iov(struct msghdr *msg,
470753fb2eeSJohn Fastabend 			 int iov_count, int iov_length,
471753fb2eeSJohn Fastabend 			 bool data, bool xmit)
472753fb2eeSJohn Fastabend {
473753fb2eeSJohn Fastabend 	unsigned char k = 0;
47416962b24SJohn Fastabend 	struct iovec *iov;
475753fb2eeSJohn Fastabend 	int i;
47616962b24SJohn Fastabend 
47716962b24SJohn Fastabend 	iov = calloc(iov_count, sizeof(struct iovec));
47816962b24SJohn Fastabend 	if (!iov)
47916962b24SJohn Fastabend 		return errno;
48016962b24SJohn Fastabend 
48116962b24SJohn Fastabend 	for (i = 0; i < iov_count; i++) {
48216962b24SJohn Fastabend 		unsigned char *d = calloc(iov_length, sizeof(char));
48316962b24SJohn Fastabend 
48416962b24SJohn Fastabend 		if (!d) {
48516962b24SJohn Fastabend 			fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
486753fb2eeSJohn Fastabend 			goto unwind_iov;
48716962b24SJohn Fastabend 		}
48816962b24SJohn Fastabend 		iov[i].iov_base = d;
48916962b24SJohn Fastabend 		iov[i].iov_len = iov_length;
49016962b24SJohn Fastabend 
491753fb2eeSJohn Fastabend 		if (data && xmit) {
49216962b24SJohn Fastabend 			int j;
49316962b24SJohn Fastabend 
49416962b24SJohn Fastabend 			for (j = 0; j < iov_length; j++)
49516962b24SJohn Fastabend 				d[j] = k++;
49616962b24SJohn Fastabend 		}
49716962b24SJohn Fastabend 	}
49816962b24SJohn Fastabend 
499753fb2eeSJohn Fastabend 	msg->msg_iov = iov;
500753fb2eeSJohn Fastabend 	msg->msg_iovlen = iov_count;
501753fb2eeSJohn Fastabend 
502753fb2eeSJohn Fastabend 	return 0;
503753fb2eeSJohn Fastabend unwind_iov:
504753fb2eeSJohn Fastabend 	for (i--; i >= 0 ; i--)
505753fb2eeSJohn Fastabend 		free(msg->msg_iov[i].iov_base);
506753fb2eeSJohn Fastabend 	return -ENOMEM;
507753fb2eeSJohn Fastabend }
508753fb2eeSJohn Fastabend 
509753fb2eeSJohn Fastabend static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz)
510753fb2eeSJohn Fastabend {
511463bac5fSJohn Fastabend 	int i, j = 0, bytes_cnt = 0;
512753fb2eeSJohn Fastabend 	unsigned char k = 0;
513753fb2eeSJohn Fastabend 
514753fb2eeSJohn Fastabend 	for (i = 0; i < msg->msg_iovlen; i++) {
515753fb2eeSJohn Fastabend 		unsigned char *d = msg->msg_iov[i].iov_base;
516753fb2eeSJohn Fastabend 
517463bac5fSJohn Fastabend 		/* Special case test for skb ingress + ktls */
518463bac5fSJohn Fastabend 		if (i == 0 && txmsg_ktls_skb) {
519463bac5fSJohn Fastabend 			if (msg->msg_iov[i].iov_len < 4)
520463bac5fSJohn Fastabend 				return -EIO;
521463bac5fSJohn Fastabend 			if (txmsg_ktls_skb_redir) {
522463bac5fSJohn Fastabend 				if (memcmp(&d[13], "PASS", 4) != 0) {
523463bac5fSJohn Fastabend 					fprintf(stderr,
524463bac5fSJohn Fastabend 						"detected redirect ktls_skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[13], d[14], d[15], d[16]);
525463bac5fSJohn Fastabend 					return -EIO;
526463bac5fSJohn Fastabend 				}
527463bac5fSJohn Fastabend 				d[13] = 0;
528463bac5fSJohn Fastabend 				d[14] = 1;
529463bac5fSJohn Fastabend 				d[15] = 2;
530463bac5fSJohn Fastabend 				d[16] = 3;
531463bac5fSJohn Fastabend 				j = 13;
532463bac5fSJohn Fastabend 			} else if (txmsg_ktls_skb) {
533463bac5fSJohn Fastabend 				if (memcmp(d, "PASS", 4) != 0) {
534463bac5fSJohn Fastabend 					fprintf(stderr,
535463bac5fSJohn Fastabend 						"detected ktls_skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[0], d[1], d[2], d[3]);
536463bac5fSJohn Fastabend 					return -EIO;
537463bac5fSJohn Fastabend 				}
538463bac5fSJohn Fastabend 				d[0] = 0;
539463bac5fSJohn Fastabend 				d[1] = 1;
540463bac5fSJohn Fastabend 				d[2] = 2;
541463bac5fSJohn Fastabend 				d[3] = 3;
542463bac5fSJohn Fastabend 			}
543463bac5fSJohn Fastabend 		}
544463bac5fSJohn Fastabend 
545463bac5fSJohn Fastabend 		for (; j < msg->msg_iov[i].iov_len && size; j++) {
546753fb2eeSJohn Fastabend 			if (d[j] != k++) {
547753fb2eeSJohn Fastabend 				fprintf(stderr,
548753fb2eeSJohn Fastabend 					"detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
549753fb2eeSJohn Fastabend 					i, j, d[j], k - 1, d[j+1], k);
550753fb2eeSJohn Fastabend 				return -EIO;
551753fb2eeSJohn Fastabend 			}
552753fb2eeSJohn Fastabend 			bytes_cnt++;
553753fb2eeSJohn Fastabend 			if (bytes_cnt == chunk_sz) {
55416962b24SJohn Fastabend 				k = 0;
555753fb2eeSJohn Fastabend 				bytes_cnt = 0;
556753fb2eeSJohn Fastabend 			}
557753fb2eeSJohn Fastabend 			size--;
558753fb2eeSJohn Fastabend 		}
559753fb2eeSJohn Fastabend 	}
560753fb2eeSJohn Fastabend 	return 0;
561753fb2eeSJohn Fastabend }
562753fb2eeSJohn Fastabend 
563753fb2eeSJohn Fastabend static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
564753fb2eeSJohn Fastabend 		    struct msg_stats *s, bool tx,
565753fb2eeSJohn Fastabend 		    struct sockmap_options *opt)
566753fb2eeSJohn Fastabend {
567753fb2eeSJohn Fastabend 	struct msghdr msg = {0}, msg_peek = {0};
568753fb2eeSJohn Fastabend 	int err, i, flags = MSG_NOSIGNAL;
569753fb2eeSJohn Fastabend 	bool drop = opt->drop_expected;
570753fb2eeSJohn Fastabend 	bool data = opt->data_test;
571753fb2eeSJohn Fastabend 
572753fb2eeSJohn Fastabend 	err = msg_alloc_iov(&msg, iov_count, iov_length, data, tx);
573753fb2eeSJohn Fastabend 	if (err)
574753fb2eeSJohn Fastabend 		goto out_errno;
575753fb2eeSJohn Fastabend 	if (peek_flag) {
576753fb2eeSJohn Fastabend 		err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx);
577753fb2eeSJohn Fastabend 		if (err)
578753fb2eeSJohn Fastabend 			goto out_errno;
579753fb2eeSJohn Fastabend 	}
58016962b24SJohn Fastabend 
58116962b24SJohn Fastabend 	if (tx) {
58216962b24SJohn Fastabend 		clock_gettime(CLOCK_MONOTONIC, &s->start);
58316962b24SJohn Fastabend 		for (i = 0; i < cnt; i++) {
584248aba1dSJohn Fastabend 			int sent;
585248aba1dSJohn Fastabend 
586248aba1dSJohn Fastabend 			errno = 0;
587248aba1dSJohn Fastabend 			sent = sendmsg(fd, &msg, flags);
58816962b24SJohn Fastabend 
58916962b24SJohn Fastabend 			if (!drop && sent < 0) {
590248aba1dSJohn Fastabend 				perror("sendmsg loop error");
59116962b24SJohn Fastabend 				goto out_errno;
59216962b24SJohn Fastabend 			} else if (drop && sent >= 0) {
593248aba1dSJohn Fastabend 				fprintf(stderr,
594248aba1dSJohn Fastabend 					"sendmsg loop error expected: %i errno %i\n",
595248aba1dSJohn Fastabend 					sent, errno);
59616962b24SJohn Fastabend 				errno = -EIO;
59716962b24SJohn Fastabend 				goto out_errno;
59816962b24SJohn Fastabend 			}
59916962b24SJohn Fastabend 			if (sent > 0)
60016962b24SJohn Fastabend 				s->bytes_sent += sent;
60116962b24SJohn Fastabend 		}
60216962b24SJohn Fastabend 		clock_gettime(CLOCK_MONOTONIC, &s->end);
60316962b24SJohn Fastabend 	} else {
604753fb2eeSJohn Fastabend 		int slct, recvp = 0, recv, max_fd = fd;
6051ade9abaSJohn Fastabend 		float total_bytes, txmsg_pop_total;
60616962b24SJohn Fastabend 		int fd_flags = O_NONBLOCK;
60716962b24SJohn Fastabend 		struct timeval timeout;
60816962b24SJohn Fastabend 		fd_set w;
60916962b24SJohn Fastabend 
61016962b24SJohn Fastabend 		fcntl(fd, fd_flags);
6111ade9abaSJohn Fastabend 		/* Account for pop bytes noting each iteration of apply will
6121ade9abaSJohn Fastabend 		 * call msg_pop_data helper so we need to account for this
6131ade9abaSJohn Fastabend 		 * by calculating the number of apply iterations. Note user
6141ade9abaSJohn Fastabend 		 * of the tool can create cases where no data is sent by
6151ade9abaSJohn Fastabend 		 * manipulating pop/push/pull/etc. For example txmsg_apply 1
6161ade9abaSJohn Fastabend 		 * with txmsg_pop 1 will try to apply 1B at a time but each
6171ade9abaSJohn Fastabend 		 * iteration will then pop 1B so no data will ever be sent.
6181ade9abaSJohn Fastabend 		 * This is really only useful for testing edge cases in code
6191ade9abaSJohn Fastabend 		 * paths.
6201ade9abaSJohn Fastabend 		 */
62116962b24SJohn Fastabend 		total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
6221ade9abaSJohn Fastabend 		if (txmsg_apply)
62318d4e900SJohn Fastabend 			txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply);
62418d4e900SJohn Fastabend 		else
62518d4e900SJohn Fastabend 			txmsg_pop_total = txmsg_pop * cnt;
6261ade9abaSJohn Fastabend 		total_bytes -= txmsg_pop_total;
62716962b24SJohn Fastabend 		err = clock_gettime(CLOCK_MONOTONIC, &s->start);
62816962b24SJohn Fastabend 		if (err < 0)
629e5dc9dd3SJakub Kicinski 			perror("recv start time");
63016962b24SJohn Fastabend 		while (s->bytes_recvd < total_bytes) {
631a009f1f3SPrashant Bhole 			if (txmsg_cork) {
632a18fda1aSJohn Fastabend 				timeout.tv_sec = 0;
6333c6ed988SDaniel Borkmann 				timeout.tv_usec = 300000;
634a009f1f3SPrashant Bhole 			} else {
6351ade9abaSJohn Fastabend 				timeout.tv_sec = 3;
636a009f1f3SPrashant Bhole 				timeout.tv_usec = 0;
637a009f1f3SPrashant Bhole 			}
63816962b24SJohn Fastabend 
63916962b24SJohn Fastabend 			/* FD sets */
64016962b24SJohn Fastabend 			FD_ZERO(&w);
64116962b24SJohn Fastabend 			FD_SET(fd, &w);
64216962b24SJohn Fastabend 
64316962b24SJohn Fastabend 			slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
64416962b24SJohn Fastabend 			if (slct == -1) {
64516962b24SJohn Fastabend 				perror("select()");
64616962b24SJohn Fastabend 				clock_gettime(CLOCK_MONOTONIC, &s->end);
64716962b24SJohn Fastabend 				goto out_errno;
64816962b24SJohn Fastabend 			} else if (!slct) {
64916962b24SJohn Fastabend 				if (opt->verbose)
6501ade9abaSJohn Fastabend 					fprintf(stderr, "unexpected timeout: recved %zu/%f pop_total %f\n", s->bytes_recvd, total_bytes, txmsg_pop_total);
65116962b24SJohn Fastabend 				errno = -EIO;
65216962b24SJohn Fastabend 				clock_gettime(CLOCK_MONOTONIC, &s->end);
65316962b24SJohn Fastabend 				goto out_errno;
65416962b24SJohn Fastabend 			}
65516962b24SJohn Fastabend 
656753fb2eeSJohn Fastabend 			errno = 0;
657753fb2eeSJohn Fastabend 			if (peek_flag) {
658753fb2eeSJohn Fastabend 				flags |= MSG_PEEK;
659753fb2eeSJohn Fastabend 				recvp = recvmsg(fd, &msg_peek, flags);
660753fb2eeSJohn Fastabend 				if (recvp < 0) {
661753fb2eeSJohn Fastabend 					if (errno != EWOULDBLOCK) {
662753fb2eeSJohn Fastabend 						clock_gettime(CLOCK_MONOTONIC, &s->end);
663753fb2eeSJohn Fastabend 						goto out_errno;
664753fb2eeSJohn Fastabend 					}
665753fb2eeSJohn Fastabend 				}
666753fb2eeSJohn Fastabend 				flags = 0;
667753fb2eeSJohn Fastabend 			}
668753fb2eeSJohn Fastabend 
66916962b24SJohn Fastabend 			recv = recvmsg(fd, &msg, flags);
67016962b24SJohn Fastabend 			if (recv < 0) {
67116962b24SJohn Fastabend 				if (errno != EWOULDBLOCK) {
67216962b24SJohn Fastabend 					clock_gettime(CLOCK_MONOTONIC, &s->end);
673e5dc9dd3SJakub Kicinski 					perror("recv failed()");
67416962b24SJohn Fastabend 					goto out_errno;
67516962b24SJohn Fastabend 				}
67616962b24SJohn Fastabend 			}
67716962b24SJohn Fastabend 
67816962b24SJohn Fastabend 			s->bytes_recvd += recv;
67916962b24SJohn Fastabend 
680753fb2eeSJohn Fastabend 			if (data) {
681753fb2eeSJohn Fastabend 				int chunk_sz = opt->sendpage ?
682753fb2eeSJohn Fastabend 						iov_length * cnt :
683753fb2eeSJohn Fastabend 						iov_length * iov_count;
68416962b24SJohn Fastabend 
685753fb2eeSJohn Fastabend 				errno = msg_verify_data(&msg, recv, chunk_sz);
686753fb2eeSJohn Fastabend 				if (errno) {
687e5dc9dd3SJakub Kicinski 					perror("data verify msg failed");
68816962b24SJohn Fastabend 					goto out_errno;
68916962b24SJohn Fastabend 				}
690753fb2eeSJohn Fastabend 				if (recvp) {
691753fb2eeSJohn Fastabend 					errno = msg_verify_data(&msg_peek,
692753fb2eeSJohn Fastabend 								recvp,
693753fb2eeSJohn Fastabend 								chunk_sz);
694753fb2eeSJohn Fastabend 					if (errno) {
695e5dc9dd3SJakub Kicinski 						perror("data verify msg_peek failed");
696753fb2eeSJohn Fastabend 						goto out_errno;
69716962b24SJohn Fastabend 					}
69816962b24SJohn Fastabend 				}
69916962b24SJohn Fastabend 			}
70016962b24SJohn Fastabend 		}
70116962b24SJohn Fastabend 		clock_gettime(CLOCK_MONOTONIC, &s->end);
70216962b24SJohn Fastabend 	}
70316962b24SJohn Fastabend 
704753fb2eeSJohn Fastabend 	msg_free_iov(&msg);
705753fb2eeSJohn Fastabend 	msg_free_iov(&msg_peek);
706753fb2eeSJohn Fastabend 	return err;
70716962b24SJohn Fastabend out_errno:
708753fb2eeSJohn Fastabend 	msg_free_iov(&msg);
709753fb2eeSJohn Fastabend 	msg_free_iov(&msg_peek);
71016962b24SJohn Fastabend 	return errno;
71116962b24SJohn Fastabend }
71216962b24SJohn Fastabend 
71316962b24SJohn Fastabend static float giga = 1000000000;
71416962b24SJohn Fastabend 
71516962b24SJohn Fastabend static inline float sentBps(struct msg_stats s)
71616962b24SJohn Fastabend {
71716962b24SJohn Fastabend 	return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
71816962b24SJohn Fastabend }
71916962b24SJohn Fastabend 
72016962b24SJohn Fastabend static inline float recvdBps(struct msg_stats s)
72116962b24SJohn Fastabend {
72216962b24SJohn Fastabend 	return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
72316962b24SJohn Fastabend }
72416962b24SJohn Fastabend 
72516962b24SJohn Fastabend static int sendmsg_test(struct sockmap_options *opt)
72616962b24SJohn Fastabend {
72716962b24SJohn Fastabend 	float sent_Bps = 0, recvd_Bps = 0;
72816962b24SJohn Fastabend 	int rx_fd, txpid, rxpid, err = 0;
72916962b24SJohn Fastabend 	struct msg_stats s = {0};
73016962b24SJohn Fastabend 	int iov_count = opt->iov_count;
73116962b24SJohn Fastabend 	int iov_buf = opt->iov_length;
73216edddfeSPrashant Bhole 	int rx_status, tx_status;
73316962b24SJohn Fastabend 	int cnt = opt->rate;
73416962b24SJohn Fastabend 
73516962b24SJohn Fastabend 	errno = 0;
73616962b24SJohn Fastabend 
73716962b24SJohn Fastabend 	if (opt->base)
73816962b24SJohn Fastabend 		rx_fd = p1;
73916962b24SJohn Fastabend 	else
74016962b24SJohn Fastabend 		rx_fd = p2;
74116962b24SJohn Fastabend 
742e9dd9047SJohn Fastabend 	if (ktls) {
743e9dd9047SJohn Fastabend 		/* Redirecting into non-TLS socket which sends into a TLS
744e9dd9047SJohn Fastabend 		 * socket is not a valid test. So in this case lets not
745e9dd9047SJohn Fastabend 		 * enable kTLS but still run the test.
746e9dd9047SJohn Fastabend 		 */
747e9dd9047SJohn Fastabend 		if (!txmsg_redir || (txmsg_redir && txmsg_ingress)) {
748e9dd9047SJohn Fastabend 			err = sockmap_init_ktls(opt->verbose, rx_fd);
749e9dd9047SJohn Fastabend 			if (err)
750e9dd9047SJohn Fastabend 				return err;
751e9dd9047SJohn Fastabend 		}
752e9dd9047SJohn Fastabend 		err = sockmap_init_ktls(opt->verbose, c1);
753e9dd9047SJohn Fastabend 		if (err)
754e9dd9047SJohn Fastabend 			return err;
755e9dd9047SJohn Fastabend 	}
756e9dd9047SJohn Fastabend 
75716962b24SJohn Fastabend 	rxpid = fork();
75816962b24SJohn Fastabend 	if (rxpid == 0) {
75918d4e900SJohn Fastabend 		iov_buf -= (txmsg_pop - txmsg_start_pop + 1);
760463bac5fSJohn Fastabend 		if (opt->drop_expected || txmsg_ktls_skb_drop)
76118d4e900SJohn Fastabend 			_exit(0);
76218d4e900SJohn Fastabend 
76318d4e900SJohn Fastabend 		if (!iov_buf) /* zero bytes sent case */
76418d4e900SJohn Fastabend 			_exit(0);
76516962b24SJohn Fastabend 
76616962b24SJohn Fastabend 		if (opt->sendpage)
76716962b24SJohn Fastabend 			iov_count = 1;
76816962b24SJohn Fastabend 		err = msg_loop(rx_fd, iov_count, iov_buf,
76916962b24SJohn Fastabend 			       cnt, &s, false, opt);
770b98ca90cSJohn Fastabend 		if (opt->verbose > 1)
77116962b24SJohn Fastabend 			fprintf(stderr,
77216962b24SJohn Fastabend 				"msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
77316962b24SJohn Fastabend 				iov_count, iov_buf, cnt, err);
77416962b24SJohn Fastabend 		if (s.end.tv_sec - s.start.tv_sec) {
77516962b24SJohn Fastabend 			sent_Bps = sentBps(s);
77616962b24SJohn Fastabend 			recvd_Bps = recvdBps(s);
77716962b24SJohn Fastabend 		}
778b98ca90cSJohn Fastabend 		if (opt->verbose > 1)
77916962b24SJohn Fastabend 			fprintf(stdout,
780753fb2eeSJohn Fastabend 				"rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n",
78116962b24SJohn Fastabend 				s.bytes_sent, sent_Bps, sent_Bps/giga,
782753fb2eeSJohn Fastabend 				s.bytes_recvd, recvd_Bps, recvd_Bps/giga,
783753fb2eeSJohn Fastabend 				peek_flag ? "(peek_msg)" : "");
78416edddfeSPrashant Bhole 		if (err && txmsg_cork)
78516edddfeSPrashant Bhole 			err = 0;
78616edddfeSPrashant Bhole 		exit(err ? 1 : 0);
78716962b24SJohn Fastabend 	} else if (rxpid == -1) {
788e5dc9dd3SJakub Kicinski 		perror("msg_loop_rx");
78916962b24SJohn Fastabend 		return errno;
79016962b24SJohn Fastabend 	}
79116962b24SJohn Fastabend 
79216962b24SJohn Fastabend 	txpid = fork();
79316962b24SJohn Fastabend 	if (txpid == 0) {
79416962b24SJohn Fastabend 		if (opt->sendpage)
79516962b24SJohn Fastabend 			err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
79616962b24SJohn Fastabend 		else
79716962b24SJohn Fastabend 			err = msg_loop(c1, iov_count, iov_buf,
79816962b24SJohn Fastabend 				       cnt, &s, true, opt);
79916962b24SJohn Fastabend 
80016962b24SJohn Fastabend 		if (err)
80116962b24SJohn Fastabend 			fprintf(stderr,
80216962b24SJohn Fastabend 				"msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
80316962b24SJohn Fastabend 				iov_count, iov_buf, cnt, err);
80416962b24SJohn Fastabend 		if (s.end.tv_sec - s.start.tv_sec) {
80516962b24SJohn Fastabend 			sent_Bps = sentBps(s);
80616962b24SJohn Fastabend 			recvd_Bps = recvdBps(s);
80716962b24SJohn Fastabend 		}
808b98ca90cSJohn Fastabend 		if (opt->verbose > 1)
80916962b24SJohn Fastabend 			fprintf(stdout,
81016962b24SJohn Fastabend 				"tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
81116962b24SJohn Fastabend 				s.bytes_sent, sent_Bps, sent_Bps/giga,
81216962b24SJohn Fastabend 				s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
81316edddfeSPrashant Bhole 		exit(err ? 1 : 0);
81416962b24SJohn Fastabend 	} else if (txpid == -1) {
815e5dc9dd3SJakub Kicinski 		perror("msg_loop_tx");
81616962b24SJohn Fastabend 		return errno;
81716962b24SJohn Fastabend 	}
81816962b24SJohn Fastabend 
81916edddfeSPrashant Bhole 	assert(waitpid(rxpid, &rx_status, 0) == rxpid);
82016edddfeSPrashant Bhole 	assert(waitpid(txpid, &tx_status, 0) == txpid);
82116edddfeSPrashant Bhole 	if (WIFEXITED(rx_status)) {
82216edddfeSPrashant Bhole 		err = WEXITSTATUS(rx_status);
82316edddfeSPrashant Bhole 		if (err) {
824248aba1dSJohn Fastabend 			fprintf(stderr, "rx thread exited with err %d.\n", err);
82516edddfeSPrashant Bhole 			goto out;
82616edddfeSPrashant Bhole 		}
82716edddfeSPrashant Bhole 	}
82816edddfeSPrashant Bhole 	if (WIFEXITED(tx_status)) {
82916edddfeSPrashant Bhole 		err = WEXITSTATUS(tx_status);
83016edddfeSPrashant Bhole 		if (err)
831248aba1dSJohn Fastabend 			fprintf(stderr, "tx thread exited with err %d.\n", err);
83216edddfeSPrashant Bhole 	}
83316edddfeSPrashant Bhole out:
83416962b24SJohn Fastabend 	return err;
83516962b24SJohn Fastabend }
83616962b24SJohn Fastabend 
83716962b24SJohn Fastabend static int forever_ping_pong(int rate, struct sockmap_options *opt)
83816962b24SJohn Fastabend {
83916962b24SJohn Fastabend 	struct timeval timeout;
84016962b24SJohn Fastabend 	char buf[1024] = {0};
84116962b24SJohn Fastabend 	int sc;
84216962b24SJohn Fastabend 
84316962b24SJohn Fastabend 	timeout.tv_sec = 10;
84416962b24SJohn Fastabend 	timeout.tv_usec = 0;
84516962b24SJohn Fastabend 
84616962b24SJohn Fastabend 	/* Ping/Pong data from client to server */
84716962b24SJohn Fastabend 	sc = send(c1, buf, sizeof(buf), 0);
84816962b24SJohn Fastabend 	if (sc < 0) {
849e5dc9dd3SJakub Kicinski 		perror("send failed()");
85016962b24SJohn Fastabend 		return sc;
85116962b24SJohn Fastabend 	}
85216962b24SJohn Fastabend 
85316962b24SJohn Fastabend 	do {
85416962b24SJohn Fastabend 		int s, rc, i, max_fd = p2;
85516962b24SJohn Fastabend 		fd_set w;
85616962b24SJohn Fastabend 
85716962b24SJohn Fastabend 		/* FD sets */
85816962b24SJohn Fastabend 		FD_ZERO(&w);
85916962b24SJohn Fastabend 		FD_SET(c1, &w);
86016962b24SJohn Fastabend 		FD_SET(c2, &w);
86116962b24SJohn Fastabend 		FD_SET(p1, &w);
86216962b24SJohn Fastabend 		FD_SET(p2, &w);
86316962b24SJohn Fastabend 
86416962b24SJohn Fastabend 		s = select(max_fd + 1, &w, NULL, NULL, &timeout);
86516962b24SJohn Fastabend 		if (s == -1) {
86616962b24SJohn Fastabend 			perror("select()");
86716962b24SJohn Fastabend 			break;
86816962b24SJohn Fastabend 		} else if (!s) {
86916962b24SJohn Fastabend 			fprintf(stderr, "unexpected timeout\n");
87016962b24SJohn Fastabend 			break;
87116962b24SJohn Fastabend 		}
87216962b24SJohn Fastabend 
87316962b24SJohn Fastabend 		for (i = 0; i <= max_fd && s > 0; ++i) {
87416962b24SJohn Fastabend 			if (!FD_ISSET(i, &w))
87516962b24SJohn Fastabend 				continue;
87616962b24SJohn Fastabend 
87716962b24SJohn Fastabend 			s--;
87816962b24SJohn Fastabend 
87916962b24SJohn Fastabend 			rc = recv(i, buf, sizeof(buf), 0);
88016962b24SJohn Fastabend 			if (rc < 0) {
88116962b24SJohn Fastabend 				if (errno != EWOULDBLOCK) {
882e5dc9dd3SJakub Kicinski 					perror("recv failed()");
88316962b24SJohn Fastabend 					return rc;
88416962b24SJohn Fastabend 				}
88516962b24SJohn Fastabend 			}
88616962b24SJohn Fastabend 
88716962b24SJohn Fastabend 			if (rc == 0) {
88816962b24SJohn Fastabend 				close(i);
88916962b24SJohn Fastabend 				break;
89016962b24SJohn Fastabend 			}
89116962b24SJohn Fastabend 
89216962b24SJohn Fastabend 			sc = send(i, buf, rc, 0);
89316962b24SJohn Fastabend 			if (sc < 0) {
894e5dc9dd3SJakub Kicinski 				perror("send failed()");
89516962b24SJohn Fastabend 				return sc;
89616962b24SJohn Fastabend 			}
89716962b24SJohn Fastabend 		}
89816962b24SJohn Fastabend 
89916962b24SJohn Fastabend 		if (rate)
90016962b24SJohn Fastabend 			sleep(rate);
90116962b24SJohn Fastabend 
90216962b24SJohn Fastabend 		if (opt->verbose) {
90316962b24SJohn Fastabend 			printf(".");
90416962b24SJohn Fastabend 			fflush(stdout);
90516962b24SJohn Fastabend 
90616962b24SJohn Fastabend 		}
90716962b24SJohn Fastabend 	} while (running);
90816962b24SJohn Fastabend 
90916962b24SJohn Fastabend 	return 0;
91016962b24SJohn Fastabend }
91116962b24SJohn Fastabend 
91216962b24SJohn Fastabend enum {
913b98ca90cSJohn Fastabend 	SELFTESTS,
91416962b24SJohn Fastabend 	PING_PONG,
91516962b24SJohn Fastabend 	SENDMSG,
91616962b24SJohn Fastabend 	BASE,
91716962b24SJohn Fastabend 	BASE_SENDPAGE,
91816962b24SJohn Fastabend 	SENDPAGE,
91916962b24SJohn Fastabend };
92016962b24SJohn Fastabend 
92116962b24SJohn Fastabend static int run_options(struct sockmap_options *options, int cg_fd,  int test)
92216962b24SJohn Fastabend {
92316962b24SJohn Fastabend 	int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
92416962b24SJohn Fastabend 
92516962b24SJohn Fastabend 	/* If base test skip BPF setup */
92616962b24SJohn Fastabend 	if (test == BASE || test == BASE_SENDPAGE)
92716962b24SJohn Fastabend 		goto run;
92816962b24SJohn Fastabend 
92916962b24SJohn Fastabend 	/* Attach programs to sockmap */
93016962b24SJohn Fastabend 	err = bpf_prog_attach(prog_fd[0], map_fd[0],
93116962b24SJohn Fastabend 				BPF_SK_SKB_STREAM_PARSER, 0);
93216962b24SJohn Fastabend 	if (err) {
93316962b24SJohn Fastabend 		fprintf(stderr,
93416962b24SJohn Fastabend 			"ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
93516962b24SJohn Fastabend 			prog_fd[0], map_fd[0], err, strerror(errno));
93616962b24SJohn Fastabend 		return err;
93716962b24SJohn Fastabend 	}
93816962b24SJohn Fastabend 
93916962b24SJohn Fastabend 	err = bpf_prog_attach(prog_fd[1], map_fd[0],
94016962b24SJohn Fastabend 				BPF_SK_SKB_STREAM_VERDICT, 0);
94116962b24SJohn Fastabend 	if (err) {
94216962b24SJohn Fastabend 		fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
94316962b24SJohn Fastabend 			err, strerror(errno));
94416962b24SJohn Fastabend 		return err;
94516962b24SJohn Fastabend 	}
94616962b24SJohn Fastabend 
947463bac5fSJohn Fastabend 	/* Attach programs to TLS sockmap */
948463bac5fSJohn Fastabend 	if (txmsg_ktls_skb) {
949463bac5fSJohn Fastabend 		err = bpf_prog_attach(prog_fd[0], map_fd[8],
950463bac5fSJohn Fastabend 					BPF_SK_SKB_STREAM_PARSER, 0);
951463bac5fSJohn Fastabend 		if (err) {
952463bac5fSJohn Fastabend 			fprintf(stderr,
953463bac5fSJohn Fastabend 				"ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n",
954463bac5fSJohn Fastabend 				prog_fd[0], map_fd[8], err, strerror(errno));
955463bac5fSJohn Fastabend 			return err;
956463bac5fSJohn Fastabend 		}
957463bac5fSJohn Fastabend 
958463bac5fSJohn Fastabend 		err = bpf_prog_attach(prog_fd[2], map_fd[8],
959463bac5fSJohn Fastabend 				      BPF_SK_SKB_STREAM_VERDICT, 0);
960463bac5fSJohn Fastabend 		if (err) {
961463bac5fSJohn Fastabend 			fprintf(stderr, "ERROR: bpf_prog_attach (TLS sockmap): %d (%s)\n",
962463bac5fSJohn Fastabend 				err, strerror(errno));
963463bac5fSJohn Fastabend 			return err;
964463bac5fSJohn Fastabend 		}
965463bac5fSJohn Fastabend 	}
966463bac5fSJohn Fastabend 
96716962b24SJohn Fastabend 	/* Attach to cgroups */
968463bac5fSJohn Fastabend 	err = bpf_prog_attach(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
96916962b24SJohn Fastabend 	if (err) {
97016962b24SJohn Fastabend 		fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
97116962b24SJohn Fastabend 			err, strerror(errno));
97216962b24SJohn Fastabend 		return err;
97316962b24SJohn Fastabend 	}
97416962b24SJohn Fastabend 
97516962b24SJohn Fastabend run:
97616962b24SJohn Fastabend 	err = sockmap_init_sockets(options->verbose);
97716962b24SJohn Fastabend 	if (err) {
97816962b24SJohn Fastabend 		fprintf(stderr, "ERROR: test socket failed: %d\n", err);
97916962b24SJohn Fastabend 		goto out;
98016962b24SJohn Fastabend 	}
98116962b24SJohn Fastabend 
98216962b24SJohn Fastabend 	/* Attach txmsg program to sockmap */
98316962b24SJohn Fastabend 	if (txmsg_pass)
984d79a3212SJohn Fastabend 		tx_prog_fd = prog_fd[4];
985463bac5fSJohn Fastabend 	else if (txmsg_redir)
98616962b24SJohn Fastabend 		tx_prog_fd = prog_fd[5];
987463bac5fSJohn Fastabend 	else if (txmsg_apply)
98816962b24SJohn Fastabend 		tx_prog_fd = prog_fd[6];
989463bac5fSJohn Fastabend 	else if (txmsg_cork)
99016962b24SJohn Fastabend 		tx_prog_fd = prog_fd[7];
991463bac5fSJohn Fastabend 	else if (txmsg_drop)
992463bac5fSJohn Fastabend 		tx_prog_fd = prog_fd[8];
99316962b24SJohn Fastabend 	else
99416962b24SJohn Fastabend 		tx_prog_fd = 0;
99516962b24SJohn Fastabend 
99616962b24SJohn Fastabend 	if (tx_prog_fd) {
99716962b24SJohn Fastabend 		int redir_fd, i = 0;
99816962b24SJohn Fastabend 
99916962b24SJohn Fastabend 		err = bpf_prog_attach(tx_prog_fd,
100016962b24SJohn Fastabend 				      map_fd[1], BPF_SK_MSG_VERDICT, 0);
100116962b24SJohn Fastabend 		if (err) {
100216962b24SJohn Fastabend 			fprintf(stderr,
100316962b24SJohn Fastabend 				"ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
100416962b24SJohn Fastabend 				err, strerror(errno));
100516962b24SJohn Fastabend 			goto out;
100616962b24SJohn Fastabend 		}
100716962b24SJohn Fastabend 
100816962b24SJohn Fastabend 		err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
100916962b24SJohn Fastabend 		if (err) {
101016962b24SJohn Fastabend 			fprintf(stderr,
101116962b24SJohn Fastabend 				"ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
101216962b24SJohn Fastabend 				err, strerror(errno));
101316962b24SJohn Fastabend 			goto out;
101416962b24SJohn Fastabend 		}
101516962b24SJohn Fastabend 
1016d79a3212SJohn Fastabend 		if (txmsg_redir)
101716962b24SJohn Fastabend 			redir_fd = c2;
101816962b24SJohn Fastabend 		else
101916962b24SJohn Fastabend 			redir_fd = c1;
102016962b24SJohn Fastabend 
102116962b24SJohn Fastabend 		err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
102216962b24SJohn Fastabend 		if (err) {
102316962b24SJohn Fastabend 			fprintf(stderr,
102416962b24SJohn Fastabend 				"ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
102516962b24SJohn Fastabend 				err, strerror(errno));
102616962b24SJohn Fastabend 			goto out;
102716962b24SJohn Fastabend 		}
102816962b24SJohn Fastabend 
102916962b24SJohn Fastabend 		if (txmsg_apply) {
103016962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[3],
103116962b24SJohn Fastabend 						  &i, &txmsg_apply, BPF_ANY);
103216962b24SJohn Fastabend 			if (err) {
103316962b24SJohn Fastabend 				fprintf(stderr,
103416962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (apply_bytes):  %d (%s\n",
103516962b24SJohn Fastabend 					err, strerror(errno));
103616962b24SJohn Fastabend 				goto out;
103716962b24SJohn Fastabend 			}
103816962b24SJohn Fastabend 		}
103916962b24SJohn Fastabend 
104016962b24SJohn Fastabend 		if (txmsg_cork) {
104116962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[4],
104216962b24SJohn Fastabend 						  &i, &txmsg_cork, BPF_ANY);
104316962b24SJohn Fastabend 			if (err) {
104416962b24SJohn Fastabend 				fprintf(stderr,
104516962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (cork_bytes):  %d (%s\n",
104616962b24SJohn Fastabend 					err, strerror(errno));
104716962b24SJohn Fastabend 				goto out;
104816962b24SJohn Fastabend 			}
104916962b24SJohn Fastabend 		}
105016962b24SJohn Fastabend 
105116962b24SJohn Fastabend 		if (txmsg_start) {
105216962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[5],
105316962b24SJohn Fastabend 						  &i, &txmsg_start, BPF_ANY);
105416962b24SJohn Fastabend 			if (err) {
105516962b24SJohn Fastabend 				fprintf(stderr,
105616962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (txmsg_start):  %d (%s)\n",
105716962b24SJohn Fastabend 					err, strerror(errno));
105816962b24SJohn Fastabend 				goto out;
105916962b24SJohn Fastabend 			}
106016962b24SJohn Fastabend 		}
106116962b24SJohn Fastabend 
106216962b24SJohn Fastabend 		if (txmsg_end) {
106316962b24SJohn Fastabend 			i = 1;
106416962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[5],
106516962b24SJohn Fastabend 						  &i, &txmsg_end, BPF_ANY);
106616962b24SJohn Fastabend 			if (err) {
106716962b24SJohn Fastabend 				fprintf(stderr,
106816962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (txmsg_end):  %d (%s)\n",
106916962b24SJohn Fastabend 					err, strerror(errno));
107016962b24SJohn Fastabend 				goto out;
107116962b24SJohn Fastabend 			}
107216962b24SJohn Fastabend 		}
107316962b24SJohn Fastabend 
107484fbfe02SJohn Fastabend 		if (txmsg_start_push) {
107584fbfe02SJohn Fastabend 			i = 2;
107684fbfe02SJohn Fastabend 			err = bpf_map_update_elem(map_fd[5],
107784fbfe02SJohn Fastabend 						  &i, &txmsg_start_push, BPF_ANY);
107884fbfe02SJohn Fastabend 			if (err) {
107984fbfe02SJohn Fastabend 				fprintf(stderr,
108084fbfe02SJohn Fastabend 					"ERROR: bpf_map_update_elem (txmsg_start_push):  %d (%s)\n",
108184fbfe02SJohn Fastabend 					err, strerror(errno));
108284fbfe02SJohn Fastabend 				goto out;
108384fbfe02SJohn Fastabend 			}
108484fbfe02SJohn Fastabend 		}
108584fbfe02SJohn Fastabend 
108684fbfe02SJohn Fastabend 		if (txmsg_end_push) {
108784fbfe02SJohn Fastabend 			i = 3;
108884fbfe02SJohn Fastabend 			err = bpf_map_update_elem(map_fd[5],
108984fbfe02SJohn Fastabend 						  &i, &txmsg_end_push, BPF_ANY);
109084fbfe02SJohn Fastabend 			if (err) {
109184fbfe02SJohn Fastabend 				fprintf(stderr,
109284fbfe02SJohn Fastabend 					"ERROR: bpf_map_update_elem %i@%i (txmsg_end_push):  %d (%s)\n",
109384fbfe02SJohn Fastabend 					txmsg_end_push, i, err, strerror(errno));
109484fbfe02SJohn Fastabend 				goto out;
109584fbfe02SJohn Fastabend 			}
109684fbfe02SJohn Fastabend 		}
109784fbfe02SJohn Fastabend 
10981ade9abaSJohn Fastabend 		if (txmsg_start_pop) {
10991ade9abaSJohn Fastabend 			i = 4;
11001ade9abaSJohn Fastabend 			err = bpf_map_update_elem(map_fd[5],
11011ade9abaSJohn Fastabend 						  &i, &txmsg_start_pop, BPF_ANY);
11021ade9abaSJohn Fastabend 			if (err) {
11031ade9abaSJohn Fastabend 				fprintf(stderr,
11041ade9abaSJohn Fastabend 					"ERROR: bpf_map_update_elem %i@%i (txmsg_start_pop):  %d (%s)\n",
11051ade9abaSJohn Fastabend 					txmsg_start_pop, i, err, strerror(errno));
11061ade9abaSJohn Fastabend 				goto out;
11071ade9abaSJohn Fastabend 			}
11081ade9abaSJohn Fastabend 		} else {
11091ade9abaSJohn Fastabend 			i = 4;
11101ade9abaSJohn Fastabend 			bpf_map_update_elem(map_fd[5],
11111ade9abaSJohn Fastabend 						  &i, &txmsg_start_pop, BPF_ANY);
11121ade9abaSJohn Fastabend 		}
11131ade9abaSJohn Fastabend 
11141ade9abaSJohn Fastabend 		if (txmsg_pop) {
11151ade9abaSJohn Fastabend 			i = 5;
11161ade9abaSJohn Fastabend 			err = bpf_map_update_elem(map_fd[5],
11171ade9abaSJohn Fastabend 						  &i, &txmsg_pop, BPF_ANY);
11181ade9abaSJohn Fastabend 			if (err) {
11191ade9abaSJohn Fastabend 				fprintf(stderr,
11201ade9abaSJohn Fastabend 					"ERROR: bpf_map_update_elem %i@%i (txmsg_pop):  %d (%s)\n",
11211ade9abaSJohn Fastabend 					txmsg_pop, i, err, strerror(errno));
11221ade9abaSJohn Fastabend 				goto out;
11231ade9abaSJohn Fastabend 			}
11241ade9abaSJohn Fastabend 		} else {
11251ade9abaSJohn Fastabend 			i = 5;
11261ade9abaSJohn Fastabend 			bpf_map_update_elem(map_fd[5],
11271ade9abaSJohn Fastabend 					    &i, &txmsg_pop, BPF_ANY);
11281ade9abaSJohn Fastabend 
11291ade9abaSJohn Fastabend 		}
11301ade9abaSJohn Fastabend 
113116962b24SJohn Fastabend 		if (txmsg_ingress) {
113216962b24SJohn Fastabend 			int in = BPF_F_INGRESS;
113316962b24SJohn Fastabend 
113416962b24SJohn Fastabend 			i = 0;
113516962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
113616962b24SJohn Fastabend 			if (err) {
113716962b24SJohn Fastabend 				fprintf(stderr,
113816962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
113916962b24SJohn Fastabend 					err, strerror(errno));
114016962b24SJohn Fastabend 			}
114116962b24SJohn Fastabend 			i = 1;
114216962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
114316962b24SJohn Fastabend 			if (err) {
114416962b24SJohn Fastabend 				fprintf(stderr,
114516962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
114616962b24SJohn Fastabend 					err, strerror(errno));
114716962b24SJohn Fastabend 			}
114816962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
114916962b24SJohn Fastabend 			if (err) {
115016962b24SJohn Fastabend 				fprintf(stderr,
115116962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
115216962b24SJohn Fastabend 					err, strerror(errno));
115316962b24SJohn Fastabend 			}
115416962b24SJohn Fastabend 
115516962b24SJohn Fastabend 			i = 2;
115616962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
115716962b24SJohn Fastabend 			if (err) {
115816962b24SJohn Fastabend 				fprintf(stderr,
115916962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
116016962b24SJohn Fastabend 					err, strerror(errno));
116116962b24SJohn Fastabend 			}
116216962b24SJohn Fastabend 		}
116316962b24SJohn Fastabend 
1164463bac5fSJohn Fastabend 		if (txmsg_ktls_skb) {
1165463bac5fSJohn Fastabend 			int ingress = BPF_F_INGRESS;
1166463bac5fSJohn Fastabend 
1167463bac5fSJohn Fastabend 			i = 0;
1168463bac5fSJohn Fastabend 			err = bpf_map_update_elem(map_fd[8], &i, &p2, BPF_ANY);
1169463bac5fSJohn Fastabend 			if (err) {
1170463bac5fSJohn Fastabend 				fprintf(stderr,
1171463bac5fSJohn Fastabend 					"ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
1172463bac5fSJohn Fastabend 					err, strerror(errno));
1173463bac5fSJohn Fastabend 			}
1174463bac5fSJohn Fastabend 
1175463bac5fSJohn Fastabend 			if (txmsg_ktls_skb_redir) {
1176463bac5fSJohn Fastabend 				i = 1;
1177463bac5fSJohn Fastabend 				err = bpf_map_update_elem(map_fd[7],
1178463bac5fSJohn Fastabend 							  &i, &ingress, BPF_ANY);
1179463bac5fSJohn Fastabend 				if (err) {
1180463bac5fSJohn Fastabend 					fprintf(stderr,
1181463bac5fSJohn Fastabend 						"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
1182463bac5fSJohn Fastabend 						err, strerror(errno));
1183463bac5fSJohn Fastabend 				}
1184463bac5fSJohn Fastabend 			}
1185463bac5fSJohn Fastabend 
1186463bac5fSJohn Fastabend 			if (txmsg_ktls_skb_drop) {
1187463bac5fSJohn Fastabend 				i = 1;
1188463bac5fSJohn Fastabend 				err = bpf_map_update_elem(map_fd[7], &i, &i, BPF_ANY);
1189463bac5fSJohn Fastabend 			}
1190463bac5fSJohn Fastabend 		}
1191463bac5fSJohn Fastabend 
1192463bac5fSJohn Fastabend 		if (txmsg_redir_skb) {
119316962b24SJohn Fastabend 			int skb_fd = (test == SENDMSG || test == SENDPAGE) ?
119416962b24SJohn Fastabend 					p2 : p1;
119516962b24SJohn Fastabend 			int ingress = BPF_F_INGRESS;
119616962b24SJohn Fastabend 
119716962b24SJohn Fastabend 			i = 0;
119816962b24SJohn Fastabend 			err = bpf_map_update_elem(map_fd[7],
119916962b24SJohn Fastabend 						  &i, &ingress, BPF_ANY);
120016962b24SJohn Fastabend 			if (err) {
120116962b24SJohn Fastabend 				fprintf(stderr,
120216962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
120316962b24SJohn Fastabend 					err, strerror(errno));
120416962b24SJohn Fastabend 			}
120516962b24SJohn Fastabend 
120616962b24SJohn Fastabend 			i = 3;
1207463bac5fSJohn Fastabend 			err = bpf_map_update_elem(map_fd[0], &i, &skb_fd, BPF_ANY);
120816962b24SJohn Fastabend 			if (err) {
120916962b24SJohn Fastabend 				fprintf(stderr,
121016962b24SJohn Fastabend 					"ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
121116962b24SJohn Fastabend 					err, strerror(errno));
121216962b24SJohn Fastabend 			}
121316962b24SJohn Fastabend 		}
121416962b24SJohn Fastabend 	}
121516962b24SJohn Fastabend 
121653792fa4SJohn Fastabend 	if (skb_use_parser) {
121753792fa4SJohn Fastabend 		i = 2;
121853792fa4SJohn Fastabend 		err = bpf_map_update_elem(map_fd[7], &i, &skb_use_parser, BPF_ANY);
121953792fa4SJohn Fastabend 	}
122053792fa4SJohn Fastabend 
122116962b24SJohn Fastabend 	if (txmsg_drop)
122216962b24SJohn Fastabend 		options->drop_expected = true;
122316962b24SJohn Fastabend 
122416962b24SJohn Fastabend 	if (test == PING_PONG)
122516962b24SJohn Fastabend 		err = forever_ping_pong(options->rate, options);
122616962b24SJohn Fastabend 	else if (test == SENDMSG) {
122716962b24SJohn Fastabend 		options->base = false;
122816962b24SJohn Fastabend 		options->sendpage = false;
122916962b24SJohn Fastabend 		err = sendmsg_test(options);
123016962b24SJohn Fastabend 	} else if (test == SENDPAGE) {
123116962b24SJohn Fastabend 		options->base = false;
123216962b24SJohn Fastabend 		options->sendpage = true;
123316962b24SJohn Fastabend 		err = sendmsg_test(options);
123416962b24SJohn Fastabend 	} else if (test == BASE) {
123516962b24SJohn Fastabend 		options->base = true;
123616962b24SJohn Fastabend 		options->sendpage = false;
123716962b24SJohn Fastabend 		err = sendmsg_test(options);
123816962b24SJohn Fastabend 	} else if (test == BASE_SENDPAGE) {
123916962b24SJohn Fastabend 		options->base = true;
124016962b24SJohn Fastabend 		options->sendpage = true;
124116962b24SJohn Fastabend 		err = sendmsg_test(options);
124216962b24SJohn Fastabend 	} else
124316962b24SJohn Fastabend 		fprintf(stderr, "unknown test\n");
124416962b24SJohn Fastabend out:
124516962b24SJohn Fastabend 	/* Detatch and zero all the maps */
1246463bac5fSJohn Fastabend 	bpf_prog_detach2(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS);
124716962b24SJohn Fastabend 	bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER);
124816962b24SJohn Fastabend 	bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT);
1249463bac5fSJohn Fastabend 	bpf_prog_detach2(prog_fd[0], map_fd[8], BPF_SK_SKB_STREAM_PARSER);
1250463bac5fSJohn Fastabend 	bpf_prog_detach2(prog_fd[2], map_fd[8], BPF_SK_SKB_STREAM_VERDICT);
1251463bac5fSJohn Fastabend 
125216962b24SJohn Fastabend 	if (tx_prog_fd >= 0)
125316962b24SJohn Fastabend 		bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT);
125416962b24SJohn Fastabend 
125516962b24SJohn Fastabend 	for (i = 0; i < 8; i++) {
125616962b24SJohn Fastabend 		key = next_key = 0;
125716962b24SJohn Fastabend 		bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
125816962b24SJohn Fastabend 		while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) {
125916962b24SJohn Fastabend 			bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
126016962b24SJohn Fastabend 			key = next_key;
126116962b24SJohn Fastabend 		}
126216962b24SJohn Fastabend 	}
126316962b24SJohn Fastabend 
126416962b24SJohn Fastabend 	close(s1);
126516962b24SJohn Fastabend 	close(s2);
126616962b24SJohn Fastabend 	close(p1);
126716962b24SJohn Fastabend 	close(p2);
126816962b24SJohn Fastabend 	close(c1);
126916962b24SJohn Fastabend 	close(c2);
127016962b24SJohn Fastabend 	return err;
127116962b24SJohn Fastabend }
127216962b24SJohn Fastabend 
127316962b24SJohn Fastabend static char *test_to_str(int test)
127416962b24SJohn Fastabend {
127516962b24SJohn Fastabend 	switch (test) {
127616962b24SJohn Fastabend 	case SENDMSG:
127716962b24SJohn Fastabend 		return "sendmsg";
127816962b24SJohn Fastabend 	case SENDPAGE:
127916962b24SJohn Fastabend 		return "sendpage";
128016962b24SJohn Fastabend 	}
128116962b24SJohn Fastabend 	return "unknown";
128216962b24SJohn Fastabend }
128316962b24SJohn Fastabend 
128416962b24SJohn Fastabend #define OPTSTRING 60
128516962b24SJohn Fastabend static void test_options(char *options)
128616962b24SJohn Fastabend {
128773563aa3SPrashant Bhole 	char tstr[OPTSTRING];
128873563aa3SPrashant Bhole 
128916962b24SJohn Fastabend 	memset(options, 0, OPTSTRING);
129016962b24SJohn Fastabend 
129116962b24SJohn Fastabend 	if (txmsg_pass)
129216962b24SJohn Fastabend 		strncat(options, "pass,", OPTSTRING);
129316962b24SJohn Fastabend 	if (txmsg_redir)
129416962b24SJohn Fastabend 		strncat(options, "redir,", OPTSTRING);
129516962b24SJohn Fastabend 	if (txmsg_drop)
129616962b24SJohn Fastabend 		strncat(options, "drop,", OPTSTRING);
129773563aa3SPrashant Bhole 	if (txmsg_apply) {
129873563aa3SPrashant Bhole 		snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply);
129973563aa3SPrashant Bhole 		strncat(options, tstr, OPTSTRING);
130073563aa3SPrashant Bhole 	}
130173563aa3SPrashant Bhole 	if (txmsg_cork) {
130273563aa3SPrashant Bhole 		snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork);
130373563aa3SPrashant Bhole 		strncat(options, tstr, OPTSTRING);
130473563aa3SPrashant Bhole 	}
130573563aa3SPrashant Bhole 	if (txmsg_start) {
130673563aa3SPrashant Bhole 		snprintf(tstr, OPTSTRING, "start %d,", txmsg_start);
130773563aa3SPrashant Bhole 		strncat(options, tstr, OPTSTRING);
130873563aa3SPrashant Bhole 	}
130973563aa3SPrashant Bhole 	if (txmsg_end) {
131073563aa3SPrashant Bhole 		snprintf(tstr, OPTSTRING, "end %d,", txmsg_end);
131173563aa3SPrashant Bhole 		strncat(options, tstr, OPTSTRING);
131273563aa3SPrashant Bhole 	}
13131ade9abaSJohn Fastabend 	if (txmsg_start_pop) {
13141ade9abaSJohn Fastabend 		snprintf(tstr, OPTSTRING, "pop (%d,%d),",
13151ade9abaSJohn Fastabend 			 txmsg_start_pop, txmsg_start_pop + txmsg_pop);
13161ade9abaSJohn Fastabend 		strncat(options, tstr, OPTSTRING);
13171ade9abaSJohn Fastabend 	}
131816962b24SJohn Fastabend 	if (txmsg_ingress)
131916962b24SJohn Fastabend 		strncat(options, "ingress,", OPTSTRING);
1320463bac5fSJohn Fastabend 	if (txmsg_redir_skb)
1321463bac5fSJohn Fastabend 		strncat(options, "redir_skb,", OPTSTRING);
1322463bac5fSJohn Fastabend 	if (txmsg_ktls_skb)
1323463bac5fSJohn Fastabend 		strncat(options, "ktls_skb,", OPTSTRING);
1324e9dd9047SJohn Fastabend 	if (ktls)
1325e9dd9047SJohn Fastabend 		strncat(options, "ktls,", OPTSTRING);
1326753fb2eeSJohn Fastabend 	if (peek_flag)
1327753fb2eeSJohn Fastabend 		strncat(options, "peek,", OPTSTRING);
132816962b24SJohn Fastabend }
132916962b24SJohn Fastabend 
133016962b24SJohn Fastabend static int __test_exec(int cgrp, int test, struct sockmap_options *opt)
133116962b24SJohn Fastabend {
133273563aa3SPrashant Bhole 	char *options = calloc(OPTSTRING, sizeof(char));
133316962b24SJohn Fastabend 	int err;
133416962b24SJohn Fastabend 
133516962b24SJohn Fastabend 	if (test == SENDPAGE)
133616962b24SJohn Fastabend 		opt->sendpage = true;
133716962b24SJohn Fastabend 	else
133816962b24SJohn Fastabend 		opt->sendpage = false;
133916962b24SJohn Fastabend 
134016962b24SJohn Fastabend 	if (txmsg_drop)
134116962b24SJohn Fastabend 		opt->drop_expected = true;
134216962b24SJohn Fastabend 	else
134316962b24SJohn Fastabend 		opt->drop_expected = false;
134416962b24SJohn Fastabend 
134516962b24SJohn Fastabend 	test_options(options);
134616962b24SJohn Fastabend 
1347328aa08aSJohn Fastabend 	if (opt->verbose) {
134816962b24SJohn Fastabend 		fprintf(stdout,
134916962b24SJohn Fastabend 			" [TEST %i]: (%i, %i, %i, %s, %s): ",
135016962b24SJohn Fastabend 			test_cnt, opt->rate, opt->iov_count, opt->iov_length,
135116962b24SJohn Fastabend 			test_to_str(test), options);
135216962b24SJohn Fastabend 		fflush(stdout);
1353328aa08aSJohn Fastabend 	}
135416962b24SJohn Fastabend 	err = run_options(opt, cgrp, test);
1355328aa08aSJohn Fastabend 	if (opt->verbose)
135616962b24SJohn Fastabend 		fprintf(stdout, " %s\n", !err ? "PASS" : "FAILED");
135716962b24SJohn Fastabend 	test_cnt++;
135816962b24SJohn Fastabend 	!err ? passed++ : failed++;
135916962b24SJohn Fastabend 	free(options);
136016962b24SJohn Fastabend 	return err;
136116962b24SJohn Fastabend }
136216962b24SJohn Fastabend 
1363328aa08aSJohn Fastabend static void test_exec(int cgrp, struct sockmap_options *opt)
136416962b24SJohn Fastabend {
1365328aa08aSJohn Fastabend 	int type = strcmp(opt->map, BPF_SOCKMAP_FILENAME);
1366328aa08aSJohn Fastabend 	int err;
136716962b24SJohn Fastabend 
1368328aa08aSJohn Fastabend 	if (type == 0) {
1369328aa08aSJohn Fastabend 		test_start();
1370328aa08aSJohn Fastabend 		err = __test_exec(cgrp, SENDMSG, opt);
137116962b24SJohn Fastabend 		if (err)
1372328aa08aSJohn Fastabend 			test_fail();
1373328aa08aSJohn Fastabend 	} else {
1374328aa08aSJohn Fastabend 		test_start();
137516962b24SJohn Fastabend 		err = __test_exec(cgrp, SENDPAGE, opt);
1376328aa08aSJohn Fastabend 		if (err)
1377328aa08aSJohn Fastabend 			test_fail();
1378328aa08aSJohn Fastabend 	}
137916962b24SJohn Fastabend }
138016962b24SJohn Fastabend 
1381328aa08aSJohn Fastabend static void test_send_one(struct sockmap_options *opt, int cgrp)
138216962b24SJohn Fastabend {
138316962b24SJohn Fastabend 	opt->iov_length = 1;
138416962b24SJohn Fastabend 	opt->iov_count = 1;
138516962b24SJohn Fastabend 	opt->rate = 1;
1386328aa08aSJohn Fastabend 	test_exec(cgrp, opt);
138716962b24SJohn Fastabend 
138816962b24SJohn Fastabend 	opt->iov_length = 1;
138916962b24SJohn Fastabend 	opt->iov_count = 1024;
139016962b24SJohn Fastabend 	opt->rate = 1;
1391328aa08aSJohn Fastabend 	test_exec(cgrp, opt);
139216962b24SJohn Fastabend 
139316962b24SJohn Fastabend 	opt->iov_length = 1024;
139416962b24SJohn Fastabend 	opt->iov_count = 1;
139516962b24SJohn Fastabend 	opt->rate = 1;
1396328aa08aSJohn Fastabend 	test_exec(cgrp, opt);
139716962b24SJohn Fastabend 
1398328aa08aSJohn Fastabend }
1399328aa08aSJohn Fastabend 
1400328aa08aSJohn Fastabend static void test_send_many(struct sockmap_options *opt, int cgrp)
1401328aa08aSJohn Fastabend {
1402328aa08aSJohn Fastabend 	opt->iov_length = 3;
140316962b24SJohn Fastabend 	opt->iov_count = 1;
1404a009f1f3SPrashant Bhole 	opt->rate = 512;
1405328aa08aSJohn Fastabend 	test_exec(cgrp, opt);
140616962b24SJohn Fastabend 
140716962b24SJohn Fastabend 	opt->rate = 100;
140816962b24SJohn Fastabend 	opt->iov_count = 1;
140916962b24SJohn Fastabend 	opt->iov_length = 5;
1410328aa08aSJohn Fastabend 	test_exec(cgrp, opt);
141116962b24SJohn Fastabend }
141216962b24SJohn Fastabend 
1413328aa08aSJohn Fastabend static void test_send_large(struct sockmap_options *opt, int cgrp)
141416962b24SJohn Fastabend {
1415328aa08aSJohn Fastabend 	opt->iov_length = 256;
1416328aa08aSJohn Fastabend 	opt->iov_count = 1024;
1417328aa08aSJohn Fastabend 	opt->rate = 2;
1418328aa08aSJohn Fastabend 	test_exec(cgrp, opt);
1419328aa08aSJohn Fastabend }
142016962b24SJohn Fastabend 
1421328aa08aSJohn Fastabend static void test_send(struct sockmap_options *opt, int cgrp)
1422328aa08aSJohn Fastabend {
1423328aa08aSJohn Fastabend 	test_send_one(opt, cgrp);
1424328aa08aSJohn Fastabend 	test_send_many(opt, cgrp);
1425328aa08aSJohn Fastabend 	test_send_large(opt, cgrp);
1426328aa08aSJohn Fastabend 	sched_yield();
1427328aa08aSJohn Fastabend }
1428328aa08aSJohn Fastabend 
1429b98ca90cSJohn Fastabend static void test_txmsg_pass(int cgrp, struct sockmap_options *opt)
1430328aa08aSJohn Fastabend {
143116962b24SJohn Fastabend 	/* Test small and large iov_count values with pass/redir/apply/cork */
143216962b24SJohn Fastabend 	txmsg_pass = 1;
1433b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
143416962b24SJohn Fastabend }
143516962b24SJohn Fastabend 
1436b98ca90cSJohn Fastabend static void test_txmsg_redir(int cgrp, struct sockmap_options *opt)
143716962b24SJohn Fastabend {
1438328aa08aSJohn Fastabend 	txmsg_redir = 1;
1439b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
1440328aa08aSJohn Fastabend }
1441328aa08aSJohn Fastabend 
1442b98ca90cSJohn Fastabend static void test_txmsg_drop(int cgrp, struct sockmap_options *opt)
1443328aa08aSJohn Fastabend {
1444328aa08aSJohn Fastabend 	txmsg_drop = 1;
1445b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
1446328aa08aSJohn Fastabend }
1447328aa08aSJohn Fastabend 
1448b98ca90cSJohn Fastabend static void test_txmsg_ingress_redir(int cgrp, struct sockmap_options *opt)
1449328aa08aSJohn Fastabend {
1450328aa08aSJohn Fastabend 	txmsg_pass = txmsg_drop = 0;
1451328aa08aSJohn Fastabend 	txmsg_ingress = txmsg_redir = 1;
1452b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
1453328aa08aSJohn Fastabend }
1454328aa08aSJohn Fastabend 
1455463bac5fSJohn Fastabend static void test_txmsg_skb(int cgrp, struct sockmap_options *opt)
1456463bac5fSJohn Fastabend {
1457463bac5fSJohn Fastabend 	bool data = opt->data_test;
1458463bac5fSJohn Fastabend 	int k = ktls;
1459463bac5fSJohn Fastabend 
1460463bac5fSJohn Fastabend 	opt->data_test = true;
1461463bac5fSJohn Fastabend 	ktls = 1;
1462463bac5fSJohn Fastabend 
1463463bac5fSJohn Fastabend 	txmsg_pass = txmsg_drop = 0;
1464463bac5fSJohn Fastabend 	txmsg_ingress = txmsg_redir = 0;
1465463bac5fSJohn Fastabend 	txmsg_ktls_skb = 1;
1466463bac5fSJohn Fastabend 	txmsg_pass = 1;
1467463bac5fSJohn Fastabend 
1468463bac5fSJohn Fastabend 	/* Using data verification so ensure iov layout is
1469463bac5fSJohn Fastabend 	 * expected from test receiver side. e.g. has enough
1470463bac5fSJohn Fastabend 	 * bytes to write test code.
1471463bac5fSJohn Fastabend 	 */
1472463bac5fSJohn Fastabend 	opt->iov_length = 100;
1473463bac5fSJohn Fastabend 	opt->iov_count = 1;
1474463bac5fSJohn Fastabend 	opt->rate = 1;
1475463bac5fSJohn Fastabend 	test_exec(cgrp, opt);
1476463bac5fSJohn Fastabend 
1477463bac5fSJohn Fastabend 	txmsg_ktls_skb_drop = 1;
1478463bac5fSJohn Fastabend 	test_exec(cgrp, opt);
1479463bac5fSJohn Fastabend 
1480463bac5fSJohn Fastabend 	txmsg_ktls_skb_drop = 0;
1481463bac5fSJohn Fastabend 	txmsg_ktls_skb_redir = 1;
1482463bac5fSJohn Fastabend 	test_exec(cgrp, opt);
1483463bac5fSJohn Fastabend 
1484463bac5fSJohn Fastabend 	opt->data_test = data;
1485463bac5fSJohn Fastabend 	ktls = k;
1486463bac5fSJohn Fastabend }
1487463bac5fSJohn Fastabend 
1488463bac5fSJohn Fastabend 
1489328aa08aSJohn Fastabend /* Test cork with hung data. This tests poor usage patterns where
1490328aa08aSJohn Fastabend  * cork can leave data on the ring if user program is buggy and
1491328aa08aSJohn Fastabend  * doesn't flush them somehow. They do take some time however
1492328aa08aSJohn Fastabend  * because they wait for a timeout. Test pass, redir and cork with
1493328aa08aSJohn Fastabend  * apply logic. Use cork size of 4097 with send_large to avoid
1494328aa08aSJohn Fastabend  * aligning cork size with send size.
1495328aa08aSJohn Fastabend  */
1496b98ca90cSJohn Fastabend static void test_txmsg_cork_hangs(int cgrp, struct sockmap_options *opt)
1497328aa08aSJohn Fastabend {
1498328aa08aSJohn Fastabend 	txmsg_pass = 1;
1499328aa08aSJohn Fastabend 	txmsg_redir = 0;
1500328aa08aSJohn Fastabend 	txmsg_cork = 4097;
1501328aa08aSJohn Fastabend 	txmsg_apply = 4097;
1502b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1503328aa08aSJohn Fastabend 
1504328aa08aSJohn Fastabend 	txmsg_pass = 0;
1505328aa08aSJohn Fastabend 	txmsg_redir = 1;
1506328aa08aSJohn Fastabend 	txmsg_apply = 0;
1507328aa08aSJohn Fastabend 	txmsg_cork = 4097;
1508b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1509328aa08aSJohn Fastabend 
1510328aa08aSJohn Fastabend 	txmsg_pass = 0;
1511328aa08aSJohn Fastabend 	txmsg_redir = 1;
1512328aa08aSJohn Fastabend 	txmsg_apply = 4097;
1513328aa08aSJohn Fastabend 	txmsg_cork = 4097;
1514b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1515328aa08aSJohn Fastabend }
1516328aa08aSJohn Fastabend 
1517b98ca90cSJohn Fastabend static void test_txmsg_pull(int cgrp, struct sockmap_options *opt)
1518328aa08aSJohn Fastabend {
1519328aa08aSJohn Fastabend 	/* Test basic start/end */
152016962b24SJohn Fastabend 	txmsg_start = 1;
152116962b24SJohn Fastabend 	txmsg_end = 2;
1522b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
1523328aa08aSJohn Fastabend 
1524328aa08aSJohn Fastabend 	/* Test >4k pull */
1525328aa08aSJohn Fastabend 	txmsg_start = 4096;
1526328aa08aSJohn Fastabend 	txmsg_end = 9182;
1527b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1528328aa08aSJohn Fastabend 
1529328aa08aSJohn Fastabend 	/* Test pull + redirect */
1530328aa08aSJohn Fastabend 	txmsg_redir = 0;
1531328aa08aSJohn Fastabend 	txmsg_start = 1;
1532328aa08aSJohn Fastabend 	txmsg_end = 2;
1533b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
1534328aa08aSJohn Fastabend 
1535328aa08aSJohn Fastabend 	/* Test pull + cork */
1536328aa08aSJohn Fastabend 	txmsg_redir = 0;
1537328aa08aSJohn Fastabend 	txmsg_cork = 512;
1538328aa08aSJohn Fastabend 	txmsg_start = 1;
1539328aa08aSJohn Fastabend 	txmsg_end = 2;
1540b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
1541328aa08aSJohn Fastabend 
1542328aa08aSJohn Fastabend 	/* Test pull + cork + redirect */
1543328aa08aSJohn Fastabend 	txmsg_redir = 1;
1544328aa08aSJohn Fastabend 	txmsg_cork = 512;
1545328aa08aSJohn Fastabend 	txmsg_start = 1;
1546328aa08aSJohn Fastabend 	txmsg_end = 2;
1547b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
1548328aa08aSJohn Fastabend }
1549328aa08aSJohn Fastabend 
1550b98ca90cSJohn Fastabend static void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
1551328aa08aSJohn Fastabend {
1552328aa08aSJohn Fastabend 	/* Test basic pop */
1553328aa08aSJohn Fastabend 	txmsg_start_pop = 1;
1554328aa08aSJohn Fastabend 	txmsg_pop = 2;
1555b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
1556328aa08aSJohn Fastabend 
1557328aa08aSJohn Fastabend 	/* Test pop with >4k */
1558328aa08aSJohn Fastabend 	txmsg_start_pop = 4096;
1559328aa08aSJohn Fastabend 	txmsg_pop = 4096;
1560b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1561328aa08aSJohn Fastabend 
1562328aa08aSJohn Fastabend 	/* Test pop + redirect */
1563328aa08aSJohn Fastabend 	txmsg_redir = 1;
1564328aa08aSJohn Fastabend 	txmsg_start_pop = 1;
1565328aa08aSJohn Fastabend 	txmsg_pop = 2;
1566b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
1567328aa08aSJohn Fastabend 
1568328aa08aSJohn Fastabend 	/* Test pop + cork */
1569328aa08aSJohn Fastabend 	txmsg_redir = 0;
1570328aa08aSJohn Fastabend 	txmsg_cork = 512;
1571328aa08aSJohn Fastabend 	txmsg_start_pop = 1;
1572328aa08aSJohn Fastabend 	txmsg_pop = 2;
1573b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
1574328aa08aSJohn Fastabend 
1575328aa08aSJohn Fastabend 	/* Test pop + redirect + cork */
1576328aa08aSJohn Fastabend 	txmsg_redir = 1;
1577328aa08aSJohn Fastabend 	txmsg_cork = 4;
1578328aa08aSJohn Fastabend 	txmsg_start_pop = 1;
1579328aa08aSJohn Fastabend 	txmsg_pop = 2;
1580b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
1581328aa08aSJohn Fastabend }
1582328aa08aSJohn Fastabend 
1583b98ca90cSJohn Fastabend static void test_txmsg_push(int cgrp, struct sockmap_options *opt)
1584328aa08aSJohn Fastabend {
1585328aa08aSJohn Fastabend 	/* Test basic push */
1586328aa08aSJohn Fastabend 	txmsg_start_push = 1;
1587328aa08aSJohn Fastabend 	txmsg_end_push = 1;
1588b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
1589328aa08aSJohn Fastabend 
1590328aa08aSJohn Fastabend 	/* Test push 4kB >4k */
1591328aa08aSJohn Fastabend 	txmsg_start_push = 4096;
1592328aa08aSJohn Fastabend 	txmsg_end_push = 4096;
1593b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1594328aa08aSJohn Fastabend 
1595328aa08aSJohn Fastabend 	/* Test push + redirect */
1596328aa08aSJohn Fastabend 	txmsg_redir = 1;
159784fbfe02SJohn Fastabend 	txmsg_start_push = 1;
159884fbfe02SJohn Fastabend 	txmsg_end_push = 2;
1599b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
16001ade9abaSJohn Fastabend 
1601328aa08aSJohn Fastabend 	/* Test push + cork */
1602328aa08aSJohn Fastabend 	txmsg_redir = 0;
1603328aa08aSJohn Fastabend 	txmsg_cork = 512;
16041ade9abaSJohn Fastabend 	txmsg_start_push = 1;
1605328aa08aSJohn Fastabend 	txmsg_end_push = 2;
1606b98ca90cSJohn Fastabend 	test_send_many(opt, cgrp);
160716962b24SJohn Fastabend }
160816962b24SJohn Fastabend 
1609b98ca90cSJohn Fastabend static void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt)
1610328aa08aSJohn Fastabend {
1611328aa08aSJohn Fastabend 	txmsg_start_push = 1;
1612328aa08aSJohn Fastabend 	txmsg_end_push = 10;
1613328aa08aSJohn Fastabend 	txmsg_start_pop = 5;
1614328aa08aSJohn Fastabend 	txmsg_pop = 4;
1615b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
161616962b24SJohn Fastabend }
161716962b24SJohn Fastabend 
1618b98ca90cSJohn Fastabend static void test_txmsg_apply(int cgrp, struct sockmap_options *opt)
1619328aa08aSJohn Fastabend {
1620328aa08aSJohn Fastabend 	txmsg_pass = 1;
1621328aa08aSJohn Fastabend 	txmsg_redir = 0;
1622328aa08aSJohn Fastabend 	txmsg_apply = 1;
1623328aa08aSJohn Fastabend 	txmsg_cork = 0;
1624b98ca90cSJohn Fastabend 	test_send_one(opt, cgrp);
16251ade9abaSJohn Fastabend 
1626328aa08aSJohn Fastabend 	txmsg_pass = 0;
1627328aa08aSJohn Fastabend 	txmsg_redir = 1;
1628328aa08aSJohn Fastabend 	txmsg_apply = 1;
1629328aa08aSJohn Fastabend 	txmsg_cork = 0;
1630b98ca90cSJohn Fastabend 	test_send_one(opt, cgrp);
163116962b24SJohn Fastabend 
1632328aa08aSJohn Fastabend 	txmsg_pass = 1;
1633328aa08aSJohn Fastabend 	txmsg_redir = 0;
1634328aa08aSJohn Fastabend 	txmsg_apply = 1024;
1635328aa08aSJohn Fastabend 	txmsg_cork = 0;
1636b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
16371ade9abaSJohn Fastabend 
1638328aa08aSJohn Fastabend 	txmsg_pass = 0;
1639328aa08aSJohn Fastabend 	txmsg_redir = 1;
1640328aa08aSJohn Fastabend 	txmsg_apply = 1024;
1641328aa08aSJohn Fastabend 	txmsg_cork = 0;
1642b98ca90cSJohn Fastabend 	test_send_large(opt, cgrp);
1643328aa08aSJohn Fastabend }
164416962b24SJohn Fastabend 
1645b98ca90cSJohn Fastabend static void test_txmsg_cork(int cgrp, struct sockmap_options *opt)
1646328aa08aSJohn Fastabend {
1647328aa08aSJohn Fastabend 	txmsg_pass = 1;
1648328aa08aSJohn Fastabend 	txmsg_redir = 0;
1649328aa08aSJohn Fastabend 	txmsg_apply = 0;
1650328aa08aSJohn Fastabend 	txmsg_cork = 1;
1651b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
165216962b24SJohn Fastabend 
1653328aa08aSJohn Fastabend 	txmsg_pass = 1;
1654328aa08aSJohn Fastabend 	txmsg_redir = 0;
1655328aa08aSJohn Fastabend 	txmsg_apply = 1;
1656328aa08aSJohn Fastabend 	txmsg_cork = 1;
1657b98ca90cSJohn Fastabend 	test_send(opt, cgrp);
165816962b24SJohn Fastabend }
165916962b24SJohn Fastabend 
166053792fa4SJohn Fastabend static void test_txmsg_ingress_parser(int cgrp, struct sockmap_options *opt)
166153792fa4SJohn Fastabend {
166253792fa4SJohn Fastabend 	txmsg_pass = 1;
166353792fa4SJohn Fastabend 	skb_use_parser = 512;
166453792fa4SJohn Fastabend 	opt->iov_length = 256;
166553792fa4SJohn Fastabend 	opt->iov_count = 1;
166653792fa4SJohn Fastabend 	opt->rate = 2;
166753792fa4SJohn Fastabend 	test_exec(cgrp, opt);
166853792fa4SJohn Fastabend }
166953792fa4SJohn Fastabend 
167016962b24SJohn Fastabend char *map_names[] = {
167116962b24SJohn Fastabend 	"sock_map",
167216962b24SJohn Fastabend 	"sock_map_txmsg",
167316962b24SJohn Fastabend 	"sock_map_redir",
167416962b24SJohn Fastabend 	"sock_apply_bytes",
167516962b24SJohn Fastabend 	"sock_cork_bytes",
167684fbfe02SJohn Fastabend 	"sock_bytes",
167716962b24SJohn Fastabend 	"sock_redir_flags",
167816962b24SJohn Fastabend 	"sock_skb_opts",
1679463bac5fSJohn Fastabend 	"tls_sock_map",
168016962b24SJohn Fastabend };
168116962b24SJohn Fastabend 
168216962b24SJohn Fastabend int prog_attach_type[] = {
168316962b24SJohn Fastabend 	BPF_SK_SKB_STREAM_PARSER,
168416962b24SJohn Fastabend 	BPF_SK_SKB_STREAM_VERDICT,
1685463bac5fSJohn Fastabend 	BPF_SK_SKB_STREAM_VERDICT,
168616962b24SJohn Fastabend 	BPF_CGROUP_SOCK_OPS,
168716962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
168816962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
168916962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
169016962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
169116962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
169216962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
169316962b24SJohn Fastabend 	BPF_SK_MSG_VERDICT,
169416962b24SJohn Fastabend };
169516962b24SJohn Fastabend 
169616962b24SJohn Fastabend int prog_type[] = {
169716962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_SKB,
169816962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_SKB,
1699463bac5fSJohn Fastabend 	BPF_PROG_TYPE_SK_SKB,
170016962b24SJohn Fastabend 	BPF_PROG_TYPE_SOCK_OPS,
170116962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170216962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170316962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170416962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170516962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170616962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170716962b24SJohn Fastabend 	BPF_PROG_TYPE_SK_MSG,
170816962b24SJohn Fastabend };
170916962b24SJohn Fastabend 
1710b8b394faSJohn Fastabend static int populate_progs(char *bpf_file)
171116962b24SJohn Fastabend {
171216962b24SJohn Fastabend 	struct bpf_program *prog;
171316962b24SJohn Fastabend 	struct bpf_object *obj;
171416962b24SJohn Fastabend 	int i = 0;
171516962b24SJohn Fastabend 	long err;
171616962b24SJohn Fastabend 
171716962b24SJohn Fastabend 	obj = bpf_object__open(bpf_file);
171816962b24SJohn Fastabend 	err = libbpf_get_error(obj);
171916962b24SJohn Fastabend 	if (err) {
172016962b24SJohn Fastabend 		char err_buf[256];
172116962b24SJohn Fastabend 
172216962b24SJohn Fastabend 		libbpf_strerror(err, err_buf, sizeof(err_buf));
172316962b24SJohn Fastabend 		printf("Unable to load eBPF objects in file '%s' : %s\n",
172416962b24SJohn Fastabend 		       bpf_file, err_buf);
172516962b24SJohn Fastabend 		return -1;
172616962b24SJohn Fastabend 	}
172716962b24SJohn Fastabend 
172816962b24SJohn Fastabend 	bpf_object__for_each_program(prog, obj) {
172916962b24SJohn Fastabend 		bpf_program__set_type(prog, prog_type[i]);
173016962b24SJohn Fastabend 		bpf_program__set_expected_attach_type(prog,
173116962b24SJohn Fastabend 						      prog_attach_type[i]);
173216962b24SJohn Fastabend 		i++;
173316962b24SJohn Fastabend 	}
173416962b24SJohn Fastabend 
173516962b24SJohn Fastabend 	i = bpf_object__load(obj);
173616962b24SJohn Fastabend 	i = 0;
173716962b24SJohn Fastabend 	bpf_object__for_each_program(prog, obj) {
173816962b24SJohn Fastabend 		prog_fd[i] = bpf_program__fd(prog);
173916962b24SJohn Fastabend 		i++;
174016962b24SJohn Fastabend 	}
174116962b24SJohn Fastabend 
174216962b24SJohn Fastabend 	for (i = 0; i < sizeof(map_fd)/sizeof(int); i++) {
174316962b24SJohn Fastabend 		maps[i] = bpf_object__find_map_by_name(obj, map_names[i]);
174416962b24SJohn Fastabend 		map_fd[i] = bpf_map__fd(maps[i]);
174516962b24SJohn Fastabend 		if (map_fd[i] < 0) {
174616962b24SJohn Fastabend 			fprintf(stderr, "load_bpf_file: (%i) %s\n",
174716962b24SJohn Fastabend 				map_fd[i], strerror(errno));
174816962b24SJohn Fastabend 			return -1;
174916962b24SJohn Fastabend 		}
175016962b24SJohn Fastabend 	}
175116962b24SJohn Fastabend 
175216962b24SJohn Fastabend 	return 0;
175316962b24SJohn Fastabend }
175416962b24SJohn Fastabend 
1755328aa08aSJohn Fastabend struct _test test[] = {
1756328aa08aSJohn Fastabend 	{"txmsg test passthrough", test_txmsg_pass},
1757328aa08aSJohn Fastabend 	{"txmsg test redirect", test_txmsg_redir},
1758328aa08aSJohn Fastabend 	{"txmsg test drop", test_txmsg_drop},
1759328aa08aSJohn Fastabend 	{"txmsg test ingress redirect", test_txmsg_ingress_redir},
1760463bac5fSJohn Fastabend 	{"txmsg test skb", test_txmsg_skb},
1761328aa08aSJohn Fastabend 	{"txmsg test apply", test_txmsg_apply},
1762328aa08aSJohn Fastabend 	{"txmsg test cork", test_txmsg_cork},
1763328aa08aSJohn Fastabend 	{"txmsg test hanging corks", test_txmsg_cork_hangs},
1764328aa08aSJohn Fastabend 	{"txmsg test push_data", test_txmsg_push},
1765328aa08aSJohn Fastabend 	{"txmsg test pull-data", test_txmsg_pull},
1766328aa08aSJohn Fastabend 	{"txmsg test pop-data", test_txmsg_pop},
1767328aa08aSJohn Fastabend 	{"txmsg test push/pop data", test_txmsg_push_pop},
176853792fa4SJohn Fastabend 	{"txmsg text ingress parser", test_txmsg_ingress_parser},
1769328aa08aSJohn Fastabend };
1770328aa08aSJohn Fastabend 
1771065a74cbSJohn Fastabend static int check_whitelist(struct _test *t, struct sockmap_options *opt)
1772065a74cbSJohn Fastabend {
1773065a74cbSJohn Fastabend 	char *entry, *ptr;
1774065a74cbSJohn Fastabend 
1775065a74cbSJohn Fastabend 	if (!opt->whitelist)
1776065a74cbSJohn Fastabend 		return 0;
1777065a74cbSJohn Fastabend 	ptr = strdup(opt->whitelist);
1778065a74cbSJohn Fastabend 	if (!ptr)
1779065a74cbSJohn Fastabend 		return -ENOMEM;
1780065a74cbSJohn Fastabend 	entry = strtok(ptr, ",");
1781065a74cbSJohn Fastabend 	while (entry) {
178296586dd9SJohn Fastabend 		if ((opt->prepend && strstr(opt->prepend, entry) != 0) ||
178396586dd9SJohn Fastabend 		    strstr(opt->map, entry) != 0 ||
178496586dd9SJohn Fastabend 		    strstr(t->title, entry) != 0)
1785065a74cbSJohn Fastabend 			return 0;
1786065a74cbSJohn Fastabend 		entry = strtok(NULL, ",");
1787065a74cbSJohn Fastabend 	}
1788065a74cbSJohn Fastabend 	return -EINVAL;
1789065a74cbSJohn Fastabend }
1790065a74cbSJohn Fastabend 
1791a7238f7cSJohn Fastabend static int check_blacklist(struct _test *t, struct sockmap_options *opt)
1792a7238f7cSJohn Fastabend {
1793a7238f7cSJohn Fastabend 	char *entry, *ptr;
1794a7238f7cSJohn Fastabend 
1795a7238f7cSJohn Fastabend 	if (!opt->blacklist)
1796a7238f7cSJohn Fastabend 		return -EINVAL;
1797a7238f7cSJohn Fastabend 	ptr = strdup(opt->blacklist);
1798a7238f7cSJohn Fastabend 	if (!ptr)
1799a7238f7cSJohn Fastabend 		return -ENOMEM;
1800a7238f7cSJohn Fastabend 	entry = strtok(ptr, ",");
1801a7238f7cSJohn Fastabend 	while (entry) {
180296586dd9SJohn Fastabend 		if ((opt->prepend && strstr(opt->prepend, entry) != 0) ||
180396586dd9SJohn Fastabend 		    strstr(opt->map, entry) != 0 ||
180496586dd9SJohn Fastabend 		    strstr(t->title, entry) != 0)
1805a7238f7cSJohn Fastabend 			return 0;
1806a7238f7cSJohn Fastabend 		entry = strtok(NULL, ",");
1807a7238f7cSJohn Fastabend 	}
1808a7238f7cSJohn Fastabend 	return -EINVAL;
1809a7238f7cSJohn Fastabend }
1810a7238f7cSJohn Fastabend 
1811b98ca90cSJohn Fastabend static int __test_selftests(int cg_fd, struct sockmap_options *opt)
1812328aa08aSJohn Fastabend {
1813328aa08aSJohn Fastabend 	int i, err;
1814328aa08aSJohn Fastabend 
1815b98ca90cSJohn Fastabend 	err = populate_progs(opt->map);
181616962b24SJohn Fastabend 	if (err < 0) {
181716962b24SJohn Fastabend 		fprintf(stderr, "ERROR: (%i) load bpf failed\n", err);
181816962b24SJohn Fastabend 		return err;
181916962b24SJohn Fastabend 	}
182016962b24SJohn Fastabend 
1821328aa08aSJohn Fastabend 	/* Tests basic commands and APIs */
1822328aa08aSJohn Fastabend 	for (i = 0; i < sizeof(test)/sizeof(struct _test); i++) {
1823328aa08aSJohn Fastabend 		struct _test t = test[i];
1824328aa08aSJohn Fastabend 
1825a7238f7cSJohn Fastabend 		if (check_whitelist(&t, opt) != 0)
1826a7238f7cSJohn Fastabend 			continue;
1827a7238f7cSJohn Fastabend 		if (check_blacklist(&t, opt) == 0)
1828065a74cbSJohn Fastabend 			continue;
1829065a74cbSJohn Fastabend 
183096586dd9SJohn Fastabend 		test_start_subtest(&t, opt);
1831b98ca90cSJohn Fastabend 		t.tester(cg_fd, opt);
1832328aa08aSJohn Fastabend 		test_end_subtest();
1833328aa08aSJohn Fastabend 	}
1834328aa08aSJohn Fastabend 
1835328aa08aSJohn Fastabend 	return err;
1836328aa08aSJohn Fastabend }
1837328aa08aSJohn Fastabend 
1838b98ca90cSJohn Fastabend static void test_selftests_sockmap(int cg_fd, struct sockmap_options *opt)
1839328aa08aSJohn Fastabend {
1840b98ca90cSJohn Fastabend 	opt->map = BPF_SOCKMAP_FILENAME;
1841b98ca90cSJohn Fastabend 	__test_selftests(cg_fd, opt);
1842328aa08aSJohn Fastabend }
1843328aa08aSJohn Fastabend 
1844b98ca90cSJohn Fastabend static void test_selftests_sockhash(int cg_fd, struct sockmap_options *opt)
1845328aa08aSJohn Fastabend {
1846b98ca90cSJohn Fastabend 	opt->map = BPF_SOCKHASH_FILENAME;
1847b98ca90cSJohn Fastabend 	__test_selftests(cg_fd, opt);
1848328aa08aSJohn Fastabend }
1849328aa08aSJohn Fastabend 
185096586dd9SJohn Fastabend static void test_selftests_ktls(int cg_fd, struct sockmap_options *opt)
185196586dd9SJohn Fastabend {
185296586dd9SJohn Fastabend 	opt->map = BPF_SOCKHASH_FILENAME;
185396586dd9SJohn Fastabend 	opt->prepend = "ktls";
185496586dd9SJohn Fastabend 	ktls = 1;
185596586dd9SJohn Fastabend 	__test_selftests(cg_fd, opt);
185696586dd9SJohn Fastabend 	ktls = 0;
185796586dd9SJohn Fastabend }
185896586dd9SJohn Fastabend 
1859b98ca90cSJohn Fastabend static int test_selftest(int cg_fd, struct sockmap_options *opt)
1860328aa08aSJohn Fastabend {
186116962b24SJohn Fastabend 
1862b98ca90cSJohn Fastabend 	test_selftests_sockmap(cg_fd, opt);
1863b98ca90cSJohn Fastabend 	test_selftests_sockhash(cg_fd, opt);
186496586dd9SJohn Fastabend 	test_selftests_ktls(cg_fd, opt);
1865328aa08aSJohn Fastabend 	test_print_results();
1866328aa08aSJohn Fastabend 	return 0;
1867b8b394faSJohn Fastabend }
1868b8b394faSJohn Fastabend 
186916962b24SJohn Fastabend int main(int argc, char **argv)
187016962b24SJohn Fastabend {
187116962b24SJohn Fastabend 	int iov_count = 1, length = 1024, rate = 1;
187216962b24SJohn Fastabend 	struct sockmap_options options = {0};
187316962b24SJohn Fastabend 	int opt, longindex, err, cg_fd = 0;
1874b8b394faSJohn Fastabend 	char *bpf_file = BPF_SOCKMAP_FILENAME;
1875b98ca90cSJohn Fastabend 	int test = SELFTESTS;
187613a5f3ffSJohn Fastabend 	bool cg_created = 0;
187716962b24SJohn Fastabend 
1878a7238f7cSJohn Fastabend 	while ((opt = getopt_long(argc, argv, ":dhv:c:r:i:l:t:p:q:n:b:",
187916962b24SJohn Fastabend 				  long_options, &longindex)) != -1) {
188016962b24SJohn Fastabend 		switch (opt) {
188116962b24SJohn Fastabend 		case 's':
188216962b24SJohn Fastabend 			txmsg_start = atoi(optarg);
188316962b24SJohn Fastabend 			break;
188416962b24SJohn Fastabend 		case 'e':
188516962b24SJohn Fastabend 			txmsg_end = atoi(optarg);
188616962b24SJohn Fastabend 			break;
188784fbfe02SJohn Fastabend 		case 'p':
188884fbfe02SJohn Fastabend 			txmsg_start_push = atoi(optarg);
188984fbfe02SJohn Fastabend 			break;
189084fbfe02SJohn Fastabend 		case 'q':
189184fbfe02SJohn Fastabend 			txmsg_end_push = atoi(optarg);
189284fbfe02SJohn Fastabend 			break;
18931ade9abaSJohn Fastabend 		case 'w':
18941ade9abaSJohn Fastabend 			txmsg_start_pop = atoi(optarg);
18951ade9abaSJohn Fastabend 			break;
18961ade9abaSJohn Fastabend 		case 'x':
18971ade9abaSJohn Fastabend 			txmsg_pop = atoi(optarg);
18981ade9abaSJohn Fastabend 			break;
189916962b24SJohn Fastabend 		case 'a':
190016962b24SJohn Fastabend 			txmsg_apply = atoi(optarg);
190116962b24SJohn Fastabend 			break;
190216962b24SJohn Fastabend 		case 'k':
190316962b24SJohn Fastabend 			txmsg_cork = atoi(optarg);
190416962b24SJohn Fastabend 			break;
190516962b24SJohn Fastabend 		case 'c':
190616962b24SJohn Fastabend 			cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
190716962b24SJohn Fastabend 			if (cg_fd < 0) {
190816962b24SJohn Fastabend 				fprintf(stderr,
190916962b24SJohn Fastabend 					"ERROR: (%i) open cg path failed: %s\n",
191016962b24SJohn Fastabend 					cg_fd, optarg);
191116962b24SJohn Fastabend 				return cg_fd;
191216962b24SJohn Fastabend 			}
191316962b24SJohn Fastabend 			break;
191416962b24SJohn Fastabend 		case 'r':
191516962b24SJohn Fastabend 			rate = atoi(optarg);
191616962b24SJohn Fastabend 			break;
191716962b24SJohn Fastabend 		case 'v':
191816962b24SJohn Fastabend 			options.verbose = 1;
1919b98ca90cSJohn Fastabend 			if (optarg)
1920b98ca90cSJohn Fastabend 				options.verbose = atoi(optarg);
192116962b24SJohn Fastabend 			break;
192216962b24SJohn Fastabend 		case 'i':
192316962b24SJohn Fastabend 			iov_count = atoi(optarg);
192416962b24SJohn Fastabend 			break;
192516962b24SJohn Fastabend 		case 'l':
192616962b24SJohn Fastabend 			length = atoi(optarg);
192716962b24SJohn Fastabend 			break;
192816962b24SJohn Fastabend 		case 'd':
192916962b24SJohn Fastabend 			options.data_test = true;
193016962b24SJohn Fastabend 			break;
193116962b24SJohn Fastabend 		case 't':
193216962b24SJohn Fastabend 			if (strcmp(optarg, "ping") == 0) {
193316962b24SJohn Fastabend 				test = PING_PONG;
193416962b24SJohn Fastabend 			} else if (strcmp(optarg, "sendmsg") == 0) {
193516962b24SJohn Fastabend 				test = SENDMSG;
193616962b24SJohn Fastabend 			} else if (strcmp(optarg, "base") == 0) {
193716962b24SJohn Fastabend 				test = BASE;
193816962b24SJohn Fastabend 			} else if (strcmp(optarg, "base_sendpage") == 0) {
193916962b24SJohn Fastabend 				test = BASE_SENDPAGE;
194016962b24SJohn Fastabend 			} else if (strcmp(optarg, "sendpage") == 0) {
194116962b24SJohn Fastabend 				test = SENDPAGE;
194216962b24SJohn Fastabend 			} else {
194316962b24SJohn Fastabend 				usage(argv);
194416962b24SJohn Fastabend 				return -1;
194516962b24SJohn Fastabend 			}
194616962b24SJohn Fastabend 			break;
1947065a74cbSJohn Fastabend 		case 'n':
1948065a74cbSJohn Fastabend 			options.whitelist = strdup(optarg);
1949065a74cbSJohn Fastabend 			if (!options.whitelist)
1950065a74cbSJohn Fastabend 				return -ENOMEM;
1951a7238f7cSJohn Fastabend 			break;
1952a7238f7cSJohn Fastabend 		case 'b':
1953a7238f7cSJohn Fastabend 			options.blacklist = strdup(optarg);
1954a7238f7cSJohn Fastabend 			if (!options.blacklist)
1955a7238f7cSJohn Fastabend 				return -ENOMEM;
195616962b24SJohn Fastabend 		case 0:
195716962b24SJohn Fastabend 			break;
195816962b24SJohn Fastabend 		case 'h':
195916962b24SJohn Fastabend 		default:
196016962b24SJohn Fastabend 			usage(argv);
196116962b24SJohn Fastabend 			return -1;
196216962b24SJohn Fastabend 		}
196316962b24SJohn Fastabend 	}
196416962b24SJohn Fastabend 
196516962b24SJohn Fastabend 	if (!cg_fd) {
196613a5f3ffSJohn Fastabend 		if (setup_cgroup_environment()) {
196713a5f3ffSJohn Fastabend 			fprintf(stderr, "ERROR: cgroup env failed\n");
196813a5f3ffSJohn Fastabend 			return -EINVAL;
196913a5f3ffSJohn Fastabend 		}
197013a5f3ffSJohn Fastabend 
197113a5f3ffSJohn Fastabend 		cg_fd = create_and_get_cgroup(CG_PATH);
197213a5f3ffSJohn Fastabend 		if (cg_fd < 0) {
197313a5f3ffSJohn Fastabend 			fprintf(stderr,
197413a5f3ffSJohn Fastabend 				"ERROR: (%i) open cg path failed: %s\n",
197513a5f3ffSJohn Fastabend 				cg_fd, strerror(errno));
197613a5f3ffSJohn Fastabend 			return cg_fd;
197713a5f3ffSJohn Fastabend 		}
197813a5f3ffSJohn Fastabend 
197913a5f3ffSJohn Fastabend 		if (join_cgroup(CG_PATH)) {
198013a5f3ffSJohn Fastabend 			fprintf(stderr, "ERROR: failed to join cgroup\n");
198113a5f3ffSJohn Fastabend 			return -EINVAL;
198213a5f3ffSJohn Fastabend 		}
198313a5f3ffSJohn Fastabend 		cg_created = 1;
198416962b24SJohn Fastabend 	}
198516962b24SJohn Fastabend 
1986b98ca90cSJohn Fastabend 	if (test == SELFTESTS) {
1987b98ca90cSJohn Fastabend 		err = test_selftest(cg_fd, &options);
1988b98ca90cSJohn Fastabend 		goto out;
1989b98ca90cSJohn Fastabend 	}
1990b98ca90cSJohn Fastabend 
1991b8b394faSJohn Fastabend 	err = populate_progs(bpf_file);
199216962b24SJohn Fastabend 	if (err) {
199316962b24SJohn Fastabend 		fprintf(stderr, "populate program: (%s) %s\n",
199416962b24SJohn Fastabend 			bpf_file, strerror(errno));
199516962b24SJohn Fastabend 		return 1;
199616962b24SJohn Fastabend 	}
199716962b24SJohn Fastabend 	running = 1;
199816962b24SJohn Fastabend 
199916962b24SJohn Fastabend 	/* catch SIGINT */
200016962b24SJohn Fastabend 	signal(SIGINT, running_handler);
200116962b24SJohn Fastabend 
200216962b24SJohn Fastabend 	options.iov_count = iov_count;
200316962b24SJohn Fastabend 	options.iov_length = length;
200416962b24SJohn Fastabend 	options.rate = rate;
200516962b24SJohn Fastabend 
200616962b24SJohn Fastabend 	err = run_options(&options, cg_fd, test);
2007b98ca90cSJohn Fastabend out:
2008065a74cbSJohn Fastabend 	if (options.whitelist)
2009065a74cbSJohn Fastabend 		free(options.whitelist);
2010a7238f7cSJohn Fastabend 	if (options.blacklist)
2011a7238f7cSJohn Fastabend 		free(options.blacklist);
201213a5f3ffSJohn Fastabend 	if (cg_created)
201313a5f3ffSJohn Fastabend 		cleanup_cgroup_environment();
201416962b24SJohn Fastabend 	close(cg_fd);
201516962b24SJohn Fastabend 	return err;
201616962b24SJohn Fastabend }
201716962b24SJohn Fastabend 
201816962b24SJohn Fastabend void running_handler(int a)
201916962b24SJohn Fastabend {
202016962b24SJohn Fastabend 	running = 0;
202116962b24SJohn Fastabend }
2022