18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <inttypes.h>
38c2ecf20Sopenharmony_ci#include <stdio.h>
48c2ecf20Sopenharmony_ci#include <stdlib.h>
58c2ecf20Sopenharmony_ci#include <unistd.h>
68c2ecf20Sopenharmony_ci#include <errno.h>
78c2ecf20Sopenharmony_ci#include <string.h>
88c2ecf20Sopenharmony_ci#include <linux/bpf.h>
98c2ecf20Sopenharmony_ci#include <sys/types.h>
108c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
118c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "bpf_rlimit.h"
148c2ecf20Sopenharmony_ci#include "bpf_util.h"
158c2ecf20Sopenharmony_ci#include "cgroup_helpers.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "test_tcpbpf.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* 3 comes from one listening socket + both ends of the connection */
208c2ecf20Sopenharmony_ci#define EXPECTED_CLOSE_EVENTS		3
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define EXPECT_EQ(expected, actual, fmt)			\
238c2ecf20Sopenharmony_ci	do {							\
248c2ecf20Sopenharmony_ci		if ((expected) != (actual)) {			\
258c2ecf20Sopenharmony_ci			printf("  Value of: " #actual "\n"	\
268c2ecf20Sopenharmony_ci			       "    Actual: %" fmt "\n"		\
278c2ecf20Sopenharmony_ci			       "  Expected: %" fmt "\n",	\
288c2ecf20Sopenharmony_ci			       (actual), (expected));		\
298c2ecf20Sopenharmony_ci			ret--;					\
308c2ecf20Sopenharmony_ci		}						\
318c2ecf20Sopenharmony_ci	} while (0)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciint verify_result(const struct tcpbpf_globals *result)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	__u32 expected_events;
368c2ecf20Sopenharmony_ci	int ret = 0;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) |
398c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_RWND_INIT) |
408c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) |
418c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) |
428c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) |
438c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_NEEDS_ECN) |
448c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_STATE_CB) |
458c2ecf20Sopenharmony_ci			   (1 << BPF_SOCK_OPS_TCP_LISTEN_CB));
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	EXPECT_EQ(expected_events, result->event_map, "#" PRIx32);
488c2ecf20Sopenharmony_ci	EXPECT_EQ(501ULL, result->bytes_received, "llu");
498c2ecf20Sopenharmony_ci	EXPECT_EQ(1002ULL, result->bytes_acked, "llu");
508c2ecf20Sopenharmony_ci	EXPECT_EQ(1, result->data_segs_in, PRIu32);
518c2ecf20Sopenharmony_ci	EXPECT_EQ(1, result->data_segs_out, PRIu32);
528c2ecf20Sopenharmony_ci	EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32);
538c2ecf20Sopenharmony_ci	EXPECT_EQ(0, result->good_cb_test_rv, PRIu32);
548c2ecf20Sopenharmony_ci	EXPECT_EQ(1, result->num_listen, PRIu32);
558c2ecf20Sopenharmony_ci	EXPECT_EQ(EXPECTED_CLOSE_EVENTS, result->num_close_events, PRIu32);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	return ret;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ciint verify_sockopt_result(int sock_map_fd)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	__u32 key = 0;
638c2ecf20Sopenharmony_ci	int ret = 0;
648c2ecf20Sopenharmony_ci	int res;
658c2ecf20Sopenharmony_ci	int rv;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* check setsockopt for SAVE_SYN */
688c2ecf20Sopenharmony_ci	rv = bpf_map_lookup_elem(sock_map_fd, &key, &res);
698c2ecf20Sopenharmony_ci	EXPECT_EQ(0, rv, "d");
708c2ecf20Sopenharmony_ci	EXPECT_EQ(0, res, "d");
718c2ecf20Sopenharmony_ci	key = 1;
728c2ecf20Sopenharmony_ci	/* check getsockopt for SAVED_SYN */
738c2ecf20Sopenharmony_ci	rv = bpf_map_lookup_elem(sock_map_fd, &key, &res);
748c2ecf20Sopenharmony_ci	EXPECT_EQ(0, rv, "d");
758c2ecf20Sopenharmony_ci	EXPECT_EQ(1, res, "d");
768c2ecf20Sopenharmony_ci	return ret;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int bpf_find_map(const char *test, struct bpf_object *obj,
808c2ecf20Sopenharmony_ci			const char *name)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct bpf_map *map;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	map = bpf_object__find_map_by_name(obj, name);
858c2ecf20Sopenharmony_ci	if (!map) {
868c2ecf20Sopenharmony_ci		printf("%s:FAIL:map '%s' not found\n", test, name);
878c2ecf20Sopenharmony_ci		return -1;
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci	return bpf_map__fd(map);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciint main(int argc, char **argv)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	const char *file = "test_tcpbpf_kern.o";
958c2ecf20Sopenharmony_ci	int prog_fd, map_fd, sock_map_fd;
968c2ecf20Sopenharmony_ci	struct tcpbpf_globals g = {0};
978c2ecf20Sopenharmony_ci	const char *cg_path = "/foo";
988c2ecf20Sopenharmony_ci	int error = EXIT_FAILURE;
998c2ecf20Sopenharmony_ci	struct bpf_object *obj;
1008c2ecf20Sopenharmony_ci	int cg_fd = -1;
1018c2ecf20Sopenharmony_ci	int retry = 10;
1028c2ecf20Sopenharmony_ci	__u32 key = 0;
1038c2ecf20Sopenharmony_ci	int rv;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	cg_fd = cgroup_setup_and_join(cg_path);
1068c2ecf20Sopenharmony_ci	if (cg_fd < 0)
1078c2ecf20Sopenharmony_ci		goto err;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) {
1108c2ecf20Sopenharmony_ci		printf("FAILED: load_bpf_file failed for: %s\n", file);
1118c2ecf20Sopenharmony_ci		goto err;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0);
1158c2ecf20Sopenharmony_ci	if (rv) {
1168c2ecf20Sopenharmony_ci		printf("FAILED: bpf_prog_attach: %d (%s)\n",
1178c2ecf20Sopenharmony_ci		       error, strerror(errno));
1188c2ecf20Sopenharmony_ci		goto err;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (system("./tcp_server.py")) {
1228c2ecf20Sopenharmony_ci		printf("FAILED: TCP server\n");
1238c2ecf20Sopenharmony_ci		goto err;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	map_fd = bpf_find_map(__func__, obj, "global_map");
1278c2ecf20Sopenharmony_ci	if (map_fd < 0)
1288c2ecf20Sopenharmony_ci		goto err;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results");
1318c2ecf20Sopenharmony_ci	if (sock_map_fd < 0)
1328c2ecf20Sopenharmony_ci		goto err;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciretry_lookup:
1358c2ecf20Sopenharmony_ci	rv = bpf_map_lookup_elem(map_fd, &key, &g);
1368c2ecf20Sopenharmony_ci	if (rv != 0) {
1378c2ecf20Sopenharmony_ci		printf("FAILED: bpf_map_lookup_elem returns %d\n", rv);
1388c2ecf20Sopenharmony_ci		goto err;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (g.num_close_events != EXPECTED_CLOSE_EVENTS && retry--) {
1428c2ecf20Sopenharmony_ci		printf("Unexpected number of close events (%d), retrying!\n",
1438c2ecf20Sopenharmony_ci		       g.num_close_events);
1448c2ecf20Sopenharmony_ci		usleep(100);
1458c2ecf20Sopenharmony_ci		goto retry_lookup;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (verify_result(&g)) {
1498c2ecf20Sopenharmony_ci		printf("FAILED: Wrong stats\n");
1508c2ecf20Sopenharmony_ci		goto err;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (verify_sockopt_result(sock_map_fd)) {
1548c2ecf20Sopenharmony_ci		printf("FAILED: Wrong sockopt stats\n");
1558c2ecf20Sopenharmony_ci		goto err;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	printf("PASSED!\n");
1598c2ecf20Sopenharmony_ci	error = 0;
1608c2ecf20Sopenharmony_cierr:
1618c2ecf20Sopenharmony_ci	bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS);
1628c2ecf20Sopenharmony_ci	close(cg_fd);
1638c2ecf20Sopenharmony_ci	cleanup_cgroup_environment();
1648c2ecf20Sopenharmony_ci	return error;
1658c2ecf20Sopenharmony_ci}
166