Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | // SPDX-License-Identifier: GPL-2.0 #include <test_progs.h> #include "cgroup_helpers.h" #include "network_helpers.h" #include "tcp_rtt.skel.h" struct tcp_rtt_storage { __u32 invoked; __u32 dsack_dups; __u32 delivered; __u32 delivered_ce; __u32 icsk_retransmits; }; static void send_byte(int fd) { char b = 0x55; ASSERT_EQ(write(fd, &b, sizeof(b)), 1, "send single byte"); } static int wait_for_ack(int fd, int retries) { struct tcp_info info; socklen_t optlen; int i, err; for (i = 0; i < retries; i++) { optlen = sizeof(info); err = getsockopt(fd, SOL_TCP, TCP_INFO, &info, &optlen); if (err < 0) { log_err("Failed to lookup TCP stats"); return err; } if (info.tcpi_unacked == 0) return 0; usleep(10); } log_err("Did not receive ACK"); return -1; } static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked, __u32 dsack_dups, __u32 delivered, __u32 delivered_ce, __u32 icsk_retransmits) { int err = 0; struct tcp_rtt_storage val; if (!ASSERT_GE(bpf_map_lookup_elem(map_fd, &client_fd, &val), 0, "read socket storage")) return -1; if (val.invoked != invoked) { log_err("%s: unexpected bpf_tcp_sock.invoked %d != %d", msg, val.invoked, invoked); err++; } if (val.dsack_dups != dsack_dups) { log_err("%s: unexpected bpf_tcp_sock.dsack_dups %d != %d", msg, val.dsack_dups, dsack_dups); err++; } if (val.delivered != delivered) { log_err("%s: unexpected bpf_tcp_sock.delivered %d != %d", msg, val.delivered, delivered); err++; } if (val.delivered_ce != delivered_ce) { log_err("%s: unexpected bpf_tcp_sock.delivered_ce %d != %d", msg, val.delivered_ce, delivered_ce); err++; } if (val.icsk_retransmits != icsk_retransmits) { log_err("%s: unexpected bpf_tcp_sock.icsk_retransmits %d != %d", msg, val.icsk_retransmits, icsk_retransmits); err++; } return err; } static int run_test(int cgroup_fd, int server_fd) { struct tcp_rtt *skel; int client_fd; int prog_fd; int map_fd; int err; skel = tcp_rtt__open_and_load(); if (!ASSERT_OK_PTR(skel, "skel_open_load")) return -1; map_fd = bpf_map__fd(skel->maps.socket_storage_map); prog_fd = bpf_program__fd(skel->progs._sockops); err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0); if (err) { log_err("Failed to attach BPF program"); goto close_bpf_object; } client_fd = connect_to_fd(server_fd, 0); if (client_fd < 0) { err = -1; goto close_bpf_object; } err += verify_sk(map_fd, client_fd, "syn-ack", /*invoked=*/1, /*dsack_dups=*/0, /*delivered=*/1, /*delivered_ce=*/0, /*icsk_retransmits=*/0); send_byte(client_fd); if (wait_for_ack(client_fd, 100) < 0) { err = -1; goto close_client_fd; } err += verify_sk(map_fd, client_fd, "first payload byte", /*invoked=*/2, /*dsack_dups=*/0, /*delivered=*/2, /*delivered_ce=*/0, /*icsk_retransmits=*/0); close_client_fd: close(client_fd); close_bpf_object: tcp_rtt__destroy(skel); return err; } void test_tcp_rtt(void) { int server_fd, cgroup_fd; cgroup_fd = test__join_cgroup("/tcp_rtt"); if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /tcp_rtt")) return; server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); if (!ASSERT_GE(server_fd, 0, "start_server")) goto close_cgroup_fd; ASSERT_OK(run_test(cgroup_fd, server_fd), "run_test"); close(server_fd); close_cgroup_fd: close(cgroup_fd); } |