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