1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
5 #include <test_progs.h>
6 #include "bpf_dctcp.skel.h"
7 #include "bpf_cubic.skel.h"
9 #define min(a, b) ((a) < (b) ? (a) : (b))
11 static const unsigned int total_bytes
= 10 * 1024 * 1024;
12 static const struct timeval timeo_sec
= { .tv_sec
= 10 };
13 static const size_t timeo_optlen
= sizeof(timeo_sec
);
14 static int stop
, duration
;
16 static int settimeo(int fd
)
20 err
= setsockopt(fd
, SOL_SOCKET
, SO_RCVTIMEO
, &timeo_sec
,
22 if (CHECK(err
== -1, "setsockopt(fd, SO_RCVTIMEO)", "errno:%d\n",
26 err
= setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, &timeo_sec
,
28 if (CHECK(err
== -1, "setsockopt(fd, SO_SNDTIMEO)", "errno:%d\n",
35 static int settcpca(int fd
, const char *tcp_ca
)
39 err
= setsockopt(fd
, IPPROTO_TCP
, TCP_CONGESTION
, tcp_ca
, strlen(tcp_ca
));
40 if (CHECK(err
== -1, "setsockopt(fd, TCP_CONGESTION)", "errno:%d\n",
47 static void *server(void *arg
)
49 int lfd
= (int)(long)arg
, err
= 0, fd
;
50 ssize_t nr_sent
= 0, bytes
= 0;
53 fd
= accept(lfd
, NULL
, NULL
);
66 while (bytes
< total_bytes
&& !READ_ONCE(stop
)) {
67 nr_sent
= send(fd
, &batch
,
68 min(total_bytes
- bytes
, sizeof(batch
)), 0);
69 if (nr_sent
== -1 && errno
== EINTR
)
78 CHECK(bytes
!= total_bytes
, "send", "%zd != %u nr_sent:%zd errno:%d\n",
79 bytes
, total_bytes
, nr_sent
, errno
);
91 static void do_test(const char *tcp_ca
)
93 struct sockaddr_in6 sa6
= {};
94 ssize_t nr_recv
= 0, bytes
= 0;
95 int lfd
= -1, fd
= -1;
97 socklen_t addrlen
= sizeof(sa6
);
104 lfd
= socket(AF_INET6
, SOCK_STREAM
, 0);
105 if (CHECK(lfd
== -1, "socket", "errno:%d\n", errno
))
107 fd
= socket(AF_INET6
, SOCK_STREAM
, 0);
108 if (CHECK(fd
== -1, "socket", "errno:%d\n", errno
)) {
113 if (settcpca(lfd
, tcp_ca
) || settcpca(fd
, tcp_ca
) ||
114 settimeo(lfd
) || settimeo(fd
))
117 /* bind, listen and start server thread to accept */
118 sa6
.sin6_family
= AF_INET6
;
119 sa6
.sin6_addr
= in6addr_loopback
;
120 err
= bind(lfd
, (struct sockaddr
*)&sa6
, addrlen
);
121 if (CHECK(err
== -1, "bind", "errno:%d\n", errno
))
123 err
= getsockname(lfd
, (struct sockaddr
*)&sa6
, &addrlen
);
124 if (CHECK(err
== -1, "getsockname", "errno:%d\n", errno
))
126 err
= listen(lfd
, 1);
127 if (CHECK(err
== -1, "listen", "errno:%d\n", errno
))
129 err
= pthread_create(&srv_thread
, NULL
, server
, (void *)(long)lfd
);
130 if (CHECK(err
!= 0, "pthread_create", "err:%d\n", err
))
133 /* connect to server */
134 err
= connect(fd
, (struct sockaddr
*)&sa6
, addrlen
);
135 if (CHECK(err
== -1, "connect", "errno:%d\n", errno
))
138 /* recv total_bytes */
139 while (bytes
< total_bytes
&& !READ_ONCE(stop
)) {
140 nr_recv
= recv(fd
, &batch
,
141 min(total_bytes
- bytes
, sizeof(batch
)), 0);
142 if (nr_recv
== -1 && errno
== EINTR
)
149 CHECK(bytes
!= total_bytes
, "recv", "%zd != %u nr_recv:%zd errno:%d\n",
150 bytes
, total_bytes
, nr_recv
, errno
);
154 pthread_join(srv_thread
, &thread_ret
);
155 CHECK(IS_ERR(thread_ret
), "pthread_join", "thread_ret:%ld",
156 PTR_ERR(thread_ret
));
162 static void test_cubic(void)
164 struct bpf_cubic
*cubic_skel
;
165 struct bpf_link
*link
;
167 cubic_skel
= bpf_cubic__open_and_load();
168 if (CHECK(!cubic_skel
, "bpf_cubic__open_and_load", "failed\n"))
171 link
= bpf_map__attach_struct_ops(cubic_skel
->maps
.cubic
);
172 if (CHECK(IS_ERR(link
), "bpf_map__attach_struct_ops", "err:%ld\n",
174 bpf_cubic__destroy(cubic_skel
);
178 do_test("bpf_cubic");
180 bpf_link__destroy(link
);
181 bpf_cubic__destroy(cubic_skel
);
184 static void test_dctcp(void)
186 struct bpf_dctcp
*dctcp_skel
;
187 struct bpf_link
*link
;
189 dctcp_skel
= bpf_dctcp__open_and_load();
190 if (CHECK(!dctcp_skel
, "bpf_dctcp__open_and_load", "failed\n"))
193 link
= bpf_map__attach_struct_ops(dctcp_skel
->maps
.dctcp
);
194 if (CHECK(IS_ERR(link
), "bpf_map__attach_struct_ops", "err:%ld\n",
196 bpf_dctcp__destroy(dctcp_skel
);
200 do_test("bpf_dctcp");
202 bpf_link__destroy(link
);
203 bpf_dctcp__destroy(dctcp_skel
);
206 void test_bpf_tcp_ca(void)
208 if (test__start_subtest("dctcp"))
210 if (test__start_subtest("cubic"))