18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <inttypes.h> 38c2ecf20Sopenharmony_ci#include <stdio.h> 48c2ecf20Sopenharmony_ci#include <stdlib.h> 58c2ecf20Sopenharmony_ci#include <unistd.h> 68c2ecf20Sopenharmony_ci#include <errno.h> 78c2ecf20Sopenharmony_ci#include <string.h> 88c2ecf20Sopenharmony_ci#include <linux/bpf.h> 98c2ecf20Sopenharmony_ci#include <sys/types.h> 108c2ecf20Sopenharmony_ci#include <bpf/bpf.h> 118c2ecf20Sopenharmony_ci#include <bpf/libbpf.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "bpf_rlimit.h" 148c2ecf20Sopenharmony_ci#include "bpf_util.h" 158c2ecf20Sopenharmony_ci#include "cgroup_helpers.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "test_tcpbpf.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 3 comes from one listening socket + both ends of the connection */ 208c2ecf20Sopenharmony_ci#define EXPECTED_CLOSE_EVENTS 3 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define EXPECT_EQ(expected, actual, fmt) \ 238c2ecf20Sopenharmony_ci do { \ 248c2ecf20Sopenharmony_ci if ((expected) != (actual)) { \ 258c2ecf20Sopenharmony_ci printf(" Value of: " #actual "\n" \ 268c2ecf20Sopenharmony_ci " Actual: %" fmt "\n" \ 278c2ecf20Sopenharmony_ci " Expected: %" fmt "\n", \ 288c2ecf20Sopenharmony_ci (actual), (expected)); \ 298c2ecf20Sopenharmony_ci ret--; \ 308c2ecf20Sopenharmony_ci } \ 318c2ecf20Sopenharmony_ci } while (0) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciint verify_result(const struct tcpbpf_globals *result) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci __u32 expected_events; 368c2ecf20Sopenharmony_ci int ret = 0; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) | 398c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_RWND_INIT) | 408c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) | 418c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) | 428c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) | 438c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_NEEDS_ECN) | 448c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_STATE_CB) | 458c2ecf20Sopenharmony_ci (1 << BPF_SOCK_OPS_TCP_LISTEN_CB)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci EXPECT_EQ(expected_events, result->event_map, "#" PRIx32); 488c2ecf20Sopenharmony_ci EXPECT_EQ(501ULL, result->bytes_received, "llu"); 498c2ecf20Sopenharmony_ci EXPECT_EQ(1002ULL, result->bytes_acked, "llu"); 508c2ecf20Sopenharmony_ci EXPECT_EQ(1, result->data_segs_in, PRIu32); 518c2ecf20Sopenharmony_ci EXPECT_EQ(1, result->data_segs_out, PRIu32); 528c2ecf20Sopenharmony_ci EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32); 538c2ecf20Sopenharmony_ci EXPECT_EQ(0, result->good_cb_test_rv, PRIu32); 548c2ecf20Sopenharmony_ci EXPECT_EQ(1, result->num_listen, PRIu32); 558c2ecf20Sopenharmony_ci EXPECT_EQ(EXPECTED_CLOSE_EVENTS, result->num_close_events, PRIu32); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return ret; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciint verify_sockopt_result(int sock_map_fd) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci __u32 key = 0; 638c2ecf20Sopenharmony_ci int ret = 0; 648c2ecf20Sopenharmony_ci int res; 658c2ecf20Sopenharmony_ci int rv; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* check setsockopt for SAVE_SYN */ 688c2ecf20Sopenharmony_ci rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); 698c2ecf20Sopenharmony_ci EXPECT_EQ(0, rv, "d"); 708c2ecf20Sopenharmony_ci EXPECT_EQ(0, res, "d"); 718c2ecf20Sopenharmony_ci key = 1; 728c2ecf20Sopenharmony_ci /* check getsockopt for SAVED_SYN */ 738c2ecf20Sopenharmony_ci rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); 748c2ecf20Sopenharmony_ci EXPECT_EQ(0, rv, "d"); 758c2ecf20Sopenharmony_ci EXPECT_EQ(1, res, "d"); 768c2ecf20Sopenharmony_ci return ret; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int bpf_find_map(const char *test, struct bpf_object *obj, 808c2ecf20Sopenharmony_ci const char *name) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct bpf_map *map; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci map = bpf_object__find_map_by_name(obj, name); 858c2ecf20Sopenharmony_ci if (!map) { 868c2ecf20Sopenharmony_ci printf("%s:FAIL:map '%s' not found\n", test, name); 878c2ecf20Sopenharmony_ci return -1; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci return bpf_map__fd(map); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciint main(int argc, char **argv) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci const char *file = "test_tcpbpf_kern.o"; 958c2ecf20Sopenharmony_ci int prog_fd, map_fd, sock_map_fd; 968c2ecf20Sopenharmony_ci struct tcpbpf_globals g = {0}; 978c2ecf20Sopenharmony_ci const char *cg_path = "/foo"; 988c2ecf20Sopenharmony_ci int error = EXIT_FAILURE; 998c2ecf20Sopenharmony_ci struct bpf_object *obj; 1008c2ecf20Sopenharmony_ci int cg_fd = -1; 1018c2ecf20Sopenharmony_ci int retry = 10; 1028c2ecf20Sopenharmony_ci __u32 key = 0; 1038c2ecf20Sopenharmony_ci int rv; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci cg_fd = cgroup_setup_and_join(cg_path); 1068c2ecf20Sopenharmony_ci if (cg_fd < 0) 1078c2ecf20Sopenharmony_ci goto err; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { 1108c2ecf20Sopenharmony_ci printf("FAILED: load_bpf_file failed for: %s\n", file); 1118c2ecf20Sopenharmony_ci goto err; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0); 1158c2ecf20Sopenharmony_ci if (rv) { 1168c2ecf20Sopenharmony_ci printf("FAILED: bpf_prog_attach: %d (%s)\n", 1178c2ecf20Sopenharmony_ci error, strerror(errno)); 1188c2ecf20Sopenharmony_ci goto err; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (system("./tcp_server.py")) { 1228c2ecf20Sopenharmony_ci printf("FAILED: TCP server\n"); 1238c2ecf20Sopenharmony_ci goto err; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci map_fd = bpf_find_map(__func__, obj, "global_map"); 1278c2ecf20Sopenharmony_ci if (map_fd < 0) 1288c2ecf20Sopenharmony_ci goto err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results"); 1318c2ecf20Sopenharmony_ci if (sock_map_fd < 0) 1328c2ecf20Sopenharmony_ci goto err; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciretry_lookup: 1358c2ecf20Sopenharmony_ci rv = bpf_map_lookup_elem(map_fd, &key, &g); 1368c2ecf20Sopenharmony_ci if (rv != 0) { 1378c2ecf20Sopenharmony_ci printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); 1388c2ecf20Sopenharmony_ci goto err; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (g.num_close_events != EXPECTED_CLOSE_EVENTS && retry--) { 1428c2ecf20Sopenharmony_ci printf("Unexpected number of close events (%d), retrying!\n", 1438c2ecf20Sopenharmony_ci g.num_close_events); 1448c2ecf20Sopenharmony_ci usleep(100); 1458c2ecf20Sopenharmony_ci goto retry_lookup; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (verify_result(&g)) { 1498c2ecf20Sopenharmony_ci printf("FAILED: Wrong stats\n"); 1508c2ecf20Sopenharmony_ci goto err; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (verify_sockopt_result(sock_map_fd)) { 1548c2ecf20Sopenharmony_ci printf("FAILED: Wrong sockopt stats\n"); 1558c2ecf20Sopenharmony_ci goto err; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci printf("PASSED!\n"); 1598c2ecf20Sopenharmony_ci error = 0; 1608c2ecf20Sopenharmony_cierr: 1618c2ecf20Sopenharmony_ci bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); 1628c2ecf20Sopenharmony_ci close(cg_fd); 1638c2ecf20Sopenharmony_ci cleanup_cgroup_environment(); 1648c2ecf20Sopenharmony_ci return error; 1658c2ecf20Sopenharmony_ci} 166