1 // SPDX-License-Identifier: GPL-2.0
7 #include <sys/socket.h>
8 #include <netinet/in.h>
11 #include <linux/filter.h>
13 #include <bpf/libbpf.h>
15 #include "bpf_rlimit.h"
17 #include "cgroup_helpers.h"
19 #define CG_PATH "/tcp_rtt"
21 struct tcp_rtt_storage {
26 __u32 icsk_retransmits;
29 static void send_byte(int fd)
33 if (write(fd, &b, sizeof(b)) != 1)
34 error(1, errno, "Failed to send single byte");
37 static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked,
38 __u32 dsack_dups, __u32 delivered, __u32 delivered_ce,
39 __u32 icsk_retransmits)
42 struct tcp_rtt_storage val;
44 if (bpf_map_lookup_elem(map_fd, &client_fd, &val) < 0)
45 error(1, errno, "Failed to read socket storage");
47 if (val.invoked != invoked) {
48 log_err("%s: unexpected bpf_tcp_sock.invoked %d != %d",
49 msg, val.invoked, invoked);
53 if (val.dsack_dups != dsack_dups) {
54 log_err("%s: unexpected bpf_tcp_sock.dsack_dups %d != %d",
55 msg, val.dsack_dups, dsack_dups);
59 if (val.delivered != delivered) {
60 log_err("%s: unexpected bpf_tcp_sock.delivered %d != %d",
61 msg, val.delivered, delivered);
65 if (val.delivered_ce != delivered_ce) {
66 log_err("%s: unexpected bpf_tcp_sock.delivered_ce %d != %d",
67 msg, val.delivered_ce, delivered_ce);
71 if (val.icsk_retransmits != icsk_retransmits) {
72 log_err("%s: unexpected bpf_tcp_sock.icsk_retransmits %d != %d",
73 msg, val.icsk_retransmits, icsk_retransmits);
80 static int connect_to_server(int server_fd)
82 struct sockaddr_storage addr;
83 socklen_t len = sizeof(addr);
86 fd = socket(AF_INET, SOCK_STREAM, 0);
88 log_err("Failed to create client socket");
92 if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) {
93 log_err("Failed to get server addr");
97 if (connect(fd, (const struct sockaddr *)&addr, len) < 0) {
98 log_err("Fail to connect to server");
109 static int run_test(int cgroup_fd, int server_fd)
111 struct bpf_prog_load_attr attr = {
112 .prog_type = BPF_PROG_TYPE_SOCK_OPS,
113 .file = "./tcp_rtt.o",
114 .expected_attach_type = BPF_CGROUP_SOCK_OPS,
116 struct bpf_object *obj;
123 err = bpf_prog_load_xattr(&attr, &obj, &prog_fd);
125 log_err("Failed to load BPF object");
129 map = bpf_map__next(NULL, obj);
130 map_fd = bpf_map__fd(map);
132 err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
134 log_err("Failed to attach BPF program");
135 goto close_bpf_object;
138 client_fd = connect_to_server(server_fd);
141 goto close_bpf_object;
144 err += verify_sk(map_fd, client_fd, "syn-ack",
149 /*icsk_retransmits=*/0);
151 send_byte(client_fd);
153 err += verify_sk(map_fd, client_fd, "first payload byte",
158 /*icsk_retransmits=*/0);
163 bpf_object__close(obj);
167 static int start_server(void)
169 struct sockaddr_in addr = {
170 .sin_family = AF_INET,
171 .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
175 fd = socket(AF_INET, SOCK_STREAM, 0);
177 log_err("Failed to create server socket");
181 if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
182 log_err("Failed to bind socket");
190 static void *server_thread(void *arg)
192 struct sockaddr_storage addr;
193 socklen_t len = sizeof(addr);
194 int fd = *(int *)arg;
197 if (listen(fd, 1) < 0)
198 error(1, errno, "Failed to listed on socket");
200 client_fd = accept(fd, (struct sockaddr *)&addr, &len);
202 error(1, errno, "Failed to accept client");
204 /* Wait for the next connection (that never arrives)
205 * to keep this thread alive to prevent calling
206 * close() on client_fd.
208 if (accept(fd, (struct sockaddr *)&addr, &len) >= 0)
209 error(1, errno, "Unexpected success in second accept");
216 int main(int args, char **argv)
218 int server_fd, cgroup_fd;
219 int err = EXIT_SUCCESS;
222 if (setup_cgroup_environment())
225 cgroup_fd = create_and_get_cgroup(CG_PATH);
227 goto cleanup_cgroup_env;
229 if (join_cgroup(CG_PATH))
232 server_fd = start_server();
238 pthread_create(&tid, NULL, server_thread, (void *)&server_fd);
240 if (run_test(cgroup_fd, server_fd))
245 printf("test_sockopt_sk: %s\n",
246 err == EXIT_SUCCESS ? "PASSED" : "FAILED");
251 cleanup_cgroup_environment();