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 21 #include "bpf_rlimit.h" 22 #include "bpf_util.h" 23 #include "cgroup_helpers.h" 24 25 #include "test_tcpnotify.h" 26 #include "trace_helpers.h" 27 28 #define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) 29 30 pthread_t tid; 31 int rx_callbacks; 32 33 static int dummyfn(void *data, int size) 34 { 35 struct tcp_notifier *t = data; 36 37 if (t->type != 0xde || t->subtype != 0xad || 38 t->source != 0xbe || t->hash != 0xef) 39 return 1; 40 rx_callbacks++; 41 return 0; 42 } 43 44 void tcp_notifier_poller(int fd) 45 { 46 while (1) 47 perf_event_poller(fd, dummyfn); 48 } 49 50 static void *poller_thread(void *arg) 51 { 52 int fd = *(int *)arg; 53 54 tcp_notifier_poller(fd); 55 return arg; 56 } 57 58 int verify_result(const struct tcpnotify_globals *result) 59 { 60 return (result->ncalls > 0 && result->ncalls == rx_callbacks ? 0 : 1); 61 } 62 63 static int bpf_find_map(const char *test, struct bpf_object *obj, 64 const char *name) 65 { 66 struct bpf_map *map; 67 68 map = bpf_object__find_map_by_name(obj, name); 69 if (!map) { 70 printf("%s:FAIL:map '%s' not found\n", test, name); 71 return -1; 72 } 73 return bpf_map__fd(map); 74 } 75 76 static int setup_bpf_perf_event(int mapfd) 77 { 78 struct perf_event_attr attr = { 79 .sample_type = PERF_SAMPLE_RAW, 80 .type = PERF_TYPE_SOFTWARE, 81 .config = PERF_COUNT_SW_BPF_OUTPUT, 82 }; 83 int key = 0; 84 int pmu_fd; 85 86 pmu_fd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, 0); 87 if (pmu_fd < 0) 88 return pmu_fd; 89 bpf_map_update_elem(mapfd, &key, &pmu_fd, BPF_ANY); 90 91 ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); 92 return pmu_fd; 93 } 94 95 int main(int argc, char **argv) 96 { 97 const char *file = "test_tcpnotify_kern.o"; 98 int prog_fd, map_fd, perf_event_fd; 99 struct tcpnotify_globals g = {0}; 100 const char *cg_path = "/foo"; 101 int error = EXIT_FAILURE; 102 struct bpf_object *obj; 103 int cg_fd = -1; 104 __u32 key = 0; 105 int rv; 106 char test_script[80]; 107 int pmu_fd; 108 cpu_set_t cpuset; 109 110 CPU_ZERO(&cpuset); 111 CPU_SET(0, &cpuset); 112 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); 113 114 if (setup_cgroup_environment()) 115 goto err; 116 117 cg_fd = create_and_get_cgroup(cg_path); 118 if (cg_fd < 0) 119 goto err; 120 121 if (join_cgroup(cg_path)) 122 goto err; 123 124 if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { 125 printf("FAILED: load_bpf_file failed for: %s\n", file); 126 goto err; 127 } 128 129 rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0); 130 if (rv) { 131 printf("FAILED: bpf_prog_attach: %d (%s)\n", 132 error, strerror(errno)); 133 goto err; 134 } 135 136 perf_event_fd = bpf_find_map(__func__, obj, "perf_event_map"); 137 if (perf_event_fd < 0) 138 goto err; 139 140 map_fd = bpf_find_map(__func__, obj, "global_map"); 141 if (map_fd < 0) 142 goto err; 143 144 pmu_fd = setup_bpf_perf_event(perf_event_fd); 145 if (pmu_fd < 0 || perf_event_mmap(pmu_fd) < 0) 146 goto err; 147 148 pthread_create(&tid, NULL, poller_thread, (void *)&pmu_fd); 149 150 sprintf(test_script, 151 "iptables -A INPUT -p tcp --dport %d -j DROP", 152 TESTPORT); 153 system(test_script); 154 155 sprintf(test_script, 156 "nc 127.0.0.1 %d < /etc/passwd > /dev/null 2>&1 ", 157 TESTPORT); 158 system(test_script); 159 160 sprintf(test_script, 161 "iptables -D INPUT -p tcp --dport %d -j DROP", 162 TESTPORT); 163 system(test_script); 164 165 rv = bpf_map_lookup_elem(map_fd, &key, &g); 166 if (rv != 0) { 167 printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); 168 goto err; 169 } 170 171 sleep(10); 172 173 if (verify_result(&g)) { 174 printf("FAILED: Wrong stats Expected %d calls, got %d\n", 175 g.ncalls, rx_callbacks); 176 goto err; 177 } 178 179 printf("PASSED!\n"); 180 error = 0; 181 err: 182 bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); 183 close(cg_fd); 184 cleanup_cgroup_environment(); 185 return error; 186 } 187