xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/bpf/test_tcpbpf_user.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <inttypes.h>
3*4882a593Smuzhiyun #include <stdio.h>
4*4882a593Smuzhiyun #include <stdlib.h>
5*4882a593Smuzhiyun #include <unistd.h>
6*4882a593Smuzhiyun #include <errno.h>
7*4882a593Smuzhiyun #include <string.h>
8*4882a593Smuzhiyun #include <linux/bpf.h>
9*4882a593Smuzhiyun #include <sys/types.h>
10*4882a593Smuzhiyun #include <bpf/bpf.h>
11*4882a593Smuzhiyun #include <bpf/libbpf.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include "bpf_rlimit.h"
14*4882a593Smuzhiyun #include "bpf_util.h"
15*4882a593Smuzhiyun #include "cgroup_helpers.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "test_tcpbpf.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /* 3 comes from one listening socket + both ends of the connection */
20*4882a593Smuzhiyun #define EXPECTED_CLOSE_EVENTS		3
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define EXPECT_EQ(expected, actual, fmt)			\
23*4882a593Smuzhiyun 	do {							\
24*4882a593Smuzhiyun 		if ((expected) != (actual)) {			\
25*4882a593Smuzhiyun 			printf("  Value of: " #actual "\n"	\
26*4882a593Smuzhiyun 			       "    Actual: %" fmt "\n"		\
27*4882a593Smuzhiyun 			       "  Expected: %" fmt "\n",	\
28*4882a593Smuzhiyun 			       (actual), (expected));		\
29*4882a593Smuzhiyun 			ret--;					\
30*4882a593Smuzhiyun 		}						\
31*4882a593Smuzhiyun 	} while (0)
32*4882a593Smuzhiyun 
verify_result(const struct tcpbpf_globals * result)33*4882a593Smuzhiyun int verify_result(const struct tcpbpf_globals *result)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	__u32 expected_events;
36*4882a593Smuzhiyun 	int ret = 0;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) |
39*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_RWND_INIT) |
40*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) |
41*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) |
42*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) |
43*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_NEEDS_ECN) |
44*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_STATE_CB) |
45*4882a593Smuzhiyun 			   (1 << BPF_SOCK_OPS_TCP_LISTEN_CB));
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	EXPECT_EQ(expected_events, result->event_map, "#" PRIx32);
48*4882a593Smuzhiyun 	EXPECT_EQ(501ULL, result->bytes_received, "llu");
49*4882a593Smuzhiyun 	EXPECT_EQ(1002ULL, result->bytes_acked, "llu");
50*4882a593Smuzhiyun 	EXPECT_EQ(1, result->data_segs_in, PRIu32);
51*4882a593Smuzhiyun 	EXPECT_EQ(1, result->data_segs_out, PRIu32);
52*4882a593Smuzhiyun 	EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32);
53*4882a593Smuzhiyun 	EXPECT_EQ(0, result->good_cb_test_rv, PRIu32);
54*4882a593Smuzhiyun 	EXPECT_EQ(1, result->num_listen, PRIu32);
55*4882a593Smuzhiyun 	EXPECT_EQ(EXPECTED_CLOSE_EVENTS, result->num_close_events, PRIu32);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	return ret;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
verify_sockopt_result(int sock_map_fd)60*4882a593Smuzhiyun int verify_sockopt_result(int sock_map_fd)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	__u32 key = 0;
63*4882a593Smuzhiyun 	int ret = 0;
64*4882a593Smuzhiyun 	int res;
65*4882a593Smuzhiyun 	int rv;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	/* check setsockopt for SAVE_SYN */
68*4882a593Smuzhiyun 	rv = bpf_map_lookup_elem(sock_map_fd, &key, &res);
69*4882a593Smuzhiyun 	EXPECT_EQ(0, rv, "d");
70*4882a593Smuzhiyun 	EXPECT_EQ(0, res, "d");
71*4882a593Smuzhiyun 	key = 1;
72*4882a593Smuzhiyun 	/* check getsockopt for SAVED_SYN */
73*4882a593Smuzhiyun 	rv = bpf_map_lookup_elem(sock_map_fd, &key, &res);
74*4882a593Smuzhiyun 	EXPECT_EQ(0, rv, "d");
75*4882a593Smuzhiyun 	EXPECT_EQ(1, res, "d");
76*4882a593Smuzhiyun 	return ret;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
bpf_find_map(const char * test,struct bpf_object * obj,const char * name)79*4882a593Smuzhiyun static int bpf_find_map(const char *test, struct bpf_object *obj,
80*4882a593Smuzhiyun 			const char *name)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	struct bpf_map *map;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	map = bpf_object__find_map_by_name(obj, name);
85*4882a593Smuzhiyun 	if (!map) {
86*4882a593Smuzhiyun 		printf("%s:FAIL:map '%s' not found\n", test, name);
87*4882a593Smuzhiyun 		return -1;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 	return bpf_map__fd(map);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
main(int argc,char ** argv)92*4882a593Smuzhiyun int main(int argc, char **argv)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	const char *file = "test_tcpbpf_kern.o";
95*4882a593Smuzhiyun 	int prog_fd, map_fd, sock_map_fd;
96*4882a593Smuzhiyun 	struct tcpbpf_globals g = {0};
97*4882a593Smuzhiyun 	const char *cg_path = "/foo";
98*4882a593Smuzhiyun 	int error = EXIT_FAILURE;
99*4882a593Smuzhiyun 	struct bpf_object *obj;
100*4882a593Smuzhiyun 	int cg_fd = -1;
101*4882a593Smuzhiyun 	int retry = 10;
102*4882a593Smuzhiyun 	__u32 key = 0;
103*4882a593Smuzhiyun 	int rv;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	cg_fd = cgroup_setup_and_join(cg_path);
106*4882a593Smuzhiyun 	if (cg_fd < 0)
107*4882a593Smuzhiyun 		goto err;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) {
110*4882a593Smuzhiyun 		printf("FAILED: load_bpf_file failed for: %s\n", file);
111*4882a593Smuzhiyun 		goto err;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0);
115*4882a593Smuzhiyun 	if (rv) {
116*4882a593Smuzhiyun 		printf("FAILED: bpf_prog_attach: %d (%s)\n",
117*4882a593Smuzhiyun 		       error, strerror(errno));
118*4882a593Smuzhiyun 		goto err;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (system("./tcp_server.py")) {
122*4882a593Smuzhiyun 		printf("FAILED: TCP server\n");
123*4882a593Smuzhiyun 		goto err;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	map_fd = bpf_find_map(__func__, obj, "global_map");
127*4882a593Smuzhiyun 	if (map_fd < 0)
128*4882a593Smuzhiyun 		goto err;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results");
131*4882a593Smuzhiyun 	if (sock_map_fd < 0)
132*4882a593Smuzhiyun 		goto err;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun retry_lookup:
135*4882a593Smuzhiyun 	rv = bpf_map_lookup_elem(map_fd, &key, &g);
136*4882a593Smuzhiyun 	if (rv != 0) {
137*4882a593Smuzhiyun 		printf("FAILED: bpf_map_lookup_elem returns %d\n", rv);
138*4882a593Smuzhiyun 		goto err;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (g.num_close_events != EXPECTED_CLOSE_EVENTS && retry--) {
142*4882a593Smuzhiyun 		printf("Unexpected number of close events (%d), retrying!\n",
143*4882a593Smuzhiyun 		       g.num_close_events);
144*4882a593Smuzhiyun 		usleep(100);
145*4882a593Smuzhiyun 		goto retry_lookup;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (verify_result(&g)) {
149*4882a593Smuzhiyun 		printf("FAILED: Wrong stats\n");
150*4882a593Smuzhiyun 		goto err;
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (verify_sockopt_result(sock_map_fd)) {
154*4882a593Smuzhiyun 		printf("FAILED: Wrong sockopt stats\n");
155*4882a593Smuzhiyun 		goto err;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	printf("PASSED!\n");
159*4882a593Smuzhiyun 	error = 0;
160*4882a593Smuzhiyun err:
161*4882a593Smuzhiyun 	bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS);
162*4882a593Smuzhiyun 	close(cg_fd);
163*4882a593Smuzhiyun 	cleanup_cgroup_environment();
164*4882a593Smuzhiyun 	return error;
165*4882a593Smuzhiyun }
166