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