162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io
362306a36Sopenharmony_ci#include <stdio.h>
462306a36Sopenharmony_ci#include <stdlib.h>
562306a36Sopenharmony_ci#include <sys/socket.h>
662306a36Sopenharmony_ci#include <sys/ioctl.h>
762306a36Sopenharmony_ci#include <sys/select.h>
862306a36Sopenharmony_ci#include <netinet/in.h>
962306a36Sopenharmony_ci#include <arpa/inet.h>
1062306a36Sopenharmony_ci#include <unistd.h>
1162306a36Sopenharmony_ci#include <string.h>
1262306a36Sopenharmony_ci#include <errno.h>
1362306a36Sopenharmony_ci#include <stdbool.h>
1462306a36Sopenharmony_ci#include <signal.h>
1562306a36Sopenharmony_ci#include <fcntl.h>
1662306a36Sopenharmony_ci#include <sys/wait.h>
1762306a36Sopenharmony_ci#include <time.h>
1862306a36Sopenharmony_ci#include <sched.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <sys/time.h>
2162306a36Sopenharmony_ci#include <sys/types.h>
2262306a36Sopenharmony_ci#include <sys/sendfile.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/netlink.h>
2562306a36Sopenharmony_ci#include <linux/socket.h>
2662306a36Sopenharmony_ci#include <linux/sock_diag.h>
2762306a36Sopenharmony_ci#include <linux/bpf.h>
2862306a36Sopenharmony_ci#include <linux/if_link.h>
2962306a36Sopenharmony_ci#include <linux/tls.h>
3062306a36Sopenharmony_ci#include <assert.h>
3162306a36Sopenharmony_ci#include <libgen.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <getopt.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <bpf/bpf.h>
3662306a36Sopenharmony_ci#include <bpf/libbpf.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "bpf_util.h"
3962306a36Sopenharmony_ci#include "cgroup_helpers.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciint running;
4262306a36Sopenharmony_cistatic void running_handler(int a);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#ifndef TCP_ULP
4562306a36Sopenharmony_ci# define TCP_ULP 31
4662306a36Sopenharmony_ci#endif
4762306a36Sopenharmony_ci#ifndef SOL_TLS
4862306a36Sopenharmony_ci# define SOL_TLS 282
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* randomly selected ports for testing on lo */
5262306a36Sopenharmony_ci#define S1_PORT 10000
5362306a36Sopenharmony_ci#define S2_PORT 10001
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define BPF_SOCKMAP_FILENAME  "test_sockmap_kern.bpf.o"
5662306a36Sopenharmony_ci#define BPF_SOCKHASH_FILENAME "test_sockhash_kern.bpf.o"
5762306a36Sopenharmony_ci#define CG_PATH "/sockmap"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* global sockets */
6062306a36Sopenharmony_ciint s1, s2, c1, c2, p1, p2;
6162306a36Sopenharmony_ciint test_cnt;
6262306a36Sopenharmony_ciint passed;
6362306a36Sopenharmony_ciint failed;
6462306a36Sopenharmony_ciint map_fd[9];
6562306a36Sopenharmony_cistruct bpf_map *maps[9];
6662306a36Sopenharmony_ciint prog_fd[11];
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciint txmsg_pass;
6962306a36Sopenharmony_ciint txmsg_redir;
7062306a36Sopenharmony_ciint txmsg_drop;
7162306a36Sopenharmony_ciint txmsg_apply;
7262306a36Sopenharmony_ciint txmsg_cork;
7362306a36Sopenharmony_ciint txmsg_start;
7462306a36Sopenharmony_ciint txmsg_end;
7562306a36Sopenharmony_ciint txmsg_start_push;
7662306a36Sopenharmony_ciint txmsg_end_push;
7762306a36Sopenharmony_ciint txmsg_start_pop;
7862306a36Sopenharmony_ciint txmsg_pop;
7962306a36Sopenharmony_ciint txmsg_ingress;
8062306a36Sopenharmony_ciint txmsg_redir_skb;
8162306a36Sopenharmony_ciint txmsg_ktls_skb;
8262306a36Sopenharmony_ciint txmsg_ktls_skb_drop;
8362306a36Sopenharmony_ciint txmsg_ktls_skb_redir;
8462306a36Sopenharmony_ciint ktls;
8562306a36Sopenharmony_ciint peek_flag;
8662306a36Sopenharmony_ciint skb_use_parser;
8762306a36Sopenharmony_ciint txmsg_omit_skb_parser;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic const struct option long_options[] = {
9062306a36Sopenharmony_ci	{"help",	no_argument,		NULL, 'h' },
9162306a36Sopenharmony_ci	{"cgroup",	required_argument,	NULL, 'c' },
9262306a36Sopenharmony_ci	{"rate",	required_argument,	NULL, 'r' },
9362306a36Sopenharmony_ci	{"verbose",	optional_argument,	NULL, 'v' },
9462306a36Sopenharmony_ci	{"iov_count",	required_argument,	NULL, 'i' },
9562306a36Sopenharmony_ci	{"length",	required_argument,	NULL, 'l' },
9662306a36Sopenharmony_ci	{"test",	required_argument,	NULL, 't' },
9762306a36Sopenharmony_ci	{"data_test",   no_argument,		NULL, 'd' },
9862306a36Sopenharmony_ci	{"txmsg",		no_argument,	&txmsg_pass,  1  },
9962306a36Sopenharmony_ci	{"txmsg_redir",		no_argument,	&txmsg_redir, 1  },
10062306a36Sopenharmony_ci	{"txmsg_drop",		no_argument,	&txmsg_drop, 1 },
10162306a36Sopenharmony_ci	{"txmsg_apply",	required_argument,	NULL, 'a'},
10262306a36Sopenharmony_ci	{"txmsg_cork",	required_argument,	NULL, 'k'},
10362306a36Sopenharmony_ci	{"txmsg_start", required_argument,	NULL, 's'},
10462306a36Sopenharmony_ci	{"txmsg_end",	required_argument,	NULL, 'e'},
10562306a36Sopenharmony_ci	{"txmsg_start_push", required_argument,	NULL, 'p'},
10662306a36Sopenharmony_ci	{"txmsg_end_push",   required_argument,	NULL, 'q'},
10762306a36Sopenharmony_ci	{"txmsg_start_pop",  required_argument,	NULL, 'w'},
10862306a36Sopenharmony_ci	{"txmsg_pop",	     required_argument,	NULL, 'x'},
10962306a36Sopenharmony_ci	{"txmsg_ingress", no_argument,		&txmsg_ingress, 1 },
11062306a36Sopenharmony_ci	{"txmsg_redir_skb", no_argument,	&txmsg_redir_skb, 1 },
11162306a36Sopenharmony_ci	{"ktls", no_argument,			&ktls, 1 },
11262306a36Sopenharmony_ci	{"peek", no_argument,			&peek_flag, 1 },
11362306a36Sopenharmony_ci	{"txmsg_omit_skb_parser", no_argument,      &txmsg_omit_skb_parser, 1},
11462306a36Sopenharmony_ci	{"whitelist", required_argument,	NULL, 'n' },
11562306a36Sopenharmony_ci	{"blacklist", required_argument,	NULL, 'b' },
11662306a36Sopenharmony_ci	{0, 0, NULL, 0 }
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct test_env {
12062306a36Sopenharmony_ci	const char *type;
12162306a36Sopenharmony_ci	const char *subtest;
12262306a36Sopenharmony_ci	const char *prepend;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	int test_num;
12562306a36Sopenharmony_ci	int subtest_num;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	int succ_cnt;
12862306a36Sopenharmony_ci	int fail_cnt;
12962306a36Sopenharmony_ci	int fail_last;
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistruct test_env env;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistruct sockmap_options {
13562306a36Sopenharmony_ci	int verbose;
13662306a36Sopenharmony_ci	bool base;
13762306a36Sopenharmony_ci	bool sendpage;
13862306a36Sopenharmony_ci	bool data_test;
13962306a36Sopenharmony_ci	bool drop_expected;
14062306a36Sopenharmony_ci	bool check_recved_len;
14162306a36Sopenharmony_ci	bool tx_wait_mem;
14262306a36Sopenharmony_ci	int iov_count;
14362306a36Sopenharmony_ci	int iov_length;
14462306a36Sopenharmony_ci	int rate;
14562306a36Sopenharmony_ci	char *map;
14662306a36Sopenharmony_ci	char *whitelist;
14762306a36Sopenharmony_ci	char *blacklist;
14862306a36Sopenharmony_ci	char *prepend;
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistruct _test {
15262306a36Sopenharmony_ci	char *title;
15362306a36Sopenharmony_ci	void (*tester)(int cg_fd, struct sockmap_options *opt);
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void test_start(void)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	env.subtest_num++;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void test_fail(void)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	env.fail_cnt++;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void test_pass(void)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	env.succ_cnt++;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void test_reset(void)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	txmsg_start = txmsg_end = 0;
17462306a36Sopenharmony_ci	txmsg_start_pop = txmsg_pop = 0;
17562306a36Sopenharmony_ci	txmsg_start_push = txmsg_end_push = 0;
17662306a36Sopenharmony_ci	txmsg_pass = txmsg_drop = txmsg_redir = 0;
17762306a36Sopenharmony_ci	txmsg_apply = txmsg_cork = 0;
17862306a36Sopenharmony_ci	txmsg_ingress = txmsg_redir_skb = 0;
17962306a36Sopenharmony_ci	txmsg_ktls_skb = txmsg_ktls_skb_drop = txmsg_ktls_skb_redir = 0;
18062306a36Sopenharmony_ci	txmsg_omit_skb_parser = 0;
18162306a36Sopenharmony_ci	skb_use_parser = 0;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int test_start_subtest(const struct _test *t, struct sockmap_options *o)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	env.type = o->map;
18762306a36Sopenharmony_ci	env.subtest = t->title;
18862306a36Sopenharmony_ci	env.prepend = o->prepend;
18962306a36Sopenharmony_ci	env.test_num++;
19062306a36Sopenharmony_ci	env.subtest_num = 0;
19162306a36Sopenharmony_ci	env.fail_last = env.fail_cnt;
19262306a36Sopenharmony_ci	test_reset();
19362306a36Sopenharmony_ci	return 0;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic void test_end_subtest(void)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int error = env.fail_cnt - env.fail_last;
19962306a36Sopenharmony_ci	int type = strcmp(env.type, BPF_SOCKMAP_FILENAME);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (!error)
20262306a36Sopenharmony_ci		test_pass();
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	fprintf(stdout, "#%2d/%2d %8s:%s:%s:%s\n",
20562306a36Sopenharmony_ci		env.test_num, env.subtest_num,
20662306a36Sopenharmony_ci		!type ? "sockmap" : "sockhash",
20762306a36Sopenharmony_ci		env.prepend ? : "",
20862306a36Sopenharmony_ci		env.subtest, error ? "FAIL" : "OK");
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic void test_print_results(void)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	fprintf(stdout, "Pass: %d Fail: %d\n",
21462306a36Sopenharmony_ci		env.succ_cnt, env.fail_cnt);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void usage(char *argv[])
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	int i;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
22262306a36Sopenharmony_ci	printf(" options:\n");
22362306a36Sopenharmony_ci	for (i = 0; long_options[i].name != 0; i++) {
22462306a36Sopenharmony_ci		printf(" --%-12s", long_options[i].name);
22562306a36Sopenharmony_ci		if (long_options[i].flag != NULL)
22662306a36Sopenharmony_ci			printf(" flag (internal value:%d)\n",
22762306a36Sopenharmony_ci				*long_options[i].flag);
22862306a36Sopenharmony_ci		else
22962306a36Sopenharmony_ci			printf(" -%c\n", long_options[i].val);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	printf("\n");
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cichar *sock_to_string(int s)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	if (s == c1)
23762306a36Sopenharmony_ci		return "client1";
23862306a36Sopenharmony_ci	else if (s == c2)
23962306a36Sopenharmony_ci		return "client2";
24062306a36Sopenharmony_ci	else if (s == s1)
24162306a36Sopenharmony_ci		return "server1";
24262306a36Sopenharmony_ci	else if (s == s2)
24362306a36Sopenharmony_ci		return "server2";
24462306a36Sopenharmony_ci	else if (s == p1)
24562306a36Sopenharmony_ci		return "peer1";
24662306a36Sopenharmony_ci	else if (s == p2)
24762306a36Sopenharmony_ci		return "peer2";
24862306a36Sopenharmony_ci	else
24962306a36Sopenharmony_ci		return "unknown";
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int sockmap_init_ktls(int verbose, int s)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct tls12_crypto_info_aes_gcm_128 tls_tx = {
25562306a36Sopenharmony_ci		.info = {
25662306a36Sopenharmony_ci			.version     = TLS_1_2_VERSION,
25762306a36Sopenharmony_ci			.cipher_type = TLS_CIPHER_AES_GCM_128,
25862306a36Sopenharmony_ci		},
25962306a36Sopenharmony_ci	};
26062306a36Sopenharmony_ci	struct tls12_crypto_info_aes_gcm_128 tls_rx = {
26162306a36Sopenharmony_ci		.info = {
26262306a36Sopenharmony_ci			.version     = TLS_1_2_VERSION,
26362306a36Sopenharmony_ci			.cipher_type = TLS_CIPHER_AES_GCM_128,
26462306a36Sopenharmony_ci		},
26562306a36Sopenharmony_ci	};
26662306a36Sopenharmony_ci	int so_buf = 6553500;
26762306a36Sopenharmony_ci	int err;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls"));
27062306a36Sopenharmony_ci	if (err) {
27162306a36Sopenharmony_ci		fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err);
27262306a36Sopenharmony_ci		return -EINVAL;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx));
27562306a36Sopenharmony_ci	if (err) {
27662306a36Sopenharmony_ci		fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err);
27762306a36Sopenharmony_ci		return -EINVAL;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci	err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx));
28062306a36Sopenharmony_ci	if (err) {
28162306a36Sopenharmony_ci		fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err);
28262306a36Sopenharmony_ci		return -EINVAL;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci	err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf));
28562306a36Sopenharmony_ci	if (err) {
28662306a36Sopenharmony_ci		fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err);
28762306a36Sopenharmony_ci		return -EINVAL;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf));
29062306a36Sopenharmony_ci	if (err) {
29162306a36Sopenharmony_ci		fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err);
29262306a36Sopenharmony_ci		return -EINVAL;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (verbose)
29662306a36Sopenharmony_ci		fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s));
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_cistatic int sockmap_init_sockets(int verbose)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	int i, err, one = 1;
30262306a36Sopenharmony_ci	struct sockaddr_in addr;
30362306a36Sopenharmony_ci	int *fds[4] = {&s1, &s2, &c1, &c2};
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	s1 = s2 = p1 = p2 = c1 = c2 = 0;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* Init sockets */
30862306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
30962306a36Sopenharmony_ci		*fds[i] = socket(AF_INET, SOCK_STREAM, 0);
31062306a36Sopenharmony_ci		if (*fds[i] < 0) {
31162306a36Sopenharmony_ci			perror("socket s1 failed()");
31262306a36Sopenharmony_ci			return errno;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* Allow reuse */
31762306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
31862306a36Sopenharmony_ci		err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
31962306a36Sopenharmony_ci				 (char *)&one, sizeof(one));
32062306a36Sopenharmony_ci		if (err) {
32162306a36Sopenharmony_ci			perror("setsockopt failed()");
32262306a36Sopenharmony_ci			return errno;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Non-blocking sockets */
32762306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
32862306a36Sopenharmony_ci		err = ioctl(*fds[i], FIONBIO, (char *)&one);
32962306a36Sopenharmony_ci		if (err < 0) {
33062306a36Sopenharmony_ci			perror("ioctl s1 failed()");
33162306a36Sopenharmony_ci			return errno;
33262306a36Sopenharmony_ci		}
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* Bind server sockets */
33662306a36Sopenharmony_ci	memset(&addr, 0, sizeof(struct sockaddr_in));
33762306a36Sopenharmony_ci	addr.sin_family = AF_INET;
33862306a36Sopenharmony_ci	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	addr.sin_port = htons(S1_PORT);
34162306a36Sopenharmony_ci	err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
34262306a36Sopenharmony_ci	if (err < 0) {
34362306a36Sopenharmony_ci		perror("bind s1 failed()");
34462306a36Sopenharmony_ci		return errno;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	addr.sin_port = htons(S2_PORT);
34862306a36Sopenharmony_ci	err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
34962306a36Sopenharmony_ci	if (err < 0) {
35062306a36Sopenharmony_ci		perror("bind s2 failed()");
35162306a36Sopenharmony_ci		return errno;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* Listen server sockets */
35562306a36Sopenharmony_ci	addr.sin_port = htons(S1_PORT);
35662306a36Sopenharmony_ci	err = listen(s1, 32);
35762306a36Sopenharmony_ci	if (err < 0) {
35862306a36Sopenharmony_ci		perror("listen s1 failed()");
35962306a36Sopenharmony_ci		return errno;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	addr.sin_port = htons(S2_PORT);
36362306a36Sopenharmony_ci	err = listen(s2, 32);
36462306a36Sopenharmony_ci	if (err < 0) {
36562306a36Sopenharmony_ci		perror("listen s1 failed()");
36662306a36Sopenharmony_ci		return errno;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* Initiate Connect */
37062306a36Sopenharmony_ci	addr.sin_port = htons(S1_PORT);
37162306a36Sopenharmony_ci	err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
37262306a36Sopenharmony_ci	if (err < 0 && errno != EINPROGRESS) {
37362306a36Sopenharmony_ci		perror("connect c1 failed()");
37462306a36Sopenharmony_ci		return errno;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	addr.sin_port = htons(S2_PORT);
37862306a36Sopenharmony_ci	err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
37962306a36Sopenharmony_ci	if (err < 0 && errno != EINPROGRESS) {
38062306a36Sopenharmony_ci		perror("connect c2 failed()");
38162306a36Sopenharmony_ci		return errno;
38262306a36Sopenharmony_ci	} else if (err < 0) {
38362306a36Sopenharmony_ci		err = 0;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Accept Connecrtions */
38762306a36Sopenharmony_ci	p1 = accept(s1, NULL, NULL);
38862306a36Sopenharmony_ci	if (p1 < 0) {
38962306a36Sopenharmony_ci		perror("accept s1 failed()");
39062306a36Sopenharmony_ci		return errno;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	p2 = accept(s2, NULL, NULL);
39462306a36Sopenharmony_ci	if (p2 < 0) {
39562306a36Sopenharmony_ci		perror("accept s1 failed()");
39662306a36Sopenharmony_ci		return errno;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (verbose > 1) {
40062306a36Sopenharmony_ci		printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
40162306a36Sopenharmony_ci		printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
40262306a36Sopenharmony_ci			c1, s1, c2, s2);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistruct msg_stats {
40862306a36Sopenharmony_ci	size_t bytes_sent;
40962306a36Sopenharmony_ci	size_t bytes_recvd;
41062306a36Sopenharmony_ci	struct timespec start;
41162306a36Sopenharmony_ci	struct timespec end;
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic int msg_loop_sendpage(int fd, int iov_length, int cnt,
41562306a36Sopenharmony_ci			     struct msg_stats *s,
41662306a36Sopenharmony_ci			     struct sockmap_options *opt)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	bool drop = opt->drop_expected;
41962306a36Sopenharmony_ci	unsigned char k = 0;
42062306a36Sopenharmony_ci	FILE *file;
42162306a36Sopenharmony_ci	int i, fp;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	file = tmpfile();
42462306a36Sopenharmony_ci	if (!file) {
42562306a36Sopenharmony_ci		perror("create file for sendpage");
42662306a36Sopenharmony_ci		return 1;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci	for (i = 0; i < iov_length * cnt; i++, k++)
42962306a36Sopenharmony_ci		fwrite(&k, sizeof(char), 1, file);
43062306a36Sopenharmony_ci	fflush(file);
43162306a36Sopenharmony_ci	fseek(file, 0, SEEK_SET);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	fp = fileno(file);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &s->start);
43662306a36Sopenharmony_ci	for (i = 0; i < cnt; i++) {
43762306a36Sopenharmony_ci		int sent;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		errno = 0;
44062306a36Sopenharmony_ci		sent = sendfile(fd, fp, NULL, iov_length);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		if (!drop && sent < 0) {
44362306a36Sopenharmony_ci			perror("sendpage loop error");
44462306a36Sopenharmony_ci			fclose(file);
44562306a36Sopenharmony_ci			return sent;
44662306a36Sopenharmony_ci		} else if (drop && sent >= 0) {
44762306a36Sopenharmony_ci			printf("sendpage loop error expected: %i errno %i\n",
44862306a36Sopenharmony_ci			       sent, errno);
44962306a36Sopenharmony_ci			fclose(file);
45062306a36Sopenharmony_ci			return -EIO;
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		if (sent > 0)
45462306a36Sopenharmony_ci			s->bytes_sent += sent;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &s->end);
45762306a36Sopenharmony_ci	fclose(file);
45862306a36Sopenharmony_ci	return 0;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void msg_free_iov(struct msghdr *msg)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	int i;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	for (i = 0; i < msg->msg_iovlen; i++)
46662306a36Sopenharmony_ci		free(msg->msg_iov[i].iov_base);
46762306a36Sopenharmony_ci	free(msg->msg_iov);
46862306a36Sopenharmony_ci	msg->msg_iov = NULL;
46962306a36Sopenharmony_ci	msg->msg_iovlen = 0;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic int msg_alloc_iov(struct msghdr *msg,
47362306a36Sopenharmony_ci			 int iov_count, int iov_length,
47462306a36Sopenharmony_ci			 bool data, bool xmit)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	unsigned char k = 0;
47762306a36Sopenharmony_ci	struct iovec *iov;
47862306a36Sopenharmony_ci	int i;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	iov = calloc(iov_count, sizeof(struct iovec));
48162306a36Sopenharmony_ci	if (!iov)
48262306a36Sopenharmony_ci		return errno;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	for (i = 0; i < iov_count; i++) {
48562306a36Sopenharmony_ci		unsigned char *d = calloc(iov_length, sizeof(char));
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		if (!d) {
48862306a36Sopenharmony_ci			fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
48962306a36Sopenharmony_ci			goto unwind_iov;
49062306a36Sopenharmony_ci		}
49162306a36Sopenharmony_ci		iov[i].iov_base = d;
49262306a36Sopenharmony_ci		iov[i].iov_len = iov_length;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		if (data && xmit) {
49562306a36Sopenharmony_ci			int j;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci			for (j = 0; j < iov_length; j++)
49862306a36Sopenharmony_ci				d[j] = k++;
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	msg->msg_iov = iov;
50362306a36Sopenharmony_ci	msg->msg_iovlen = iov_count;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	return 0;
50662306a36Sopenharmony_ciunwind_iov:
50762306a36Sopenharmony_ci	for (i--; i >= 0 ; i--)
50862306a36Sopenharmony_ci		free(msg->msg_iov[i].iov_base);
50962306a36Sopenharmony_ci	return -ENOMEM;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int msg_verify_data(struct msghdr *msg, int size, int chunk_sz)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	int i, j = 0, bytes_cnt = 0;
51562306a36Sopenharmony_ci	unsigned char k = 0;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	for (i = 0; i < msg->msg_iovlen; i++) {
51862306a36Sopenharmony_ci		unsigned char *d = msg->msg_iov[i].iov_base;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		/* Special case test for skb ingress + ktls */
52162306a36Sopenharmony_ci		if (i == 0 && txmsg_ktls_skb) {
52262306a36Sopenharmony_ci			if (msg->msg_iov[i].iov_len < 4)
52362306a36Sopenharmony_ci				return -EIO;
52462306a36Sopenharmony_ci			if (memcmp(d, "PASS", 4) != 0) {
52562306a36Sopenharmony_ci				fprintf(stderr,
52662306a36Sopenharmony_ci					"detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n",
52762306a36Sopenharmony_ci					i, 0, d[0], d[1], d[2], d[3]);
52862306a36Sopenharmony_ci				return -EIO;
52962306a36Sopenharmony_ci			}
53062306a36Sopenharmony_ci			j = 4; /* advance index past PASS header */
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		for (; j < msg->msg_iov[i].iov_len && size; j++) {
53462306a36Sopenharmony_ci			if (d[j] != k++) {
53562306a36Sopenharmony_ci				fprintf(stderr,
53662306a36Sopenharmony_ci					"detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
53762306a36Sopenharmony_ci					i, j, d[j], k - 1, d[j+1], k);
53862306a36Sopenharmony_ci				return -EIO;
53962306a36Sopenharmony_ci			}
54062306a36Sopenharmony_ci			bytes_cnt++;
54162306a36Sopenharmony_ci			if (bytes_cnt == chunk_sz) {
54262306a36Sopenharmony_ci				k = 0;
54362306a36Sopenharmony_ci				bytes_cnt = 0;
54462306a36Sopenharmony_ci			}
54562306a36Sopenharmony_ci			size--;
54662306a36Sopenharmony_ci		}
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic int msg_loop(int fd, int iov_count, int iov_length, int cnt,
55262306a36Sopenharmony_ci		    struct msg_stats *s, bool tx,
55362306a36Sopenharmony_ci		    struct sockmap_options *opt)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct msghdr msg = {0}, msg_peek = {0};
55662306a36Sopenharmony_ci	int err, i, flags = MSG_NOSIGNAL;
55762306a36Sopenharmony_ci	bool drop = opt->drop_expected;
55862306a36Sopenharmony_ci	bool data = opt->data_test;
55962306a36Sopenharmony_ci	int iov_alloc_length = iov_length;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (!tx && opt->check_recved_len)
56262306a36Sopenharmony_ci		iov_alloc_length *= 2;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	err = msg_alloc_iov(&msg, iov_count, iov_alloc_length, data, tx);
56562306a36Sopenharmony_ci	if (err)
56662306a36Sopenharmony_ci		goto out_errno;
56762306a36Sopenharmony_ci	if (peek_flag) {
56862306a36Sopenharmony_ci		err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx);
56962306a36Sopenharmony_ci		if (err)
57062306a36Sopenharmony_ci			goto out_errno;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (tx) {
57462306a36Sopenharmony_ci		clock_gettime(CLOCK_MONOTONIC, &s->start);
57562306a36Sopenharmony_ci		for (i = 0; i < cnt; i++) {
57662306a36Sopenharmony_ci			int sent;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci			errno = 0;
57962306a36Sopenharmony_ci			sent = sendmsg(fd, &msg, flags);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci			if (!drop && sent < 0) {
58262306a36Sopenharmony_ci				if (opt->tx_wait_mem && errno == EACCES) {
58362306a36Sopenharmony_ci					errno = 0;
58462306a36Sopenharmony_ci					goto out_errno;
58562306a36Sopenharmony_ci				}
58662306a36Sopenharmony_ci				perror("sendmsg loop error");
58762306a36Sopenharmony_ci				goto out_errno;
58862306a36Sopenharmony_ci			} else if (drop && sent >= 0) {
58962306a36Sopenharmony_ci				fprintf(stderr,
59062306a36Sopenharmony_ci					"sendmsg loop error expected: %i errno %i\n",
59162306a36Sopenharmony_ci					sent, errno);
59262306a36Sopenharmony_ci				errno = -EIO;
59362306a36Sopenharmony_ci				goto out_errno;
59462306a36Sopenharmony_ci			}
59562306a36Sopenharmony_ci			if (sent > 0)
59662306a36Sopenharmony_ci				s->bytes_sent += sent;
59762306a36Sopenharmony_ci		}
59862306a36Sopenharmony_ci		clock_gettime(CLOCK_MONOTONIC, &s->end);
59962306a36Sopenharmony_ci	} else {
60062306a36Sopenharmony_ci		int slct, recvp = 0, recv, max_fd = fd;
60162306a36Sopenharmony_ci		float total_bytes, txmsg_pop_total;
60262306a36Sopenharmony_ci		int fd_flags = O_NONBLOCK;
60362306a36Sopenharmony_ci		struct timeval timeout;
60462306a36Sopenharmony_ci		fd_set w;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		fcntl(fd, fd_flags);
60762306a36Sopenharmony_ci		/* Account for pop bytes noting each iteration of apply will
60862306a36Sopenharmony_ci		 * call msg_pop_data helper so we need to account for this
60962306a36Sopenharmony_ci		 * by calculating the number of apply iterations. Note user
61062306a36Sopenharmony_ci		 * of the tool can create cases where no data is sent by
61162306a36Sopenharmony_ci		 * manipulating pop/push/pull/etc. For example txmsg_apply 1
61262306a36Sopenharmony_ci		 * with txmsg_pop 1 will try to apply 1B at a time but each
61362306a36Sopenharmony_ci		 * iteration will then pop 1B so no data will ever be sent.
61462306a36Sopenharmony_ci		 * This is really only useful for testing edge cases in code
61562306a36Sopenharmony_ci		 * paths.
61662306a36Sopenharmony_ci		 */
61762306a36Sopenharmony_ci		total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
61862306a36Sopenharmony_ci		if (txmsg_apply)
61962306a36Sopenharmony_ci			txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply);
62062306a36Sopenharmony_ci		else
62162306a36Sopenharmony_ci			txmsg_pop_total = txmsg_pop * cnt;
62262306a36Sopenharmony_ci		total_bytes -= txmsg_pop_total;
62362306a36Sopenharmony_ci		err = clock_gettime(CLOCK_MONOTONIC, &s->start);
62462306a36Sopenharmony_ci		if (err < 0)
62562306a36Sopenharmony_ci			perror("recv start time");
62662306a36Sopenharmony_ci		while (s->bytes_recvd < total_bytes) {
62762306a36Sopenharmony_ci			if (txmsg_cork) {
62862306a36Sopenharmony_ci				timeout.tv_sec = 0;
62962306a36Sopenharmony_ci				timeout.tv_usec = 300000;
63062306a36Sopenharmony_ci			} else {
63162306a36Sopenharmony_ci				timeout.tv_sec = 3;
63262306a36Sopenharmony_ci				timeout.tv_usec = 0;
63362306a36Sopenharmony_ci			}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci			/* FD sets */
63662306a36Sopenharmony_ci			FD_ZERO(&w);
63762306a36Sopenharmony_ci			FD_SET(fd, &w);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci			slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
64062306a36Sopenharmony_ci			if (slct == -1) {
64162306a36Sopenharmony_ci				perror("select()");
64262306a36Sopenharmony_ci				clock_gettime(CLOCK_MONOTONIC, &s->end);
64362306a36Sopenharmony_ci				goto out_errno;
64462306a36Sopenharmony_ci			} else if (!slct) {
64562306a36Sopenharmony_ci				if (opt->verbose)
64662306a36Sopenharmony_ci					fprintf(stderr, "unexpected timeout: recved %zu/%f pop_total %f\n", s->bytes_recvd, total_bytes, txmsg_pop_total);
64762306a36Sopenharmony_ci				errno = -EIO;
64862306a36Sopenharmony_ci				clock_gettime(CLOCK_MONOTONIC, &s->end);
64962306a36Sopenharmony_ci				goto out_errno;
65062306a36Sopenharmony_ci			}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci			if (opt->tx_wait_mem) {
65362306a36Sopenharmony_ci				FD_ZERO(&w);
65462306a36Sopenharmony_ci				FD_SET(fd, &w);
65562306a36Sopenharmony_ci				slct = select(max_fd + 1, NULL, NULL, &w, &timeout);
65662306a36Sopenharmony_ci				errno = 0;
65762306a36Sopenharmony_ci				close(fd);
65862306a36Sopenharmony_ci				goto out_errno;
65962306a36Sopenharmony_ci			}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci			errno = 0;
66262306a36Sopenharmony_ci			if (peek_flag) {
66362306a36Sopenharmony_ci				flags |= MSG_PEEK;
66462306a36Sopenharmony_ci				recvp = recvmsg(fd, &msg_peek, flags);
66562306a36Sopenharmony_ci				if (recvp < 0) {
66662306a36Sopenharmony_ci					if (errno != EWOULDBLOCK) {
66762306a36Sopenharmony_ci						clock_gettime(CLOCK_MONOTONIC, &s->end);
66862306a36Sopenharmony_ci						goto out_errno;
66962306a36Sopenharmony_ci					}
67062306a36Sopenharmony_ci				}
67162306a36Sopenharmony_ci				flags = 0;
67262306a36Sopenharmony_ci			}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci			recv = recvmsg(fd, &msg, flags);
67562306a36Sopenharmony_ci			if (recv < 0) {
67662306a36Sopenharmony_ci				if (errno != EWOULDBLOCK) {
67762306a36Sopenharmony_ci					clock_gettime(CLOCK_MONOTONIC, &s->end);
67862306a36Sopenharmony_ci					perror("recv failed()");
67962306a36Sopenharmony_ci					goto out_errno;
68062306a36Sopenharmony_ci				}
68162306a36Sopenharmony_ci			}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci			s->bytes_recvd += recv;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci			if (opt->check_recved_len && s->bytes_recvd > total_bytes) {
68662306a36Sopenharmony_ci				errno = EMSGSIZE;
68762306a36Sopenharmony_ci				fprintf(stderr, "recv failed(), bytes_recvd:%zd, total_bytes:%f\n",
68862306a36Sopenharmony_ci						s->bytes_recvd, total_bytes);
68962306a36Sopenharmony_ci				goto out_errno;
69062306a36Sopenharmony_ci			}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci			if (data) {
69362306a36Sopenharmony_ci				int chunk_sz = opt->sendpage ?
69462306a36Sopenharmony_ci						iov_length * cnt :
69562306a36Sopenharmony_ci						iov_length * iov_count;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci				errno = msg_verify_data(&msg, recv, chunk_sz);
69862306a36Sopenharmony_ci				if (errno) {
69962306a36Sopenharmony_ci					perror("data verify msg failed");
70062306a36Sopenharmony_ci					goto out_errno;
70162306a36Sopenharmony_ci				}
70262306a36Sopenharmony_ci				if (recvp) {
70362306a36Sopenharmony_ci					errno = msg_verify_data(&msg_peek,
70462306a36Sopenharmony_ci								recvp,
70562306a36Sopenharmony_ci								chunk_sz);
70662306a36Sopenharmony_ci					if (errno) {
70762306a36Sopenharmony_ci						perror("data verify msg_peek failed");
70862306a36Sopenharmony_ci						goto out_errno;
70962306a36Sopenharmony_ci					}
71062306a36Sopenharmony_ci				}
71162306a36Sopenharmony_ci			}
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci		clock_gettime(CLOCK_MONOTONIC, &s->end);
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	msg_free_iov(&msg);
71762306a36Sopenharmony_ci	msg_free_iov(&msg_peek);
71862306a36Sopenharmony_ci	return err;
71962306a36Sopenharmony_ciout_errno:
72062306a36Sopenharmony_ci	msg_free_iov(&msg);
72162306a36Sopenharmony_ci	msg_free_iov(&msg_peek);
72262306a36Sopenharmony_ci	return errno;
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic float giga = 1000000000;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic inline float sentBps(struct msg_stats s)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic inline float recvdBps(struct msg_stats s)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic int sendmsg_test(struct sockmap_options *opt)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	float sent_Bps = 0, recvd_Bps = 0;
74062306a36Sopenharmony_ci	int rx_fd, txpid, rxpid, err = 0;
74162306a36Sopenharmony_ci	struct msg_stats s = {0};
74262306a36Sopenharmony_ci	int iov_count = opt->iov_count;
74362306a36Sopenharmony_ci	int iov_buf = opt->iov_length;
74462306a36Sopenharmony_ci	int rx_status, tx_status;
74562306a36Sopenharmony_ci	int cnt = opt->rate;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	errno = 0;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (opt->base)
75062306a36Sopenharmony_ci		rx_fd = p1;
75162306a36Sopenharmony_ci	else
75262306a36Sopenharmony_ci		rx_fd = p2;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (ktls) {
75562306a36Sopenharmony_ci		/* Redirecting into non-TLS socket which sends into a TLS
75662306a36Sopenharmony_ci		 * socket is not a valid test. So in this case lets not
75762306a36Sopenharmony_ci		 * enable kTLS but still run the test.
75862306a36Sopenharmony_ci		 */
75962306a36Sopenharmony_ci		if (!txmsg_redir || txmsg_ingress) {
76062306a36Sopenharmony_ci			err = sockmap_init_ktls(opt->verbose, rx_fd);
76162306a36Sopenharmony_ci			if (err)
76262306a36Sopenharmony_ci				return err;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci		err = sockmap_init_ktls(opt->verbose, c1);
76562306a36Sopenharmony_ci		if (err)
76662306a36Sopenharmony_ci			return err;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (opt->tx_wait_mem) {
77062306a36Sopenharmony_ci		struct timeval timeout;
77162306a36Sopenharmony_ci		int rxtx_buf_len = 1024;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		timeout.tv_sec = 3;
77462306a36Sopenharmony_ci		timeout.tv_usec = 0;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		err = setsockopt(c2, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval));
77762306a36Sopenharmony_ci		err |= setsockopt(c2, SOL_SOCKET, SO_SNDBUFFORCE, &rxtx_buf_len, sizeof(int));
77862306a36Sopenharmony_ci		err |= setsockopt(p2, SOL_SOCKET, SO_RCVBUFFORCE, &rxtx_buf_len, sizeof(int));
77962306a36Sopenharmony_ci		if (err) {
78062306a36Sopenharmony_ci			perror("setsockopt failed()");
78162306a36Sopenharmony_ci			return errno;
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	rxpid = fork();
78662306a36Sopenharmony_ci	if (rxpid == 0) {
78762306a36Sopenharmony_ci		if (txmsg_pop || txmsg_start_pop)
78862306a36Sopenharmony_ci			iov_buf -= (txmsg_pop - txmsg_start_pop + 1);
78962306a36Sopenharmony_ci		if (opt->drop_expected || txmsg_ktls_skb_drop)
79062306a36Sopenharmony_ci			_exit(0);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		if (!iov_buf) /* zero bytes sent case */
79362306a36Sopenharmony_ci			_exit(0);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		if (opt->sendpage)
79662306a36Sopenharmony_ci			iov_count = 1;
79762306a36Sopenharmony_ci		err = msg_loop(rx_fd, iov_count, iov_buf,
79862306a36Sopenharmony_ci			       cnt, &s, false, opt);
79962306a36Sopenharmony_ci		if (opt->verbose > 1)
80062306a36Sopenharmony_ci			fprintf(stderr,
80162306a36Sopenharmony_ci				"msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
80262306a36Sopenharmony_ci				iov_count, iov_buf, cnt, err);
80362306a36Sopenharmony_ci		if (s.end.tv_sec - s.start.tv_sec) {
80462306a36Sopenharmony_ci			sent_Bps = sentBps(s);
80562306a36Sopenharmony_ci			recvd_Bps = recvdBps(s);
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci		if (opt->verbose > 1)
80862306a36Sopenharmony_ci			fprintf(stdout,
80962306a36Sopenharmony_ci				"rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n",
81062306a36Sopenharmony_ci				s.bytes_sent, sent_Bps, sent_Bps/giga,
81162306a36Sopenharmony_ci				s.bytes_recvd, recvd_Bps, recvd_Bps/giga,
81262306a36Sopenharmony_ci				peek_flag ? "(peek_msg)" : "");
81362306a36Sopenharmony_ci		if (err && txmsg_cork)
81462306a36Sopenharmony_ci			err = 0;
81562306a36Sopenharmony_ci		exit(err ? 1 : 0);
81662306a36Sopenharmony_ci	} else if (rxpid == -1) {
81762306a36Sopenharmony_ci		perror("msg_loop_rx");
81862306a36Sopenharmony_ci		return errno;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (opt->tx_wait_mem)
82262306a36Sopenharmony_ci		close(c2);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	txpid = fork();
82562306a36Sopenharmony_ci	if (txpid == 0) {
82662306a36Sopenharmony_ci		if (opt->sendpage)
82762306a36Sopenharmony_ci			err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
82862306a36Sopenharmony_ci		else
82962306a36Sopenharmony_ci			err = msg_loop(c1, iov_count, iov_buf,
83062306a36Sopenharmony_ci				       cnt, &s, true, opt);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		if (err)
83362306a36Sopenharmony_ci			fprintf(stderr,
83462306a36Sopenharmony_ci				"msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
83562306a36Sopenharmony_ci				iov_count, iov_buf, cnt, err);
83662306a36Sopenharmony_ci		if (s.end.tv_sec - s.start.tv_sec) {
83762306a36Sopenharmony_ci			sent_Bps = sentBps(s);
83862306a36Sopenharmony_ci			recvd_Bps = recvdBps(s);
83962306a36Sopenharmony_ci		}
84062306a36Sopenharmony_ci		if (opt->verbose > 1)
84162306a36Sopenharmony_ci			fprintf(stdout,
84262306a36Sopenharmony_ci				"tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
84362306a36Sopenharmony_ci				s.bytes_sent, sent_Bps, sent_Bps/giga,
84462306a36Sopenharmony_ci				s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
84562306a36Sopenharmony_ci		exit(err ? 1 : 0);
84662306a36Sopenharmony_ci	} else if (txpid == -1) {
84762306a36Sopenharmony_ci		perror("msg_loop_tx");
84862306a36Sopenharmony_ci		return errno;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	assert(waitpid(rxpid, &rx_status, 0) == rxpid);
85262306a36Sopenharmony_ci	assert(waitpid(txpid, &tx_status, 0) == txpid);
85362306a36Sopenharmony_ci	if (WIFEXITED(rx_status)) {
85462306a36Sopenharmony_ci		err = WEXITSTATUS(rx_status);
85562306a36Sopenharmony_ci		if (err) {
85662306a36Sopenharmony_ci			fprintf(stderr, "rx thread exited with err %d.\n", err);
85762306a36Sopenharmony_ci			goto out;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci	if (WIFEXITED(tx_status)) {
86162306a36Sopenharmony_ci		err = WEXITSTATUS(tx_status);
86262306a36Sopenharmony_ci		if (err)
86362306a36Sopenharmony_ci			fprintf(stderr, "tx thread exited with err %d.\n", err);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ciout:
86662306a36Sopenharmony_ci	return err;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic int forever_ping_pong(int rate, struct sockmap_options *opt)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct timeval timeout;
87262306a36Sopenharmony_ci	char buf[1024] = {0};
87362306a36Sopenharmony_ci	int sc;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	timeout.tv_sec = 10;
87662306a36Sopenharmony_ci	timeout.tv_usec = 0;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* Ping/Pong data from client to server */
87962306a36Sopenharmony_ci	sc = send(c1, buf, sizeof(buf), 0);
88062306a36Sopenharmony_ci	if (sc < 0) {
88162306a36Sopenharmony_ci		perror("send failed()");
88262306a36Sopenharmony_ci		return sc;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	do {
88662306a36Sopenharmony_ci		int s, rc, i, max_fd = p2;
88762306a36Sopenharmony_ci		fd_set w;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		/* FD sets */
89062306a36Sopenharmony_ci		FD_ZERO(&w);
89162306a36Sopenharmony_ci		FD_SET(c1, &w);
89262306a36Sopenharmony_ci		FD_SET(c2, &w);
89362306a36Sopenharmony_ci		FD_SET(p1, &w);
89462306a36Sopenharmony_ci		FD_SET(p2, &w);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		s = select(max_fd + 1, &w, NULL, NULL, &timeout);
89762306a36Sopenharmony_ci		if (s == -1) {
89862306a36Sopenharmony_ci			perror("select()");
89962306a36Sopenharmony_ci			break;
90062306a36Sopenharmony_ci		} else if (!s) {
90162306a36Sopenharmony_ci			fprintf(stderr, "unexpected timeout\n");
90262306a36Sopenharmony_ci			break;
90362306a36Sopenharmony_ci		}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		for (i = 0; i <= max_fd && s > 0; ++i) {
90662306a36Sopenharmony_ci			if (!FD_ISSET(i, &w))
90762306a36Sopenharmony_ci				continue;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci			s--;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci			rc = recv(i, buf, sizeof(buf), 0);
91262306a36Sopenharmony_ci			if (rc < 0) {
91362306a36Sopenharmony_ci				if (errno != EWOULDBLOCK) {
91462306a36Sopenharmony_ci					perror("recv failed()");
91562306a36Sopenharmony_ci					return rc;
91662306a36Sopenharmony_ci				}
91762306a36Sopenharmony_ci			}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci			if (rc == 0) {
92062306a36Sopenharmony_ci				close(i);
92162306a36Sopenharmony_ci				break;
92262306a36Sopenharmony_ci			}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci			sc = send(i, buf, rc, 0);
92562306a36Sopenharmony_ci			if (sc < 0) {
92662306a36Sopenharmony_ci				perror("send failed()");
92762306a36Sopenharmony_ci				return sc;
92862306a36Sopenharmony_ci			}
92962306a36Sopenharmony_ci		}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		if (rate)
93262306a36Sopenharmony_ci			sleep(rate);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci		if (opt->verbose) {
93562306a36Sopenharmony_ci			printf(".");
93662306a36Sopenharmony_ci			fflush(stdout);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		}
93962306a36Sopenharmony_ci	} while (running);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	return 0;
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cienum {
94562306a36Sopenharmony_ci	SELFTESTS,
94662306a36Sopenharmony_ci	PING_PONG,
94762306a36Sopenharmony_ci	SENDMSG,
94862306a36Sopenharmony_ci	BASE,
94962306a36Sopenharmony_ci	BASE_SENDPAGE,
95062306a36Sopenharmony_ci	SENDPAGE,
95162306a36Sopenharmony_ci};
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic int run_options(struct sockmap_options *options, int cg_fd,  int test)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	/* If base test skip BPF setup */
95862306a36Sopenharmony_ci	if (test == BASE || test == BASE_SENDPAGE)
95962306a36Sopenharmony_ci		goto run;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* Attach programs to sockmap */
96262306a36Sopenharmony_ci	if (!txmsg_omit_skb_parser) {
96362306a36Sopenharmony_ci		err = bpf_prog_attach(prog_fd[0], map_fd[0],
96462306a36Sopenharmony_ci				      BPF_SK_SKB_STREAM_PARSER, 0);
96562306a36Sopenharmony_ci		if (err) {
96662306a36Sopenharmony_ci			fprintf(stderr,
96762306a36Sopenharmony_ci				"ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
96862306a36Sopenharmony_ci				prog_fd[0], map_fd[0], err, strerror(errno));
96962306a36Sopenharmony_ci			return err;
97062306a36Sopenharmony_ci		}
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	err = bpf_prog_attach(prog_fd[1], map_fd[0],
97462306a36Sopenharmony_ci				BPF_SK_SKB_STREAM_VERDICT, 0);
97562306a36Sopenharmony_ci	if (err) {
97662306a36Sopenharmony_ci		fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
97762306a36Sopenharmony_ci			err, strerror(errno));
97862306a36Sopenharmony_ci		return err;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* Attach programs to TLS sockmap */
98262306a36Sopenharmony_ci	if (txmsg_ktls_skb) {
98362306a36Sopenharmony_ci		if (!txmsg_omit_skb_parser) {
98462306a36Sopenharmony_ci			err = bpf_prog_attach(prog_fd[0], map_fd[8],
98562306a36Sopenharmony_ci					      BPF_SK_SKB_STREAM_PARSER, 0);
98662306a36Sopenharmony_ci			if (err) {
98762306a36Sopenharmony_ci				fprintf(stderr,
98862306a36Sopenharmony_ci					"ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n",
98962306a36Sopenharmony_ci					prog_fd[0], map_fd[8], err, strerror(errno));
99062306a36Sopenharmony_ci				return err;
99162306a36Sopenharmony_ci			}
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		err = bpf_prog_attach(prog_fd[2], map_fd[8],
99562306a36Sopenharmony_ci				      BPF_SK_SKB_STREAM_VERDICT, 0);
99662306a36Sopenharmony_ci		if (err) {
99762306a36Sopenharmony_ci			fprintf(stderr, "ERROR: bpf_prog_attach (TLS sockmap): %d (%s)\n",
99862306a36Sopenharmony_ci				err, strerror(errno));
99962306a36Sopenharmony_ci			return err;
100062306a36Sopenharmony_ci		}
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/* Attach to cgroups */
100462306a36Sopenharmony_ci	err = bpf_prog_attach(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
100562306a36Sopenharmony_ci	if (err) {
100662306a36Sopenharmony_ci		fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
100762306a36Sopenharmony_ci			err, strerror(errno));
100862306a36Sopenharmony_ci		return err;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cirun:
101262306a36Sopenharmony_ci	err = sockmap_init_sockets(options->verbose);
101362306a36Sopenharmony_ci	if (err) {
101462306a36Sopenharmony_ci		fprintf(stderr, "ERROR: test socket failed: %d\n", err);
101562306a36Sopenharmony_ci		goto out;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Attach txmsg program to sockmap */
101962306a36Sopenharmony_ci	if (txmsg_pass)
102062306a36Sopenharmony_ci		tx_prog_fd = prog_fd[4];
102162306a36Sopenharmony_ci	else if (txmsg_redir)
102262306a36Sopenharmony_ci		tx_prog_fd = prog_fd[5];
102362306a36Sopenharmony_ci	else if (txmsg_apply)
102462306a36Sopenharmony_ci		tx_prog_fd = prog_fd[6];
102562306a36Sopenharmony_ci	else if (txmsg_cork)
102662306a36Sopenharmony_ci		tx_prog_fd = prog_fd[7];
102762306a36Sopenharmony_ci	else if (txmsg_drop)
102862306a36Sopenharmony_ci		tx_prog_fd = prog_fd[8];
102962306a36Sopenharmony_ci	else
103062306a36Sopenharmony_ci		tx_prog_fd = 0;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (tx_prog_fd) {
103362306a36Sopenharmony_ci		int redir_fd, i = 0;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		err = bpf_prog_attach(tx_prog_fd,
103662306a36Sopenharmony_ci				      map_fd[1], BPF_SK_MSG_VERDICT, 0);
103762306a36Sopenharmony_ci		if (err) {
103862306a36Sopenharmony_ci			fprintf(stderr,
103962306a36Sopenharmony_ci				"ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
104062306a36Sopenharmony_ci				err, strerror(errno));
104162306a36Sopenharmony_ci			goto out;
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
104562306a36Sopenharmony_ci		if (err) {
104662306a36Sopenharmony_ci			fprintf(stderr,
104762306a36Sopenharmony_ci				"ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
104862306a36Sopenharmony_ci				err, strerror(errno));
104962306a36Sopenharmony_ci			goto out;
105062306a36Sopenharmony_ci		}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		if (txmsg_redir)
105362306a36Sopenharmony_ci			redir_fd = c2;
105462306a36Sopenharmony_ci		else
105562306a36Sopenharmony_ci			redir_fd = c1;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
105862306a36Sopenharmony_ci		if (err) {
105962306a36Sopenharmony_ci			fprintf(stderr,
106062306a36Sopenharmony_ci				"ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
106162306a36Sopenharmony_ci				err, strerror(errno));
106262306a36Sopenharmony_ci			goto out;
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		if (txmsg_apply) {
106662306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[3],
106762306a36Sopenharmony_ci						  &i, &txmsg_apply, BPF_ANY);
106862306a36Sopenharmony_ci			if (err) {
106962306a36Sopenharmony_ci				fprintf(stderr,
107062306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (apply_bytes):  %d (%s\n",
107162306a36Sopenharmony_ci					err, strerror(errno));
107262306a36Sopenharmony_ci				goto out;
107362306a36Sopenharmony_ci			}
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		if (txmsg_cork) {
107762306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[4],
107862306a36Sopenharmony_ci						  &i, &txmsg_cork, BPF_ANY);
107962306a36Sopenharmony_ci			if (err) {
108062306a36Sopenharmony_ci				fprintf(stderr,
108162306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (cork_bytes):  %d (%s\n",
108262306a36Sopenharmony_ci					err, strerror(errno));
108362306a36Sopenharmony_ci				goto out;
108462306a36Sopenharmony_ci			}
108562306a36Sopenharmony_ci		}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci		if (txmsg_start) {
108862306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[5],
108962306a36Sopenharmony_ci						  &i, &txmsg_start, BPF_ANY);
109062306a36Sopenharmony_ci			if (err) {
109162306a36Sopenharmony_ci				fprintf(stderr,
109262306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (txmsg_start):  %d (%s)\n",
109362306a36Sopenharmony_ci					err, strerror(errno));
109462306a36Sopenharmony_ci				goto out;
109562306a36Sopenharmony_ci			}
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci		if (txmsg_end) {
109962306a36Sopenharmony_ci			i = 1;
110062306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[5],
110162306a36Sopenharmony_ci						  &i, &txmsg_end, BPF_ANY);
110262306a36Sopenharmony_ci			if (err) {
110362306a36Sopenharmony_ci				fprintf(stderr,
110462306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (txmsg_end):  %d (%s)\n",
110562306a36Sopenharmony_ci					err, strerror(errno));
110662306a36Sopenharmony_ci				goto out;
110762306a36Sopenharmony_ci			}
110862306a36Sopenharmony_ci		}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		if (txmsg_start_push) {
111162306a36Sopenharmony_ci			i = 2;
111262306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[5],
111362306a36Sopenharmony_ci						  &i, &txmsg_start_push, BPF_ANY);
111462306a36Sopenharmony_ci			if (err) {
111562306a36Sopenharmony_ci				fprintf(stderr,
111662306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (txmsg_start_push):  %d (%s)\n",
111762306a36Sopenharmony_ci					err, strerror(errno));
111862306a36Sopenharmony_ci				goto out;
111962306a36Sopenharmony_ci			}
112062306a36Sopenharmony_ci		}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		if (txmsg_end_push) {
112362306a36Sopenharmony_ci			i = 3;
112462306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[5],
112562306a36Sopenharmony_ci						  &i, &txmsg_end_push, BPF_ANY);
112662306a36Sopenharmony_ci			if (err) {
112762306a36Sopenharmony_ci				fprintf(stderr,
112862306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem %i@%i (txmsg_end_push):  %d (%s)\n",
112962306a36Sopenharmony_ci					txmsg_end_push, i, err, strerror(errno));
113062306a36Sopenharmony_ci				goto out;
113162306a36Sopenharmony_ci			}
113262306a36Sopenharmony_ci		}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci		if (txmsg_start_pop) {
113562306a36Sopenharmony_ci			i = 4;
113662306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[5],
113762306a36Sopenharmony_ci						  &i, &txmsg_start_pop, BPF_ANY);
113862306a36Sopenharmony_ci			if (err) {
113962306a36Sopenharmony_ci				fprintf(stderr,
114062306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem %i@%i (txmsg_start_pop):  %d (%s)\n",
114162306a36Sopenharmony_ci					txmsg_start_pop, i, err, strerror(errno));
114262306a36Sopenharmony_ci				goto out;
114362306a36Sopenharmony_ci			}
114462306a36Sopenharmony_ci		} else {
114562306a36Sopenharmony_ci			i = 4;
114662306a36Sopenharmony_ci			bpf_map_update_elem(map_fd[5],
114762306a36Sopenharmony_ci						  &i, &txmsg_start_pop, BPF_ANY);
114862306a36Sopenharmony_ci		}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		if (txmsg_pop) {
115162306a36Sopenharmony_ci			i = 5;
115262306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[5],
115362306a36Sopenharmony_ci						  &i, &txmsg_pop, BPF_ANY);
115462306a36Sopenharmony_ci			if (err) {
115562306a36Sopenharmony_ci				fprintf(stderr,
115662306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem %i@%i (txmsg_pop):  %d (%s)\n",
115762306a36Sopenharmony_ci					txmsg_pop, i, err, strerror(errno));
115862306a36Sopenharmony_ci				goto out;
115962306a36Sopenharmony_ci			}
116062306a36Sopenharmony_ci		} else {
116162306a36Sopenharmony_ci			i = 5;
116262306a36Sopenharmony_ci			bpf_map_update_elem(map_fd[5],
116362306a36Sopenharmony_ci					    &i, &txmsg_pop, BPF_ANY);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci		if (txmsg_ingress) {
116862306a36Sopenharmony_ci			int in = BPF_F_INGRESS;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci			i = 0;
117162306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
117262306a36Sopenharmony_ci			if (err) {
117362306a36Sopenharmony_ci				fprintf(stderr,
117462306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
117562306a36Sopenharmony_ci					err, strerror(errno));
117662306a36Sopenharmony_ci			}
117762306a36Sopenharmony_ci			i = 1;
117862306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
117962306a36Sopenharmony_ci			if (err) {
118062306a36Sopenharmony_ci				fprintf(stderr,
118162306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
118262306a36Sopenharmony_ci					err, strerror(errno));
118362306a36Sopenharmony_ci			}
118462306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
118562306a36Sopenharmony_ci			if (err) {
118662306a36Sopenharmony_ci				fprintf(stderr,
118762306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
118862306a36Sopenharmony_ci					err, strerror(errno));
118962306a36Sopenharmony_ci			}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci			i = 2;
119262306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
119362306a36Sopenharmony_ci			if (err) {
119462306a36Sopenharmony_ci				fprintf(stderr,
119562306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
119662306a36Sopenharmony_ci					err, strerror(errno));
119762306a36Sopenharmony_ci			}
119862306a36Sopenharmony_ci		}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci		if (txmsg_ktls_skb) {
120162306a36Sopenharmony_ci			int ingress = BPF_F_INGRESS;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci			i = 0;
120462306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[8], &i, &p2, BPF_ANY);
120562306a36Sopenharmony_ci			if (err) {
120662306a36Sopenharmony_ci				fprintf(stderr,
120762306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
120862306a36Sopenharmony_ci					err, strerror(errno));
120962306a36Sopenharmony_ci			}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci			if (txmsg_ktls_skb_redir) {
121262306a36Sopenharmony_ci				i = 1;
121362306a36Sopenharmony_ci				err = bpf_map_update_elem(map_fd[7],
121462306a36Sopenharmony_ci							  &i, &ingress, BPF_ANY);
121562306a36Sopenharmony_ci				if (err) {
121662306a36Sopenharmony_ci					fprintf(stderr,
121762306a36Sopenharmony_ci						"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
121862306a36Sopenharmony_ci						err, strerror(errno));
121962306a36Sopenharmony_ci				}
122062306a36Sopenharmony_ci			}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci			if (txmsg_ktls_skb_drop) {
122362306a36Sopenharmony_ci				i = 1;
122462306a36Sopenharmony_ci				err = bpf_map_update_elem(map_fd[7], &i, &i, BPF_ANY);
122562306a36Sopenharmony_ci			}
122662306a36Sopenharmony_ci		}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		if (txmsg_redir_skb) {
122962306a36Sopenharmony_ci			int skb_fd = (test == SENDMSG || test == SENDPAGE) ?
123062306a36Sopenharmony_ci					p2 : p1;
123162306a36Sopenharmony_ci			int ingress = BPF_F_INGRESS;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci			i = 0;
123462306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[7],
123562306a36Sopenharmony_ci						  &i, &ingress, BPF_ANY);
123662306a36Sopenharmony_ci			if (err) {
123762306a36Sopenharmony_ci				fprintf(stderr,
123862306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
123962306a36Sopenharmony_ci					err, strerror(errno));
124062306a36Sopenharmony_ci			}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci			i = 3;
124362306a36Sopenharmony_ci			err = bpf_map_update_elem(map_fd[0], &i, &skb_fd, BPF_ANY);
124462306a36Sopenharmony_ci			if (err) {
124562306a36Sopenharmony_ci				fprintf(stderr,
124662306a36Sopenharmony_ci					"ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
124762306a36Sopenharmony_ci					err, strerror(errno));
124862306a36Sopenharmony_ci			}
124962306a36Sopenharmony_ci		}
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	if (skb_use_parser) {
125362306a36Sopenharmony_ci		i = 2;
125462306a36Sopenharmony_ci		err = bpf_map_update_elem(map_fd[7], &i, &skb_use_parser, BPF_ANY);
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (txmsg_drop)
125862306a36Sopenharmony_ci		options->drop_expected = true;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	if (test == PING_PONG)
126162306a36Sopenharmony_ci		err = forever_ping_pong(options->rate, options);
126262306a36Sopenharmony_ci	else if (test == SENDMSG) {
126362306a36Sopenharmony_ci		options->base = false;
126462306a36Sopenharmony_ci		options->sendpage = false;
126562306a36Sopenharmony_ci		err = sendmsg_test(options);
126662306a36Sopenharmony_ci	} else if (test == SENDPAGE) {
126762306a36Sopenharmony_ci		options->base = false;
126862306a36Sopenharmony_ci		options->sendpage = true;
126962306a36Sopenharmony_ci		err = sendmsg_test(options);
127062306a36Sopenharmony_ci	} else if (test == BASE) {
127162306a36Sopenharmony_ci		options->base = true;
127262306a36Sopenharmony_ci		options->sendpage = false;
127362306a36Sopenharmony_ci		err = sendmsg_test(options);
127462306a36Sopenharmony_ci	} else if (test == BASE_SENDPAGE) {
127562306a36Sopenharmony_ci		options->base = true;
127662306a36Sopenharmony_ci		options->sendpage = true;
127762306a36Sopenharmony_ci		err = sendmsg_test(options);
127862306a36Sopenharmony_ci	} else
127962306a36Sopenharmony_ci		fprintf(stderr, "unknown test\n");
128062306a36Sopenharmony_ciout:
128162306a36Sopenharmony_ci	/* Detatch and zero all the maps */
128262306a36Sopenharmony_ci	bpf_prog_detach2(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS);
128362306a36Sopenharmony_ci	bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER);
128462306a36Sopenharmony_ci	bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT);
128562306a36Sopenharmony_ci	bpf_prog_detach2(prog_fd[0], map_fd[8], BPF_SK_SKB_STREAM_PARSER);
128662306a36Sopenharmony_ci	bpf_prog_detach2(prog_fd[2], map_fd[8], BPF_SK_SKB_STREAM_VERDICT);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (tx_prog_fd >= 0)
128962306a36Sopenharmony_ci		bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
129262306a36Sopenharmony_ci		key = next_key = 0;
129362306a36Sopenharmony_ci		bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
129462306a36Sopenharmony_ci		while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) {
129562306a36Sopenharmony_ci			bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
129662306a36Sopenharmony_ci			key = next_key;
129762306a36Sopenharmony_ci		}
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	close(s1);
130162306a36Sopenharmony_ci	close(s2);
130262306a36Sopenharmony_ci	close(p1);
130362306a36Sopenharmony_ci	close(p2);
130462306a36Sopenharmony_ci	close(c1);
130562306a36Sopenharmony_ci	close(c2);
130662306a36Sopenharmony_ci	return err;
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cistatic char *test_to_str(int test)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	switch (test) {
131262306a36Sopenharmony_ci	case SENDMSG:
131362306a36Sopenharmony_ci		return "sendmsg";
131462306a36Sopenharmony_ci	case SENDPAGE:
131562306a36Sopenharmony_ci		return "sendpage";
131662306a36Sopenharmony_ci	}
131762306a36Sopenharmony_ci	return "unknown";
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic void append_str(char *dst, const char *src, size_t dst_cap)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	size_t avail = dst_cap - strlen(dst);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	if (avail <= 1) /* just zero byte could be written */
132562306a36Sopenharmony_ci		return;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	strncat(dst, src, avail - 1); /* strncat() adds + 1 for zero byte */
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci#define OPTSTRING 60
133162306a36Sopenharmony_cistatic void test_options(char *options)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	char tstr[OPTSTRING];
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	memset(options, 0, OPTSTRING);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (txmsg_pass)
133862306a36Sopenharmony_ci		append_str(options, "pass,", OPTSTRING);
133962306a36Sopenharmony_ci	if (txmsg_redir)
134062306a36Sopenharmony_ci		append_str(options, "redir,", OPTSTRING);
134162306a36Sopenharmony_ci	if (txmsg_drop)
134262306a36Sopenharmony_ci		append_str(options, "drop,", OPTSTRING);
134362306a36Sopenharmony_ci	if (txmsg_apply) {
134462306a36Sopenharmony_ci		snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply);
134562306a36Sopenharmony_ci		append_str(options, tstr, OPTSTRING);
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci	if (txmsg_cork) {
134862306a36Sopenharmony_ci		snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork);
134962306a36Sopenharmony_ci		append_str(options, tstr, OPTSTRING);
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci	if (txmsg_start) {
135262306a36Sopenharmony_ci		snprintf(tstr, OPTSTRING, "start %d,", txmsg_start);
135362306a36Sopenharmony_ci		append_str(options, tstr, OPTSTRING);
135462306a36Sopenharmony_ci	}
135562306a36Sopenharmony_ci	if (txmsg_end) {
135662306a36Sopenharmony_ci		snprintf(tstr, OPTSTRING, "end %d,", txmsg_end);
135762306a36Sopenharmony_ci		append_str(options, tstr, OPTSTRING);
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci	if (txmsg_start_pop) {
136062306a36Sopenharmony_ci		snprintf(tstr, OPTSTRING, "pop (%d,%d),",
136162306a36Sopenharmony_ci			 txmsg_start_pop, txmsg_start_pop + txmsg_pop);
136262306a36Sopenharmony_ci		append_str(options, tstr, OPTSTRING);
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci	if (txmsg_ingress)
136562306a36Sopenharmony_ci		append_str(options, "ingress,", OPTSTRING);
136662306a36Sopenharmony_ci	if (txmsg_redir_skb)
136762306a36Sopenharmony_ci		append_str(options, "redir_skb,", OPTSTRING);
136862306a36Sopenharmony_ci	if (txmsg_ktls_skb)
136962306a36Sopenharmony_ci		append_str(options, "ktls_skb,", OPTSTRING);
137062306a36Sopenharmony_ci	if (ktls)
137162306a36Sopenharmony_ci		append_str(options, "ktls,", OPTSTRING);
137262306a36Sopenharmony_ci	if (peek_flag)
137362306a36Sopenharmony_ci		append_str(options, "peek,", OPTSTRING);
137462306a36Sopenharmony_ci}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_cistatic int __test_exec(int cgrp, int test, struct sockmap_options *opt)
137762306a36Sopenharmony_ci{
137862306a36Sopenharmony_ci	char *options = calloc(OPTSTRING, sizeof(char));
137962306a36Sopenharmony_ci	int err;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	if (test == SENDPAGE)
138262306a36Sopenharmony_ci		opt->sendpage = true;
138362306a36Sopenharmony_ci	else
138462306a36Sopenharmony_ci		opt->sendpage = false;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (txmsg_drop)
138762306a36Sopenharmony_ci		opt->drop_expected = true;
138862306a36Sopenharmony_ci	else
138962306a36Sopenharmony_ci		opt->drop_expected = false;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	test_options(options);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	if (opt->verbose) {
139462306a36Sopenharmony_ci		fprintf(stdout,
139562306a36Sopenharmony_ci			" [TEST %i]: (%i, %i, %i, %s, %s): ",
139662306a36Sopenharmony_ci			test_cnt, opt->rate, opt->iov_count, opt->iov_length,
139762306a36Sopenharmony_ci			test_to_str(test), options);
139862306a36Sopenharmony_ci		fflush(stdout);
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci	err = run_options(opt, cgrp, test);
140162306a36Sopenharmony_ci	if (opt->verbose)
140262306a36Sopenharmony_ci		fprintf(stdout, " %s\n", !err ? "PASS" : "FAILED");
140362306a36Sopenharmony_ci	test_cnt++;
140462306a36Sopenharmony_ci	!err ? passed++ : failed++;
140562306a36Sopenharmony_ci	free(options);
140662306a36Sopenharmony_ci	return err;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic void test_exec(int cgrp, struct sockmap_options *opt)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	int type = strcmp(opt->map, BPF_SOCKMAP_FILENAME);
141262306a36Sopenharmony_ci	int err;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	if (type == 0) {
141562306a36Sopenharmony_ci		test_start();
141662306a36Sopenharmony_ci		err = __test_exec(cgrp, SENDMSG, opt);
141762306a36Sopenharmony_ci		if (err)
141862306a36Sopenharmony_ci			test_fail();
141962306a36Sopenharmony_ci	} else {
142062306a36Sopenharmony_ci		test_start();
142162306a36Sopenharmony_ci		err = __test_exec(cgrp, SENDPAGE, opt);
142262306a36Sopenharmony_ci		if (err)
142362306a36Sopenharmony_ci			test_fail();
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic void test_send_one(struct sockmap_options *opt, int cgrp)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	opt->iov_length = 1;
143062306a36Sopenharmony_ci	opt->iov_count = 1;
143162306a36Sopenharmony_ci	opt->rate = 1;
143262306a36Sopenharmony_ci	test_exec(cgrp, opt);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	opt->iov_length = 1;
143562306a36Sopenharmony_ci	opt->iov_count = 1024;
143662306a36Sopenharmony_ci	opt->rate = 1;
143762306a36Sopenharmony_ci	test_exec(cgrp, opt);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	opt->iov_length = 1024;
144062306a36Sopenharmony_ci	opt->iov_count = 1;
144162306a36Sopenharmony_ci	opt->rate = 1;
144262306a36Sopenharmony_ci	test_exec(cgrp, opt);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cistatic void test_send_many(struct sockmap_options *opt, int cgrp)
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	opt->iov_length = 3;
144962306a36Sopenharmony_ci	opt->iov_count = 1;
145062306a36Sopenharmony_ci	opt->rate = 512;
145162306a36Sopenharmony_ci	test_exec(cgrp, opt);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	opt->rate = 100;
145462306a36Sopenharmony_ci	opt->iov_count = 1;
145562306a36Sopenharmony_ci	opt->iov_length = 5;
145662306a36Sopenharmony_ci	test_exec(cgrp, opt);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic void test_send_large(struct sockmap_options *opt, int cgrp)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	opt->iov_length = 256;
146262306a36Sopenharmony_ci	opt->iov_count = 1024;
146362306a36Sopenharmony_ci	opt->rate = 2;
146462306a36Sopenharmony_ci	test_exec(cgrp, opt);
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_cistatic void test_send(struct sockmap_options *opt, int cgrp)
146862306a36Sopenharmony_ci{
146962306a36Sopenharmony_ci	test_send_one(opt, cgrp);
147062306a36Sopenharmony_ci	test_send_many(opt, cgrp);
147162306a36Sopenharmony_ci	test_send_large(opt, cgrp);
147262306a36Sopenharmony_ci	sched_yield();
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic void test_txmsg_pass(int cgrp, struct sockmap_options *opt)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	/* Test small and large iov_count values with pass/redir/apply/cork */
147862306a36Sopenharmony_ci	txmsg_pass = 1;
147962306a36Sopenharmony_ci	test_send(opt, cgrp);
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic void test_txmsg_redir(int cgrp, struct sockmap_options *opt)
148362306a36Sopenharmony_ci{
148462306a36Sopenharmony_ci	txmsg_redir = 1;
148562306a36Sopenharmony_ci	test_send(opt, cgrp);
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic void test_txmsg_redir_wait_sndmem(int cgrp, struct sockmap_options *opt)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	txmsg_redir = 1;
149162306a36Sopenharmony_ci	opt->tx_wait_mem = true;
149262306a36Sopenharmony_ci	test_send_large(opt, cgrp);
149362306a36Sopenharmony_ci	opt->tx_wait_mem = false;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_cistatic void test_txmsg_drop(int cgrp, struct sockmap_options *opt)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	txmsg_drop = 1;
149962306a36Sopenharmony_ci	test_send(opt, cgrp);
150062306a36Sopenharmony_ci}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_cistatic void test_txmsg_ingress_redir(int cgrp, struct sockmap_options *opt)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	txmsg_pass = txmsg_drop = 0;
150562306a36Sopenharmony_ci	txmsg_ingress = txmsg_redir = 1;
150662306a36Sopenharmony_ci	test_send(opt, cgrp);
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_cistatic void test_txmsg_skb(int cgrp, struct sockmap_options *opt)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	bool data = opt->data_test;
151262306a36Sopenharmony_ci	int k = ktls;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	opt->data_test = true;
151562306a36Sopenharmony_ci	ktls = 1;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	txmsg_pass = txmsg_drop = 0;
151862306a36Sopenharmony_ci	txmsg_ingress = txmsg_redir = 0;
151962306a36Sopenharmony_ci	txmsg_ktls_skb = 1;
152062306a36Sopenharmony_ci	txmsg_pass = 1;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	/* Using data verification so ensure iov layout is
152362306a36Sopenharmony_ci	 * expected from test receiver side. e.g. has enough
152462306a36Sopenharmony_ci	 * bytes to write test code.
152562306a36Sopenharmony_ci	 */
152662306a36Sopenharmony_ci	opt->iov_length = 100;
152762306a36Sopenharmony_ci	opt->iov_count = 1;
152862306a36Sopenharmony_ci	opt->rate = 1;
152962306a36Sopenharmony_ci	test_exec(cgrp, opt);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	txmsg_ktls_skb_drop = 1;
153262306a36Sopenharmony_ci	test_exec(cgrp, opt);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	txmsg_ktls_skb_drop = 0;
153562306a36Sopenharmony_ci	txmsg_ktls_skb_redir = 1;
153662306a36Sopenharmony_ci	test_exec(cgrp, opt);
153762306a36Sopenharmony_ci	txmsg_ktls_skb_redir = 0;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/* Tests that omit skb_parser */
154062306a36Sopenharmony_ci	txmsg_omit_skb_parser = 1;
154162306a36Sopenharmony_ci	ktls = 0;
154262306a36Sopenharmony_ci	txmsg_ktls_skb = 0;
154362306a36Sopenharmony_ci	test_exec(cgrp, opt);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	txmsg_ktls_skb_drop = 1;
154662306a36Sopenharmony_ci	test_exec(cgrp, opt);
154762306a36Sopenharmony_ci	txmsg_ktls_skb_drop = 0;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	txmsg_ktls_skb_redir = 1;
155062306a36Sopenharmony_ci	test_exec(cgrp, opt);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	ktls = 1;
155362306a36Sopenharmony_ci	test_exec(cgrp, opt);
155462306a36Sopenharmony_ci	txmsg_omit_skb_parser = 0;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	opt->data_test = data;
155762306a36Sopenharmony_ci	ktls = k;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci/* Test cork with hung data. This tests poor usage patterns where
156162306a36Sopenharmony_ci * cork can leave data on the ring if user program is buggy and
156262306a36Sopenharmony_ci * doesn't flush them somehow. They do take some time however
156362306a36Sopenharmony_ci * because they wait for a timeout. Test pass, redir and cork with
156462306a36Sopenharmony_ci * apply logic. Use cork size of 4097 with send_large to avoid
156562306a36Sopenharmony_ci * aligning cork size with send size.
156662306a36Sopenharmony_ci */
156762306a36Sopenharmony_cistatic void test_txmsg_cork_hangs(int cgrp, struct sockmap_options *opt)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	txmsg_pass = 1;
157062306a36Sopenharmony_ci	txmsg_redir = 0;
157162306a36Sopenharmony_ci	txmsg_cork = 4097;
157262306a36Sopenharmony_ci	txmsg_apply = 4097;
157362306a36Sopenharmony_ci	test_send_large(opt, cgrp);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	txmsg_pass = 0;
157662306a36Sopenharmony_ci	txmsg_redir = 1;
157762306a36Sopenharmony_ci	txmsg_apply = 0;
157862306a36Sopenharmony_ci	txmsg_cork = 4097;
157962306a36Sopenharmony_ci	test_send_large(opt, cgrp);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	txmsg_pass = 0;
158262306a36Sopenharmony_ci	txmsg_redir = 1;
158362306a36Sopenharmony_ci	txmsg_apply = 4097;
158462306a36Sopenharmony_ci	txmsg_cork = 4097;
158562306a36Sopenharmony_ci	test_send_large(opt, cgrp);
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic void test_txmsg_pull(int cgrp, struct sockmap_options *opt)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	/* Test basic start/end */
159162306a36Sopenharmony_ci	txmsg_start = 1;
159262306a36Sopenharmony_ci	txmsg_end = 2;
159362306a36Sopenharmony_ci	test_send(opt, cgrp);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	/* Test >4k pull */
159662306a36Sopenharmony_ci	txmsg_start = 4096;
159762306a36Sopenharmony_ci	txmsg_end = 9182;
159862306a36Sopenharmony_ci	test_send_large(opt, cgrp);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	/* Test pull + redirect */
160162306a36Sopenharmony_ci	txmsg_redir = 0;
160262306a36Sopenharmony_ci	txmsg_start = 1;
160362306a36Sopenharmony_ci	txmsg_end = 2;
160462306a36Sopenharmony_ci	test_send(opt, cgrp);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	/* Test pull + cork */
160762306a36Sopenharmony_ci	txmsg_redir = 0;
160862306a36Sopenharmony_ci	txmsg_cork = 512;
160962306a36Sopenharmony_ci	txmsg_start = 1;
161062306a36Sopenharmony_ci	txmsg_end = 2;
161162306a36Sopenharmony_ci	test_send_many(opt, cgrp);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	/* Test pull + cork + redirect */
161462306a36Sopenharmony_ci	txmsg_redir = 1;
161562306a36Sopenharmony_ci	txmsg_cork = 512;
161662306a36Sopenharmony_ci	txmsg_start = 1;
161762306a36Sopenharmony_ci	txmsg_end = 2;
161862306a36Sopenharmony_ci	test_send_many(opt, cgrp);
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	/* Test basic pop */
162462306a36Sopenharmony_ci	txmsg_start_pop = 1;
162562306a36Sopenharmony_ci	txmsg_pop = 2;
162662306a36Sopenharmony_ci	test_send_many(opt, cgrp);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	/* Test pop with >4k */
162962306a36Sopenharmony_ci	txmsg_start_pop = 4096;
163062306a36Sopenharmony_ci	txmsg_pop = 4096;
163162306a36Sopenharmony_ci	test_send_large(opt, cgrp);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	/* Test pop + redirect */
163462306a36Sopenharmony_ci	txmsg_redir = 1;
163562306a36Sopenharmony_ci	txmsg_start_pop = 1;
163662306a36Sopenharmony_ci	txmsg_pop = 2;
163762306a36Sopenharmony_ci	test_send_many(opt, cgrp);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	/* Test pop + cork */
164062306a36Sopenharmony_ci	txmsg_redir = 0;
164162306a36Sopenharmony_ci	txmsg_cork = 512;
164262306a36Sopenharmony_ci	txmsg_start_pop = 1;
164362306a36Sopenharmony_ci	txmsg_pop = 2;
164462306a36Sopenharmony_ci	test_send_many(opt, cgrp);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	/* Test pop + redirect + cork */
164762306a36Sopenharmony_ci	txmsg_redir = 1;
164862306a36Sopenharmony_ci	txmsg_cork = 4;
164962306a36Sopenharmony_ci	txmsg_start_pop = 1;
165062306a36Sopenharmony_ci	txmsg_pop = 2;
165162306a36Sopenharmony_ci	test_send_many(opt, cgrp);
165262306a36Sopenharmony_ci}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cistatic void test_txmsg_push(int cgrp, struct sockmap_options *opt)
165562306a36Sopenharmony_ci{
165662306a36Sopenharmony_ci	/* Test basic push */
165762306a36Sopenharmony_ci	txmsg_start_push = 1;
165862306a36Sopenharmony_ci	txmsg_end_push = 1;
165962306a36Sopenharmony_ci	test_send(opt, cgrp);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	/* Test push 4kB >4k */
166262306a36Sopenharmony_ci	txmsg_start_push = 4096;
166362306a36Sopenharmony_ci	txmsg_end_push = 4096;
166462306a36Sopenharmony_ci	test_send_large(opt, cgrp);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	/* Test push + redirect */
166762306a36Sopenharmony_ci	txmsg_redir = 1;
166862306a36Sopenharmony_ci	txmsg_start_push = 1;
166962306a36Sopenharmony_ci	txmsg_end_push = 2;
167062306a36Sopenharmony_ci	test_send_many(opt, cgrp);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	/* Test push + cork */
167362306a36Sopenharmony_ci	txmsg_redir = 0;
167462306a36Sopenharmony_ci	txmsg_cork = 512;
167562306a36Sopenharmony_ci	txmsg_start_push = 1;
167662306a36Sopenharmony_ci	txmsg_end_push = 2;
167762306a36Sopenharmony_ci	test_send_many(opt, cgrp);
167862306a36Sopenharmony_ci}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_cistatic void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	txmsg_start_push = 1;
168362306a36Sopenharmony_ci	txmsg_end_push = 10;
168462306a36Sopenharmony_ci	txmsg_start_pop = 5;
168562306a36Sopenharmony_ci	txmsg_pop = 4;
168662306a36Sopenharmony_ci	test_send_large(opt, cgrp);
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistatic void test_txmsg_apply(int cgrp, struct sockmap_options *opt)
169062306a36Sopenharmony_ci{
169162306a36Sopenharmony_ci	txmsg_pass = 1;
169262306a36Sopenharmony_ci	txmsg_redir = 0;
169362306a36Sopenharmony_ci	txmsg_ingress = 0;
169462306a36Sopenharmony_ci	txmsg_apply = 1;
169562306a36Sopenharmony_ci	txmsg_cork = 0;
169662306a36Sopenharmony_ci	test_send_one(opt, cgrp);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	txmsg_pass = 0;
169962306a36Sopenharmony_ci	txmsg_redir = 1;
170062306a36Sopenharmony_ci	txmsg_ingress = 0;
170162306a36Sopenharmony_ci	txmsg_apply = 1;
170262306a36Sopenharmony_ci	txmsg_cork = 0;
170362306a36Sopenharmony_ci	test_send_one(opt, cgrp);
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	txmsg_pass = 0;
170662306a36Sopenharmony_ci	txmsg_redir = 1;
170762306a36Sopenharmony_ci	txmsg_ingress = 1;
170862306a36Sopenharmony_ci	txmsg_apply = 1;
170962306a36Sopenharmony_ci	txmsg_cork = 0;
171062306a36Sopenharmony_ci	test_send_one(opt, cgrp);
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	txmsg_pass = 1;
171362306a36Sopenharmony_ci	txmsg_redir = 0;
171462306a36Sopenharmony_ci	txmsg_ingress = 0;
171562306a36Sopenharmony_ci	txmsg_apply = 1024;
171662306a36Sopenharmony_ci	txmsg_cork = 0;
171762306a36Sopenharmony_ci	test_send_large(opt, cgrp);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	txmsg_pass = 0;
172062306a36Sopenharmony_ci	txmsg_redir = 1;
172162306a36Sopenharmony_ci	txmsg_ingress = 0;
172262306a36Sopenharmony_ci	txmsg_apply = 1024;
172362306a36Sopenharmony_ci	txmsg_cork = 0;
172462306a36Sopenharmony_ci	test_send_large(opt, cgrp);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	txmsg_pass = 0;
172762306a36Sopenharmony_ci	txmsg_redir = 1;
172862306a36Sopenharmony_ci	txmsg_ingress = 1;
172962306a36Sopenharmony_ci	txmsg_apply = 1024;
173062306a36Sopenharmony_ci	txmsg_cork = 0;
173162306a36Sopenharmony_ci	test_send_large(opt, cgrp);
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_cistatic void test_txmsg_cork(int cgrp, struct sockmap_options *opt)
173562306a36Sopenharmony_ci{
173662306a36Sopenharmony_ci	txmsg_pass = 1;
173762306a36Sopenharmony_ci	txmsg_redir = 0;
173862306a36Sopenharmony_ci	txmsg_apply = 0;
173962306a36Sopenharmony_ci	txmsg_cork = 1;
174062306a36Sopenharmony_ci	test_send(opt, cgrp);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	txmsg_pass = 1;
174362306a36Sopenharmony_ci	txmsg_redir = 0;
174462306a36Sopenharmony_ci	txmsg_apply = 1;
174562306a36Sopenharmony_ci	txmsg_cork = 1;
174662306a36Sopenharmony_ci	test_send(opt, cgrp);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic void test_txmsg_ingress_parser(int cgrp, struct sockmap_options *opt)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	txmsg_pass = 1;
175262306a36Sopenharmony_ci	skb_use_parser = 512;
175362306a36Sopenharmony_ci	if (ktls == 1)
175462306a36Sopenharmony_ci		skb_use_parser = 570;
175562306a36Sopenharmony_ci	opt->iov_length = 256;
175662306a36Sopenharmony_ci	opt->iov_count = 1;
175762306a36Sopenharmony_ci	opt->rate = 2;
175862306a36Sopenharmony_ci	test_exec(cgrp, opt);
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic void test_txmsg_ingress_parser2(int cgrp, struct sockmap_options *opt)
176262306a36Sopenharmony_ci{
176362306a36Sopenharmony_ci	if (ktls == 1)
176462306a36Sopenharmony_ci		return;
176562306a36Sopenharmony_ci	skb_use_parser = 10;
176662306a36Sopenharmony_ci	opt->iov_length = 20;
176762306a36Sopenharmony_ci	opt->iov_count = 1;
176862306a36Sopenharmony_ci	opt->rate = 1;
176962306a36Sopenharmony_ci	opt->check_recved_len = true;
177062306a36Sopenharmony_ci	test_exec(cgrp, opt);
177162306a36Sopenharmony_ci	opt->check_recved_len = false;
177262306a36Sopenharmony_ci}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_cichar *map_names[] = {
177562306a36Sopenharmony_ci	"sock_map",
177662306a36Sopenharmony_ci	"sock_map_txmsg",
177762306a36Sopenharmony_ci	"sock_map_redir",
177862306a36Sopenharmony_ci	"sock_apply_bytes",
177962306a36Sopenharmony_ci	"sock_cork_bytes",
178062306a36Sopenharmony_ci	"sock_bytes",
178162306a36Sopenharmony_ci	"sock_redir_flags",
178262306a36Sopenharmony_ci	"sock_skb_opts",
178362306a36Sopenharmony_ci	"tls_sock_map",
178462306a36Sopenharmony_ci};
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ciint prog_attach_type[] = {
178762306a36Sopenharmony_ci	BPF_SK_SKB_STREAM_PARSER,
178862306a36Sopenharmony_ci	BPF_SK_SKB_STREAM_VERDICT,
178962306a36Sopenharmony_ci	BPF_SK_SKB_STREAM_VERDICT,
179062306a36Sopenharmony_ci	BPF_CGROUP_SOCK_OPS,
179162306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179262306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179362306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179462306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179562306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179662306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179762306a36Sopenharmony_ci	BPF_SK_MSG_VERDICT,
179862306a36Sopenharmony_ci};
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ciint prog_type[] = {
180162306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_SKB,
180262306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_SKB,
180362306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_SKB,
180462306a36Sopenharmony_ci	BPF_PROG_TYPE_SOCK_OPS,
180562306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
180662306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
180762306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
180862306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
180962306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
181062306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
181162306a36Sopenharmony_ci	BPF_PROG_TYPE_SK_MSG,
181262306a36Sopenharmony_ci};
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic int populate_progs(char *bpf_file)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	struct bpf_program *prog;
181762306a36Sopenharmony_ci	struct bpf_object *obj;
181862306a36Sopenharmony_ci	int i = 0;
181962306a36Sopenharmony_ci	long err;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	obj = bpf_object__open(bpf_file);
182262306a36Sopenharmony_ci	err = libbpf_get_error(obj);
182362306a36Sopenharmony_ci	if (err) {
182462306a36Sopenharmony_ci		char err_buf[256];
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci		libbpf_strerror(err, err_buf, sizeof(err_buf));
182762306a36Sopenharmony_ci		printf("Unable to load eBPF objects in file '%s' : %s\n",
182862306a36Sopenharmony_ci		       bpf_file, err_buf);
182962306a36Sopenharmony_ci		return -1;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
183362306a36Sopenharmony_ci		bpf_program__set_type(prog, prog_type[i]);
183462306a36Sopenharmony_ci		bpf_program__set_expected_attach_type(prog,
183562306a36Sopenharmony_ci						      prog_attach_type[i]);
183662306a36Sopenharmony_ci		i++;
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	i = bpf_object__load(obj);
184062306a36Sopenharmony_ci	i = 0;
184162306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
184262306a36Sopenharmony_ci		prog_fd[i] = bpf_program__fd(prog);
184362306a36Sopenharmony_ci		i++;
184462306a36Sopenharmony_ci	}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map_fd); i++) {
184762306a36Sopenharmony_ci		maps[i] = bpf_object__find_map_by_name(obj, map_names[i]);
184862306a36Sopenharmony_ci		map_fd[i] = bpf_map__fd(maps[i]);
184962306a36Sopenharmony_ci		if (map_fd[i] < 0) {
185062306a36Sopenharmony_ci			fprintf(stderr, "load_bpf_file: (%i) %s\n",
185162306a36Sopenharmony_ci				map_fd[i], strerror(errno));
185262306a36Sopenharmony_ci			return -1;
185362306a36Sopenharmony_ci		}
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	return 0;
185762306a36Sopenharmony_ci}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_cistruct _test test[] = {
186062306a36Sopenharmony_ci	{"txmsg test passthrough", test_txmsg_pass},
186162306a36Sopenharmony_ci	{"txmsg test redirect", test_txmsg_redir},
186262306a36Sopenharmony_ci	{"txmsg test redirect wait send mem", test_txmsg_redir_wait_sndmem},
186362306a36Sopenharmony_ci	{"txmsg test drop", test_txmsg_drop},
186462306a36Sopenharmony_ci	{"txmsg test ingress redirect", test_txmsg_ingress_redir},
186562306a36Sopenharmony_ci	{"txmsg test skb", test_txmsg_skb},
186662306a36Sopenharmony_ci	{"txmsg test apply", test_txmsg_apply},
186762306a36Sopenharmony_ci	{"txmsg test cork", test_txmsg_cork},
186862306a36Sopenharmony_ci	{"txmsg test hanging corks", test_txmsg_cork_hangs},
186962306a36Sopenharmony_ci	{"txmsg test push_data", test_txmsg_push},
187062306a36Sopenharmony_ci	{"txmsg test pull-data", test_txmsg_pull},
187162306a36Sopenharmony_ci	{"txmsg test pop-data", test_txmsg_pop},
187262306a36Sopenharmony_ci	{"txmsg test push/pop data", test_txmsg_push_pop},
187362306a36Sopenharmony_ci	{"txmsg test ingress parser", test_txmsg_ingress_parser},
187462306a36Sopenharmony_ci	{"txmsg test ingress parser2", test_txmsg_ingress_parser2},
187562306a36Sopenharmony_ci};
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_cistatic int check_whitelist(struct _test *t, struct sockmap_options *opt)
187862306a36Sopenharmony_ci{
187962306a36Sopenharmony_ci	char *entry, *ptr;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	if (!opt->whitelist)
188262306a36Sopenharmony_ci		return 0;
188362306a36Sopenharmony_ci	ptr = strdup(opt->whitelist);
188462306a36Sopenharmony_ci	if (!ptr)
188562306a36Sopenharmony_ci		return -ENOMEM;
188662306a36Sopenharmony_ci	entry = strtok(ptr, ",");
188762306a36Sopenharmony_ci	while (entry) {
188862306a36Sopenharmony_ci		if ((opt->prepend && strstr(opt->prepend, entry) != 0) ||
188962306a36Sopenharmony_ci		    strstr(opt->map, entry) != 0 ||
189062306a36Sopenharmony_ci		    strstr(t->title, entry) != 0)
189162306a36Sopenharmony_ci			return 0;
189262306a36Sopenharmony_ci		entry = strtok(NULL, ",");
189362306a36Sopenharmony_ci	}
189462306a36Sopenharmony_ci	return -EINVAL;
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cistatic int check_blacklist(struct _test *t, struct sockmap_options *opt)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	char *entry, *ptr;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	if (!opt->blacklist)
190262306a36Sopenharmony_ci		return -EINVAL;
190362306a36Sopenharmony_ci	ptr = strdup(opt->blacklist);
190462306a36Sopenharmony_ci	if (!ptr)
190562306a36Sopenharmony_ci		return -ENOMEM;
190662306a36Sopenharmony_ci	entry = strtok(ptr, ",");
190762306a36Sopenharmony_ci	while (entry) {
190862306a36Sopenharmony_ci		if ((opt->prepend && strstr(opt->prepend, entry) != 0) ||
190962306a36Sopenharmony_ci		    strstr(opt->map, entry) != 0 ||
191062306a36Sopenharmony_ci		    strstr(t->title, entry) != 0)
191162306a36Sopenharmony_ci			return 0;
191262306a36Sopenharmony_ci		entry = strtok(NULL, ",");
191362306a36Sopenharmony_ci	}
191462306a36Sopenharmony_ci	return -EINVAL;
191562306a36Sopenharmony_ci}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_cistatic int __test_selftests(int cg_fd, struct sockmap_options *opt)
191862306a36Sopenharmony_ci{
191962306a36Sopenharmony_ci	int i, err;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	err = populate_progs(opt->map);
192262306a36Sopenharmony_ci	if (err < 0) {
192362306a36Sopenharmony_ci		fprintf(stderr, "ERROR: (%i) load bpf failed\n", err);
192462306a36Sopenharmony_ci		return err;
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	/* Tests basic commands and APIs */
192862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test); i++) {
192962306a36Sopenharmony_ci		struct _test t = test[i];
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci		if (check_whitelist(&t, opt) != 0)
193262306a36Sopenharmony_ci			continue;
193362306a36Sopenharmony_ci		if (check_blacklist(&t, opt) == 0)
193462306a36Sopenharmony_ci			continue;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		test_start_subtest(&t, opt);
193762306a36Sopenharmony_ci		t.tester(cg_fd, opt);
193862306a36Sopenharmony_ci		test_end_subtest();
193962306a36Sopenharmony_ci	}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	return err;
194262306a36Sopenharmony_ci}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_cistatic void test_selftests_sockmap(int cg_fd, struct sockmap_options *opt)
194562306a36Sopenharmony_ci{
194662306a36Sopenharmony_ci	opt->map = BPF_SOCKMAP_FILENAME;
194762306a36Sopenharmony_ci	__test_selftests(cg_fd, opt);
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cistatic void test_selftests_sockhash(int cg_fd, struct sockmap_options *opt)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	opt->map = BPF_SOCKHASH_FILENAME;
195362306a36Sopenharmony_ci	__test_selftests(cg_fd, opt);
195462306a36Sopenharmony_ci}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_cistatic void test_selftests_ktls(int cg_fd, struct sockmap_options *opt)
195762306a36Sopenharmony_ci{
195862306a36Sopenharmony_ci	opt->map = BPF_SOCKHASH_FILENAME;
195962306a36Sopenharmony_ci	opt->prepend = "ktls";
196062306a36Sopenharmony_ci	ktls = 1;
196162306a36Sopenharmony_ci	__test_selftests(cg_fd, opt);
196262306a36Sopenharmony_ci	ktls = 0;
196362306a36Sopenharmony_ci}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_cistatic int test_selftest(int cg_fd, struct sockmap_options *opt)
196662306a36Sopenharmony_ci{
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	test_selftests_sockmap(cg_fd, opt);
196962306a36Sopenharmony_ci	test_selftests_sockhash(cg_fd, opt);
197062306a36Sopenharmony_ci	test_selftests_ktls(cg_fd, opt);
197162306a36Sopenharmony_ci	test_print_results();
197262306a36Sopenharmony_ci	return 0;
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ciint main(int argc, char **argv)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	int iov_count = 1, length = 1024, rate = 1;
197862306a36Sopenharmony_ci	struct sockmap_options options = {0};
197962306a36Sopenharmony_ci	int opt, longindex, err, cg_fd = 0;
198062306a36Sopenharmony_ci	char *bpf_file = BPF_SOCKMAP_FILENAME;
198162306a36Sopenharmony_ci	int test = SELFTESTS;
198262306a36Sopenharmony_ci	bool cg_created = 0;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	while ((opt = getopt_long(argc, argv, ":dhv:c:r:i:l:t:p:q:n:b:",
198562306a36Sopenharmony_ci				  long_options, &longindex)) != -1) {
198662306a36Sopenharmony_ci		switch (opt) {
198762306a36Sopenharmony_ci		case 's':
198862306a36Sopenharmony_ci			txmsg_start = atoi(optarg);
198962306a36Sopenharmony_ci			break;
199062306a36Sopenharmony_ci		case 'e':
199162306a36Sopenharmony_ci			txmsg_end = atoi(optarg);
199262306a36Sopenharmony_ci			break;
199362306a36Sopenharmony_ci		case 'p':
199462306a36Sopenharmony_ci			txmsg_start_push = atoi(optarg);
199562306a36Sopenharmony_ci			break;
199662306a36Sopenharmony_ci		case 'q':
199762306a36Sopenharmony_ci			txmsg_end_push = atoi(optarg);
199862306a36Sopenharmony_ci			break;
199962306a36Sopenharmony_ci		case 'w':
200062306a36Sopenharmony_ci			txmsg_start_pop = atoi(optarg);
200162306a36Sopenharmony_ci			break;
200262306a36Sopenharmony_ci		case 'x':
200362306a36Sopenharmony_ci			txmsg_pop = atoi(optarg);
200462306a36Sopenharmony_ci			break;
200562306a36Sopenharmony_ci		case 'a':
200662306a36Sopenharmony_ci			txmsg_apply = atoi(optarg);
200762306a36Sopenharmony_ci			break;
200862306a36Sopenharmony_ci		case 'k':
200962306a36Sopenharmony_ci			txmsg_cork = atoi(optarg);
201062306a36Sopenharmony_ci			break;
201162306a36Sopenharmony_ci		case 'c':
201262306a36Sopenharmony_ci			cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
201362306a36Sopenharmony_ci			if (cg_fd < 0) {
201462306a36Sopenharmony_ci				fprintf(stderr,
201562306a36Sopenharmony_ci					"ERROR: (%i) open cg path failed: %s\n",
201662306a36Sopenharmony_ci					cg_fd, optarg);
201762306a36Sopenharmony_ci				return cg_fd;
201862306a36Sopenharmony_ci			}
201962306a36Sopenharmony_ci			break;
202062306a36Sopenharmony_ci		case 'r':
202162306a36Sopenharmony_ci			rate = atoi(optarg);
202262306a36Sopenharmony_ci			break;
202362306a36Sopenharmony_ci		case 'v':
202462306a36Sopenharmony_ci			options.verbose = 1;
202562306a36Sopenharmony_ci			if (optarg)
202662306a36Sopenharmony_ci				options.verbose = atoi(optarg);
202762306a36Sopenharmony_ci			break;
202862306a36Sopenharmony_ci		case 'i':
202962306a36Sopenharmony_ci			iov_count = atoi(optarg);
203062306a36Sopenharmony_ci			break;
203162306a36Sopenharmony_ci		case 'l':
203262306a36Sopenharmony_ci			length = atoi(optarg);
203362306a36Sopenharmony_ci			break;
203462306a36Sopenharmony_ci		case 'd':
203562306a36Sopenharmony_ci			options.data_test = true;
203662306a36Sopenharmony_ci			break;
203762306a36Sopenharmony_ci		case 't':
203862306a36Sopenharmony_ci			if (strcmp(optarg, "ping") == 0) {
203962306a36Sopenharmony_ci				test = PING_PONG;
204062306a36Sopenharmony_ci			} else if (strcmp(optarg, "sendmsg") == 0) {
204162306a36Sopenharmony_ci				test = SENDMSG;
204262306a36Sopenharmony_ci			} else if (strcmp(optarg, "base") == 0) {
204362306a36Sopenharmony_ci				test = BASE;
204462306a36Sopenharmony_ci			} else if (strcmp(optarg, "base_sendpage") == 0) {
204562306a36Sopenharmony_ci				test = BASE_SENDPAGE;
204662306a36Sopenharmony_ci			} else if (strcmp(optarg, "sendpage") == 0) {
204762306a36Sopenharmony_ci				test = SENDPAGE;
204862306a36Sopenharmony_ci			} else {
204962306a36Sopenharmony_ci				usage(argv);
205062306a36Sopenharmony_ci				return -1;
205162306a36Sopenharmony_ci			}
205262306a36Sopenharmony_ci			break;
205362306a36Sopenharmony_ci		case 'n':
205462306a36Sopenharmony_ci			options.whitelist = strdup(optarg);
205562306a36Sopenharmony_ci			if (!options.whitelist)
205662306a36Sopenharmony_ci				return -ENOMEM;
205762306a36Sopenharmony_ci			break;
205862306a36Sopenharmony_ci		case 'b':
205962306a36Sopenharmony_ci			options.blacklist = strdup(optarg);
206062306a36Sopenharmony_ci			if (!options.blacklist)
206162306a36Sopenharmony_ci				return -ENOMEM;
206262306a36Sopenharmony_ci		case 0:
206362306a36Sopenharmony_ci			break;
206462306a36Sopenharmony_ci		case 'h':
206562306a36Sopenharmony_ci		default:
206662306a36Sopenharmony_ci			usage(argv);
206762306a36Sopenharmony_ci			return -1;
206862306a36Sopenharmony_ci		}
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	if (!cg_fd) {
207262306a36Sopenharmony_ci		cg_fd = cgroup_setup_and_join(CG_PATH);
207362306a36Sopenharmony_ci		if (cg_fd < 0)
207462306a36Sopenharmony_ci			return cg_fd;
207562306a36Sopenharmony_ci		cg_created = 1;
207662306a36Sopenharmony_ci	}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	/* Use libbpf 1.0 API mode */
207962306a36Sopenharmony_ci	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (test == SELFTESTS) {
208262306a36Sopenharmony_ci		err = test_selftest(cg_fd, &options);
208362306a36Sopenharmony_ci		goto out;
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	err = populate_progs(bpf_file);
208762306a36Sopenharmony_ci	if (err) {
208862306a36Sopenharmony_ci		fprintf(stderr, "populate program: (%s) %s\n",
208962306a36Sopenharmony_ci			bpf_file, strerror(errno));
209062306a36Sopenharmony_ci		return 1;
209162306a36Sopenharmony_ci	}
209262306a36Sopenharmony_ci	running = 1;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	/* catch SIGINT */
209562306a36Sopenharmony_ci	signal(SIGINT, running_handler);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	options.iov_count = iov_count;
209862306a36Sopenharmony_ci	options.iov_length = length;
209962306a36Sopenharmony_ci	options.rate = rate;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	err = run_options(&options, cg_fd, test);
210262306a36Sopenharmony_ciout:
210362306a36Sopenharmony_ci	if (options.whitelist)
210462306a36Sopenharmony_ci		free(options.whitelist);
210562306a36Sopenharmony_ci	if (options.blacklist)
210662306a36Sopenharmony_ci		free(options.blacklist);
210762306a36Sopenharmony_ci	if (cg_created)
210862306a36Sopenharmony_ci		cleanup_cgroup_environment();
210962306a36Sopenharmony_ci	close(cg_fd);
211062306a36Sopenharmony_ci	return err;
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_civoid running_handler(int a)
211462306a36Sopenharmony_ci{
211562306a36Sopenharmony_ci	running = 0;
211662306a36Sopenharmony_ci}
2117