1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #define _GNU_SOURCE |
3 | #include <pthread.h> |
4 | #include <inttypes.h> |
5 | #include <stdio.h> |
6 | #include <stdlib.h> |
7 | #include <unistd.h> |
8 | #include <asm/types.h> |
9 | #include <sys/syscall.h> |
10 | #include <errno.h> |
11 | #include <string.h> |
12 | #include <linux/bpf.h> |
13 | #include <sys/socket.h> |
14 | #include <bpf/bpf.h> |
15 | #include <bpf/libbpf.h> |
16 | #include <sys/ioctl.h> |
17 | #include <linux/rtnetlink.h> |
18 | #include <signal.h> |
19 | #include <linux/perf_event.h> |
20 | #include <linux/err.h> |
21 | |
22 | #include "bpf_util.h" |
23 | #include "cgroup_helpers.h" |
24 | |
25 | #include "test_tcpnotify.h" |
26 | #include "trace_helpers.h" |
27 | #include "testing_helpers.h" |
28 | |
29 | #define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) |
30 | |
31 | pthread_t tid; |
32 | int rx_callbacks; |
33 | |
34 | static void dummyfn(void *ctx, int cpu, void *data, __u32 size) |
35 | { |
36 | struct tcp_notifier *t = data; |
37 | |
38 | if (t->type != 0xde || t->subtype != 0xad || |
39 | t->source != 0xbe || t->hash != 0xef) |
40 | return; |
41 | rx_callbacks++; |
42 | } |
43 | |
44 | void tcp_notifier_poller(struct perf_buffer *pb) |
45 | { |
46 | int err; |
47 | |
48 | while (1) { |
49 | err = perf_buffer__poll(pb, 100); |
50 | if (err < 0 && err != -EINTR) { |
51 | printf("failed perf_buffer__poll: %d\n" , err); |
52 | return; |
53 | } |
54 | } |
55 | } |
56 | |
57 | static void *poller_thread(void *arg) |
58 | { |
59 | struct perf_buffer *pb = arg; |
60 | |
61 | tcp_notifier_poller(pb); |
62 | return arg; |
63 | } |
64 | |
65 | int verify_result(const struct tcpnotify_globals *result) |
66 | { |
67 | return (result->ncalls > 0 && result->ncalls == rx_callbacks ? 0 : 1); |
68 | } |
69 | |
70 | int main(int argc, char **argv) |
71 | { |
72 | const char *file = "test_tcpnotify_kern.bpf.o" ; |
73 | struct bpf_map *perf_map, *global_map; |
74 | struct tcpnotify_globals g = {0}; |
75 | struct perf_buffer *pb = NULL; |
76 | const char *cg_path = "/foo" ; |
77 | int prog_fd, rv, cg_fd = -1; |
78 | int error = EXIT_FAILURE; |
79 | struct bpf_object *obj; |
80 | char test_script[80]; |
81 | cpu_set_t cpuset; |
82 | __u32 key = 0; |
83 | |
84 | libbpf_set_strict_mode(LIBBPF_STRICT_ALL); |
85 | |
86 | CPU_ZERO(&cpuset); |
87 | CPU_SET(0, &cpuset); |
88 | pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); |
89 | |
90 | cg_fd = cgroup_setup_and_join(relative_path: cg_path); |
91 | if (cg_fd < 0) |
92 | goto err; |
93 | |
94 | if (bpf_prog_test_load(file, type: BPF_PROG_TYPE_SOCK_OPS, pobj: &obj, prog_fd: &prog_fd)) { |
95 | printf("FAILED: load_bpf_file failed for: %s\n" , file); |
96 | goto err; |
97 | } |
98 | |
99 | rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0); |
100 | if (rv) { |
101 | printf("FAILED: bpf_prog_attach: %d (%s)\n" , |
102 | error, strerror(errno)); |
103 | goto err; |
104 | } |
105 | |
106 | perf_map = bpf_object__find_map_by_name(obj, "perf_event_map" ); |
107 | if (!perf_map) { |
108 | printf("FAIL:map '%s' not found\n" , "perf_event_map" ); |
109 | goto err; |
110 | } |
111 | |
112 | global_map = bpf_object__find_map_by_name(obj, "global_map" ); |
113 | if (!global_map) { |
114 | printf("FAIL:map '%s' not found\n" , "global_map" ); |
115 | return -1; |
116 | } |
117 | |
118 | pb = perf_buffer__new(bpf_map__fd(perf_map), 8, dummyfn, NULL, NULL, NULL); |
119 | if (!pb) |
120 | goto err; |
121 | |
122 | pthread_create(&tid, NULL, poller_thread, pb); |
123 | |
124 | sprintf(buf: test_script, |
125 | fmt: "iptables -A INPUT -p tcp --dport %d -j DROP" , |
126 | TESTPORT); |
127 | if (system(test_script)) { |
128 | printf("FAILED: execute command: %s, err %d\n" , test_script, -errno); |
129 | goto err; |
130 | } |
131 | |
132 | sprintf(buf: test_script, |
133 | fmt: "nc 127.0.0.1 %d < /etc/passwd > /dev/null 2>&1 " , |
134 | TESTPORT); |
135 | if (system(test_script)) |
136 | printf("execute command: %s, err %d\n" , test_script, -errno); |
137 | |
138 | sprintf(buf: test_script, |
139 | fmt: "iptables -D INPUT -p tcp --dport %d -j DROP" , |
140 | TESTPORT); |
141 | if (system(test_script)) { |
142 | printf("FAILED: execute command: %s, err %d\n" , test_script, -errno); |
143 | goto err; |
144 | } |
145 | |
146 | rv = bpf_map_lookup_elem(bpf_map__fd(global_map), &key, &g); |
147 | if (rv != 0) { |
148 | printf("FAILED: bpf_map_lookup_elem returns %d\n" , rv); |
149 | goto err; |
150 | } |
151 | |
152 | sleep(10); |
153 | |
154 | if (verify_result(result: &g)) { |
155 | printf("FAILED: Wrong stats Expected %d calls, got %d\n" , |
156 | g.ncalls, rx_callbacks); |
157 | goto err; |
158 | } |
159 | |
160 | printf("PASSED!\n" ); |
161 | error = 0; |
162 | err: |
163 | bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); |
164 | close(cg_fd); |
165 | cleanup_cgroup_environment(); |
166 | perf_buffer__free(pb); |
167 | return error; |
168 | } |
169 | |