diff options
Diffstat (limited to 'tools/testing/selftests/bpf/test_tcpnotify_user.c')
-rw-r--r-- | tools/testing/selftests/bpf/test_tcpnotify_user.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/test_tcpnotify_user.c b/tools/testing/selftests/bpf/test_tcpnotify_user.c new file mode 100644 index 000000000..595194453 --- /dev/null +++ b/tools/testing/selftests/bpf/test_tcpnotify_user.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <pthread.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <asm/types.h> +#include <sys/syscall.h> +#include <errno.h> +#include <string.h> +#include <linux/bpf.h> +#include <sys/socket.h> +#include <bpf/bpf.h> +#include <bpf/libbpf.h> +#include <sys/ioctl.h> +#include <linux/rtnetlink.h> +#include <signal.h> +#include <linux/perf_event.h> +#include <linux/err.h> + +#include "bpf_util.h" +#include "cgroup_helpers.h" + +#include "test_tcpnotify.h" +#include "trace_helpers.h" +#include "testing_helpers.h" + +#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) + +pthread_t tid; +int rx_callbacks; + +static void dummyfn(void *ctx, int cpu, void *data, __u32 size) +{ + struct tcp_notifier *t = data; + + if (t->type != 0xde || t->subtype != 0xad || + t->source != 0xbe || t->hash != 0xef) + return; + rx_callbacks++; +} + +void tcp_notifier_poller(struct perf_buffer *pb) +{ + int err; + + while (1) { + err = perf_buffer__poll(pb, 100); + if (err < 0 && err != -EINTR) { + printf("failed perf_buffer__poll: %d\n", err); + return; + } + } +} + +static void *poller_thread(void *arg) +{ + struct perf_buffer *pb = arg; + + tcp_notifier_poller(pb); + return arg; +} + +int verify_result(const struct tcpnotify_globals *result) +{ + return (result->ncalls > 0 && result->ncalls == rx_callbacks ? 0 : 1); +} + +int main(int argc, char **argv) +{ + const char *file = "test_tcpnotify_kern.bpf.o"; + struct bpf_map *perf_map, *global_map; + struct tcpnotify_globals g = {0}; + struct perf_buffer *pb = NULL; + const char *cg_path = "/foo"; + int prog_fd, rv, cg_fd = -1; + int error = EXIT_FAILURE; + struct bpf_object *obj; + char test_script[80]; + cpu_set_t cpuset; + __u32 key = 0; + + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + + cg_fd = cgroup_setup_and_join(cg_path); + if (cg_fd < 0) + goto err; + + if (bpf_prog_test_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { + printf("FAILED: load_bpf_file failed for: %s\n", file); + goto err; + } + + rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0); + if (rv) { + printf("FAILED: bpf_prog_attach: %d (%s)\n", + error, strerror(errno)); + goto err; + } + + perf_map = bpf_object__find_map_by_name(obj, "perf_event_map"); + if (!perf_map) { + printf("FAIL:map '%s' not found\n", "perf_event_map"); + goto err; + } + + global_map = bpf_object__find_map_by_name(obj, "global_map"); + if (!global_map) { + printf("FAIL:map '%s' not found\n", "global_map"); + return -1; + } + + pb = perf_buffer__new(bpf_map__fd(perf_map), 8, dummyfn, NULL, NULL, NULL); + if (!pb) + goto err; + + pthread_create(&tid, NULL, poller_thread, pb); + + sprintf(test_script, + "iptables -A INPUT -p tcp --dport %d -j DROP", + TESTPORT); + if (system(test_script)) { + printf("FAILED: execute command: %s, err %d\n", test_script, -errno); + goto err; + } + + sprintf(test_script, + "nc 127.0.0.1 %d < /etc/passwd > /dev/null 2>&1 ", + TESTPORT); + if (system(test_script)) + printf("execute command: %s, err %d\n", test_script, -errno); + + sprintf(test_script, + "iptables -D INPUT -p tcp --dport %d -j DROP", + TESTPORT); + if (system(test_script)) { + printf("FAILED: execute command: %s, err %d\n", test_script, -errno); + goto err; + } + + rv = bpf_map_lookup_elem(bpf_map__fd(global_map), &key, &g); + if (rv != 0) { + printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); + goto err; + } + + sleep(10); + + if (verify_result(&g)) { + printf("FAILED: Wrong stats Expected %d calls, got %d\n", + g.ncalls, rx_callbacks); + goto err; + } + + printf("PASSED!\n"); + error = 0; +err: + bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); + close(cg_fd); + cleanup_cgroup_environment(); + perf_buffer__free(pb); + return error; +} |