18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#define _GNU_SOURCE
38c2ecf20Sopenharmony_ci#include <pthread.h>
48c2ecf20Sopenharmony_ci#include <inttypes.h>
58c2ecf20Sopenharmony_ci#include <stdio.h>
68c2ecf20Sopenharmony_ci#include <stdlib.h>
78c2ecf20Sopenharmony_ci#include <unistd.h>
88c2ecf20Sopenharmony_ci#include <asm/types.h>
98c2ecf20Sopenharmony_ci#include <sys/syscall.h>
108c2ecf20Sopenharmony_ci#include <errno.h>
118c2ecf20Sopenharmony_ci#include <string.h>
128c2ecf20Sopenharmony_ci#include <linux/bpf.h>
138c2ecf20Sopenharmony_ci#include <sys/socket.h>
148c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
158c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
168c2ecf20Sopenharmony_ci#include <sys/ioctl.h>
178c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
188c2ecf20Sopenharmony_ci#include <signal.h>
198c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
208c2ecf20Sopenharmony_ci#include <linux/err.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "bpf_rlimit.h"
238c2ecf20Sopenharmony_ci#include "bpf_util.h"
248c2ecf20Sopenharmony_ci#include "cgroup_helpers.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "test_tcpnotify.h"
278c2ecf20Sopenharmony_ci#include "trace_helpers.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cipthread_t tid;
328c2ecf20Sopenharmony_ciint rx_callbacks;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void dummyfn(void *ctx, int cpu, void *data, __u32 size)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct tcp_notifier *t = data;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (t->type != 0xde || t->subtype != 0xad ||
398c2ecf20Sopenharmony_ci	    t->source != 0xbe || t->hash != 0xef)
408c2ecf20Sopenharmony_ci		return;
418c2ecf20Sopenharmony_ci	rx_callbacks++;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_civoid tcp_notifier_poller(struct perf_buffer *pb)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	int err;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	while (1) {
498c2ecf20Sopenharmony_ci		err = perf_buffer__poll(pb, 100);
508c2ecf20Sopenharmony_ci		if (err < 0 && err != -EINTR) {
518c2ecf20Sopenharmony_ci			printf("failed perf_buffer__poll: %d\n", err);
528c2ecf20Sopenharmony_ci			return;
538c2ecf20Sopenharmony_ci		}
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void *poller_thread(void *arg)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct perf_buffer *pb = arg;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	tcp_notifier_poller(pb);
628c2ecf20Sopenharmony_ci	return arg;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciint verify_result(const struct tcpnotify_globals *result)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	return (result->ncalls > 0 && result->ncalls == rx_callbacks ? 0 : 1);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciint main(int argc, char **argv)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	const char *file = "test_tcpnotify_kern.o";
738c2ecf20Sopenharmony_ci	struct bpf_map *perf_map, *global_map;
748c2ecf20Sopenharmony_ci	struct perf_buffer_opts pb_opts = {};
758c2ecf20Sopenharmony_ci	struct tcpnotify_globals g = {0};
768c2ecf20Sopenharmony_ci	struct perf_buffer *pb = NULL;
778c2ecf20Sopenharmony_ci	const char *cg_path = "/foo";
788c2ecf20Sopenharmony_ci	int prog_fd, rv, cg_fd = -1;
798c2ecf20Sopenharmony_ci	int error = EXIT_FAILURE;
808c2ecf20Sopenharmony_ci	struct bpf_object *obj;
818c2ecf20Sopenharmony_ci	char test_script[80];
828c2ecf20Sopenharmony_ci	cpu_set_t cpuset;
838c2ecf20Sopenharmony_ci	__u32 key = 0;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	CPU_ZERO(&cpuset);
868c2ecf20Sopenharmony_ci	CPU_SET(0, &cpuset);
878c2ecf20Sopenharmony_ci	pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	cg_fd = cgroup_setup_and_join(cg_path);
908c2ecf20Sopenharmony_ci	if (cg_fd < 0)
918c2ecf20Sopenharmony_ci		goto err;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) {
948c2ecf20Sopenharmony_ci		printf("FAILED: load_bpf_file failed for: %s\n", file);
958c2ecf20Sopenharmony_ci		goto err;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0);
998c2ecf20Sopenharmony_ci	if (rv) {
1008c2ecf20Sopenharmony_ci		printf("FAILED: bpf_prog_attach: %d (%s)\n",
1018c2ecf20Sopenharmony_ci		       error, strerror(errno));
1028c2ecf20Sopenharmony_ci		goto err;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	perf_map = bpf_object__find_map_by_name(obj, "perf_event_map");
1068c2ecf20Sopenharmony_ci	if (!perf_map) {
1078c2ecf20Sopenharmony_ci		printf("FAIL:map '%s' not found\n", "perf_event_map");
1088c2ecf20Sopenharmony_ci		goto err;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	global_map = bpf_object__find_map_by_name(obj, "global_map");
1128c2ecf20Sopenharmony_ci	if (!global_map) {
1138c2ecf20Sopenharmony_ci		printf("FAIL:map '%s' not found\n", "global_map");
1148c2ecf20Sopenharmony_ci		return -1;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	pb_opts.sample_cb = dummyfn;
1188c2ecf20Sopenharmony_ci	pb = perf_buffer__new(bpf_map__fd(perf_map), 8, &pb_opts);
1198c2ecf20Sopenharmony_ci	if (IS_ERR(pb))
1208c2ecf20Sopenharmony_ci		goto err;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	pthread_create(&tid, NULL, poller_thread, pb);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	sprintf(test_script,
1258c2ecf20Sopenharmony_ci		"iptables -A INPUT -p tcp --dport %d -j DROP",
1268c2ecf20Sopenharmony_ci		TESTPORT);
1278c2ecf20Sopenharmony_ci	if (system(test_script)) {
1288c2ecf20Sopenharmony_ci		printf("FAILED: execute command: %s, err %d\n", test_script, -errno);
1298c2ecf20Sopenharmony_ci		goto err;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	sprintf(test_script,
1338c2ecf20Sopenharmony_ci		"nc 127.0.0.1 %d < /etc/passwd > /dev/null 2>&1 ",
1348c2ecf20Sopenharmony_ci		TESTPORT);
1358c2ecf20Sopenharmony_ci	if (system(test_script))
1368c2ecf20Sopenharmony_ci		printf("execute command: %s, err %d\n", test_script, -errno);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	sprintf(test_script,
1398c2ecf20Sopenharmony_ci		"iptables -D INPUT -p tcp --dport %d -j DROP",
1408c2ecf20Sopenharmony_ci		TESTPORT);
1418c2ecf20Sopenharmony_ci	if (system(test_script)) {
1428c2ecf20Sopenharmony_ci		printf("FAILED: execute command: %s, err %d\n", test_script, -errno);
1438c2ecf20Sopenharmony_ci		goto err;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	rv = bpf_map_lookup_elem(bpf_map__fd(global_map), &key, &g);
1478c2ecf20Sopenharmony_ci	if (rv != 0) {
1488c2ecf20Sopenharmony_ci		printf("FAILED: bpf_map_lookup_elem returns %d\n", rv);
1498c2ecf20Sopenharmony_ci		goto err;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	sleep(10);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (verify_result(&g)) {
1558c2ecf20Sopenharmony_ci		printf("FAILED: Wrong stats Expected %d calls, got %d\n",
1568c2ecf20Sopenharmony_ci			g.ncalls, rx_callbacks);
1578c2ecf20Sopenharmony_ci		goto err;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	printf("PASSED!\n");
1618c2ecf20Sopenharmony_ci	error = 0;
1628c2ecf20Sopenharmony_cierr:
1638c2ecf20Sopenharmony_ci	bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS);
1648c2ecf20Sopenharmony_ci	close(cg_fd);
1658c2ecf20Sopenharmony_ci	cleanup_cgroup_environment();
1668c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(pb))
1678c2ecf20Sopenharmony_ci		perf_buffer__free(pb);
1688c2ecf20Sopenharmony_ci	return error;
1698c2ecf20Sopenharmony_ci}
170