109903869SMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
209903869SMartin KaFai Lau /* Copyright (c) 2019 Facebook */
309903869SMartin KaFai Lau 
409903869SMartin KaFai Lau #include <linux/err.h>
59cacf81fSStanislav Fomichev #include <netinet/tcp.h>
609903869SMartin KaFai Lau #include <test_progs.h>
7574ee209SMartin KaFai Lau #include "network_helpers.h"
809903869SMartin KaFai Lau #include "bpf_dctcp.skel.h"
96de4a9c4SMartin KaFai Lau #include "bpf_cubic.skel.h"
10d8e8052eSToke Høiland-Jørgensen #include "bpf_tcp_nogpl.skel.h"
1106da9f3bSKui-Feng Lee #include "tcp_ca_update.skel.h"
12574ee209SMartin KaFai Lau #include "bpf_dctcp_release.skel.h"
136e945d57SJörn-Thorben Hinz #include "tcp_ca_write_sk_pacing.skel.h"
140735627dSJörn-Thorben Hinz #include "tcp_ca_incompl_cong_ops.skel.h"
15f14a3f64SJörn-Thorben Hinz #include "tcp_ca_unsupp_cong_op.skel.h"
165da7fb04SMartin KaFai Lau #include "tcp_ca_kfunc.skel.h"
17*96c3490dSMiao Xu #include "bpf_cc_cubic.skel.h"
1809903869SMartin KaFai Lau 
19574ee209SMartin KaFai Lau #ifndef ENOTSUPP
20574ee209SMartin KaFai Lau #define ENOTSUPP 524
21574ee209SMartin KaFai Lau #endif
22574ee209SMartin KaFai Lau 
2309903869SMartin KaFai Lau static const unsigned int total_bytes = 10 * 1024 * 1024;
24c9b24312SMartin KaFai Lau static int expected_stg = 0xeB9F;
2509903869SMartin KaFai Lau 
settcpca(int fd,const char * tcp_ca)2609903869SMartin KaFai Lau static int settcpca(int fd, const char *tcp_ca)
2709903869SMartin KaFai Lau {
2809903869SMartin KaFai Lau 	int err;
2909903869SMartin KaFai Lau 
3009903869SMartin KaFai Lau 	err = setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, tcp_ca, strlen(tcp_ca));
31b0e2a039SYuran Pereira 	if (!ASSERT_NEQ(err, -1, "setsockopt"))
3209903869SMartin KaFai Lau 		return -1;
3309903869SMartin KaFai Lau 
3409903869SMartin KaFai Lau 	return 0;
3509903869SMartin KaFai Lau }
3609903869SMartin KaFai Lau 
do_test(const char * tcp_ca,const struct bpf_map * sk_stg_map)37c9b24312SMartin KaFai Lau static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map)
3809903869SMartin KaFai Lau {
3909903869SMartin KaFai Lau 	int lfd = -1, fd = -1;
4009903869SMartin KaFai Lau 	int err;
4109903869SMartin KaFai Lau 
42c29083f3SGeliang Tang 	lfd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
43b0e2a039SYuran Pereira 	if (!ASSERT_NEQ(lfd, -1, "socket"))
4409903869SMartin KaFai Lau 		return;
45b0e2a039SYuran Pereira 
4609903869SMartin KaFai Lau 	fd = socket(AF_INET6, SOCK_STREAM, 0);
47b0e2a039SYuran Pereira 	if (!ASSERT_NEQ(fd, -1, "socket")) {
4809903869SMartin KaFai Lau 		close(lfd);
4909903869SMartin KaFai Lau 		return;
5009903869SMartin KaFai Lau 	}
5109903869SMartin KaFai Lau 
5242667092SGeliang Tang 	if (settcpca(lfd, tcp_ca) || settcpca(fd, tcp_ca))
5309903869SMartin KaFai Lau 		goto done;
5409903869SMartin KaFai Lau 
55c9b24312SMartin KaFai Lau 	if (sk_stg_map) {
56c9b24312SMartin KaFai Lau 		err = bpf_map_update_elem(bpf_map__fd(sk_stg_map), &fd,
57c9b24312SMartin KaFai Lau 					  &expected_stg, BPF_NOEXIST);
58b0e2a039SYuran Pereira 		if (!ASSERT_OK(err, "bpf_map_update_elem(sk_stg_map)"))
5909903869SMartin KaFai Lau 			goto done;
60c9b24312SMartin KaFai Lau 	}
6109903869SMartin KaFai Lau 
6209903869SMartin KaFai Lau 	/* connect to server */
63e5e1a3aaSGeliang Tang 	err = connect_fd_to_fd(fd, lfd, 0);
64b0e2a039SYuran Pereira 	if (!ASSERT_NEQ(err, -1, "connect"))
65c9b24312SMartin KaFai Lau 		goto done;
66c9b24312SMartin KaFai Lau 
67c9b24312SMartin KaFai Lau 	if (sk_stg_map) {
68c9b24312SMartin KaFai Lau 		int tmp_stg;
69c9b24312SMartin KaFai Lau 
70c9b24312SMartin KaFai Lau 		err = bpf_map_lookup_elem(bpf_map__fd(sk_stg_map), &fd,
71c9b24312SMartin KaFai Lau 					  &tmp_stg);
72b0e2a039SYuran Pereira 		if (!ASSERT_ERR(err, "bpf_map_lookup_elem(sk_stg_map)") ||
73b0e2a039SYuran Pereira 				!ASSERT_EQ(errno, ENOENT, "bpf_map_lookup_elem(sk_stg_map)"))
74c9b24312SMartin KaFai Lau 			goto done;
75c9b24312SMartin KaFai Lau 	}
76c9b24312SMartin KaFai Lau 
77dc34e44eSGeliang Tang 	ASSERT_OK(send_recv_data(lfd, fd, total_bytes), "send_recv_data");
78b0e2a039SYuran Pereira 
7909903869SMartin KaFai Lau done:
8009903869SMartin KaFai Lau 	close(lfd);
8109903869SMartin KaFai Lau 	close(fd);
8209903869SMartin KaFai Lau }
8309903869SMartin KaFai Lau 
test_cubic(void)846de4a9c4SMartin KaFai Lau static void test_cubic(void)
856de4a9c4SMartin KaFai Lau {
866de4a9c4SMartin KaFai Lau 	struct bpf_cubic *cubic_skel;
876de4a9c4SMartin KaFai Lau 	struct bpf_link *link;
886de4a9c4SMartin KaFai Lau 
896de4a9c4SMartin KaFai Lau 	cubic_skel = bpf_cubic__open_and_load();
90b0e2a039SYuran Pereira 	if (!ASSERT_OK_PTR(cubic_skel, "bpf_cubic__open_and_load"))
916de4a9c4SMartin KaFai Lau 		return;
926de4a9c4SMartin KaFai Lau 
936de4a9c4SMartin KaFai Lau 	link = bpf_map__attach_struct_ops(cubic_skel->maps.cubic);
94bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
956de4a9c4SMartin KaFai Lau 		bpf_cubic__destroy(cubic_skel);
966de4a9c4SMartin KaFai Lau 		return;
976de4a9c4SMartin KaFai Lau 	}
986de4a9c4SMartin KaFai Lau 
99c9b24312SMartin KaFai Lau 	do_test("bpf_cubic", NULL);
1006de4a9c4SMartin KaFai Lau 
10148f5e7d3SSong Liu 	ASSERT_EQ(cubic_skel->bss->bpf_cubic_acked_called, 1, "pkts_acked called");
10248f5e7d3SSong Liu 
1036de4a9c4SMartin KaFai Lau 	bpf_link__destroy(link);
1046de4a9c4SMartin KaFai Lau 	bpf_cubic__destroy(cubic_skel);
1056de4a9c4SMartin KaFai Lau }
1066de4a9c4SMartin KaFai Lau 
test_dctcp(void)10709903869SMartin KaFai Lau static void test_dctcp(void)
10809903869SMartin KaFai Lau {
10909903869SMartin KaFai Lau 	struct bpf_dctcp *dctcp_skel;
11009903869SMartin KaFai Lau 	struct bpf_link *link;
11109903869SMartin KaFai Lau 
11209903869SMartin KaFai Lau 	dctcp_skel = bpf_dctcp__open_and_load();
113b0e2a039SYuran Pereira 	if (!ASSERT_OK_PTR(dctcp_skel, "bpf_dctcp__open_and_load"))
11409903869SMartin KaFai Lau 		return;
11509903869SMartin KaFai Lau 
11609903869SMartin KaFai Lau 	link = bpf_map__attach_struct_ops(dctcp_skel->maps.dctcp);
117bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
11809903869SMartin KaFai Lau 		bpf_dctcp__destroy(dctcp_skel);
11909903869SMartin KaFai Lau 		return;
12009903869SMartin KaFai Lau 	}
12109903869SMartin KaFai Lau 
122c9b24312SMartin KaFai Lau 	do_test("bpf_dctcp", dctcp_skel->maps.sk_stg_map);
123b0e2a039SYuran Pereira 	ASSERT_EQ(dctcp_skel->bss->stg_result, expected_stg, "stg_result");
12409903869SMartin KaFai Lau 
12509903869SMartin KaFai Lau 	bpf_link__destroy(link);
12609903869SMartin KaFai Lau 	bpf_dctcp__destroy(dctcp_skel);
12709903869SMartin KaFai Lau }
12809903869SMartin KaFai Lau 
129d8e8052eSToke Høiland-Jørgensen static char *err_str;
130d8e8052eSToke Høiland-Jørgensen static bool found;
131d8e8052eSToke Høiland-Jørgensen 
libbpf_debug_print(enum libbpf_print_level level,const char * format,va_list args)132d8e8052eSToke Høiland-Jørgensen static int libbpf_debug_print(enum libbpf_print_level level,
133d8e8052eSToke Høiland-Jørgensen 			      const char *format, va_list args)
134d8e8052eSToke Høiland-Jørgensen {
135acd143eeSJean-Philippe Brucker 	const char *prog_name, *log_buf;
136d8e8052eSToke Høiland-Jørgensen 
137d8e8052eSToke Høiland-Jørgensen 	if (level != LIBBPF_WARN ||
138ad9a7f96SAndrii Nakryiko 	    !strstr(format, "-- BEGIN PROG LOAD LOG --")) {
139d8e8052eSToke Høiland-Jørgensen 		vprintf(format, args);
140d8e8052eSToke Høiland-Jørgensen 		return 0;
141d8e8052eSToke Høiland-Jørgensen 	}
142d8e8052eSToke Høiland-Jørgensen 
143acd143eeSJean-Philippe Brucker 	prog_name = va_arg(args, char *);
144d8e8052eSToke Høiland-Jørgensen 	log_buf = va_arg(args, char *);
145d8e8052eSToke Høiland-Jørgensen 	if (!log_buf)
146d8e8052eSToke Høiland-Jørgensen 		goto out;
147d8e8052eSToke Høiland-Jørgensen 	if (err_str && strstr(log_buf, err_str) != NULL)
148d8e8052eSToke Høiland-Jørgensen 		found = true;
149d8e8052eSToke Høiland-Jørgensen out:
150acd143eeSJean-Philippe Brucker 	printf(format, prog_name, log_buf);
151d8e8052eSToke Høiland-Jørgensen 	return 0;
152d8e8052eSToke Høiland-Jørgensen }
153d8e8052eSToke Høiland-Jørgensen 
test_invalid_license(void)154d8e8052eSToke Høiland-Jørgensen static void test_invalid_license(void)
155d8e8052eSToke Høiland-Jørgensen {
156d8e8052eSToke Høiland-Jørgensen 	libbpf_print_fn_t old_print_fn;
157d8e8052eSToke Høiland-Jørgensen 	struct bpf_tcp_nogpl *skel;
158d8e8052eSToke Høiland-Jørgensen 
159d8e8052eSToke Høiland-Jørgensen 	err_str = "struct ops programs must have a GPL compatible license";
160d8e8052eSToke Høiland-Jørgensen 	found = false;
161d8e8052eSToke Høiland-Jørgensen 	old_print_fn = libbpf_set_print(libbpf_debug_print);
162d8e8052eSToke Høiland-Jørgensen 
163d8e8052eSToke Høiland-Jørgensen 	skel = bpf_tcp_nogpl__open_and_load();
164d8e8052eSToke Høiland-Jørgensen 	ASSERT_NULL(skel, "bpf_tcp_nogpl");
165d8e8052eSToke Høiland-Jørgensen 	ASSERT_EQ(found, true, "expected_err_msg");
166d8e8052eSToke Høiland-Jørgensen 
167d8e8052eSToke Høiland-Jørgensen 	bpf_tcp_nogpl__destroy(skel);
168d8e8052eSToke Høiland-Jørgensen 	libbpf_set_print(old_print_fn);
169d8e8052eSToke Høiland-Jørgensen }
170d8e8052eSToke Høiland-Jørgensen 
test_dctcp_fallback(void)171574ee209SMartin KaFai Lau static void test_dctcp_fallback(void)
172574ee209SMartin KaFai Lau {
173574ee209SMartin KaFai Lau 	int err, lfd = -1, cli_fd = -1, srv_fd = -1;
174574ee209SMartin KaFai Lau 	struct network_helper_opts opts = {
175574ee209SMartin KaFai Lau 		.cc = "cubic",
176574ee209SMartin KaFai Lau 	};
177574ee209SMartin KaFai Lau 	struct bpf_dctcp *dctcp_skel;
178574ee209SMartin KaFai Lau 	struct bpf_link *link = NULL;
179574ee209SMartin KaFai Lau 	char srv_cc[16];
180574ee209SMartin KaFai Lau 	socklen_t cc_len = sizeof(srv_cc);
181574ee209SMartin KaFai Lau 
182574ee209SMartin KaFai Lau 	dctcp_skel = bpf_dctcp__open();
183574ee209SMartin KaFai Lau 	if (!ASSERT_OK_PTR(dctcp_skel, "dctcp_skel"))
184574ee209SMartin KaFai Lau 		return;
185574ee209SMartin KaFai Lau 	strcpy(dctcp_skel->rodata->fallback, "cubic");
186574ee209SMartin KaFai Lau 	if (!ASSERT_OK(bpf_dctcp__load(dctcp_skel), "bpf_dctcp__load"))
187574ee209SMartin KaFai Lau 		goto done;
188574ee209SMartin KaFai Lau 
189574ee209SMartin KaFai Lau 	link = bpf_map__attach_struct_ops(dctcp_skel->maps.dctcp);
190574ee209SMartin KaFai Lau 	if (!ASSERT_OK_PTR(link, "dctcp link"))
191574ee209SMartin KaFai Lau 		goto done;
192574ee209SMartin KaFai Lau 
193574ee209SMartin KaFai Lau 	lfd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
194574ee209SMartin KaFai Lau 	if (!ASSERT_GE(lfd, 0, "lfd") ||
195574ee209SMartin KaFai Lau 	    !ASSERT_OK(settcpca(lfd, "bpf_dctcp"), "lfd=>bpf_dctcp"))
196574ee209SMartin KaFai Lau 		goto done;
197574ee209SMartin KaFai Lau 
198574ee209SMartin KaFai Lau 	cli_fd = connect_to_fd_opts(lfd, &opts);
199574ee209SMartin KaFai Lau 	if (!ASSERT_GE(cli_fd, 0, "cli_fd"))
200574ee209SMartin KaFai Lau 		goto done;
201574ee209SMartin KaFai Lau 
202574ee209SMartin KaFai Lau 	srv_fd = accept(lfd, NULL, 0);
203574ee209SMartin KaFai Lau 	if (!ASSERT_GE(srv_fd, 0, "srv_fd"))
204574ee209SMartin KaFai Lau 		goto done;
205574ee209SMartin KaFai Lau 	ASSERT_STREQ(dctcp_skel->bss->cc_res, "cubic", "cc_res");
206574ee209SMartin KaFai Lau 	ASSERT_EQ(dctcp_skel->bss->tcp_cdg_res, -ENOTSUPP, "tcp_cdg_res");
2073411c5b6SMartin KaFai Lau 	/* All setsockopt(TCP_CONGESTION) in the recurred
2083411c5b6SMartin KaFai Lau 	 * bpf_dctcp->init() should fail with -EBUSY.
2093411c5b6SMartin KaFai Lau 	 */
2103411c5b6SMartin KaFai Lau 	ASSERT_EQ(dctcp_skel->bss->ebusy_cnt, 3, "ebusy_cnt");
211574ee209SMartin KaFai Lau 
212574ee209SMartin KaFai Lau 	err = getsockopt(srv_fd, SOL_TCP, TCP_CONGESTION, srv_cc, &cc_len);
213574ee209SMartin KaFai Lau 	if (!ASSERT_OK(err, "getsockopt(srv_fd, TCP_CONGESTION)"))
214574ee209SMartin KaFai Lau 		goto done;
215574ee209SMartin KaFai Lau 	ASSERT_STREQ(srv_cc, "cubic", "srv_fd cc");
216574ee209SMartin KaFai Lau 
217574ee209SMartin KaFai Lau done:
218574ee209SMartin KaFai Lau 	bpf_link__destroy(link);
219574ee209SMartin KaFai Lau 	bpf_dctcp__destroy(dctcp_skel);
220574ee209SMartin KaFai Lau 	if (lfd != -1)
221574ee209SMartin KaFai Lau 		close(lfd);
222574ee209SMartin KaFai Lau 	if (srv_fd != -1)
223574ee209SMartin KaFai Lau 		close(srv_fd);
224574ee209SMartin KaFai Lau 	if (cli_fd != -1)
225574ee209SMartin KaFai Lau 		close(cli_fd);
226574ee209SMartin KaFai Lau }
227574ee209SMartin KaFai Lau 
test_rel_setsockopt(void)228574ee209SMartin KaFai Lau static void test_rel_setsockopt(void)
229574ee209SMartin KaFai Lau {
230574ee209SMartin KaFai Lau 	struct bpf_dctcp_release *rel_skel;
231574ee209SMartin KaFai Lau 	libbpf_print_fn_t old_print_fn;
232574ee209SMartin KaFai Lau 
233786bf0e7SMykyta Yatsenko 	err_str = "program of this type cannot use helper bpf_setsockopt";
234574ee209SMartin KaFai Lau 	found = false;
235574ee209SMartin KaFai Lau 
236574ee209SMartin KaFai Lau 	old_print_fn = libbpf_set_print(libbpf_debug_print);
237574ee209SMartin KaFai Lau 	rel_skel = bpf_dctcp_release__open_and_load();
238574ee209SMartin KaFai Lau 	libbpf_set_print(old_print_fn);
239574ee209SMartin KaFai Lau 
240574ee209SMartin KaFai Lau 	ASSERT_ERR_PTR(rel_skel, "rel_skel");
241574ee209SMartin KaFai Lau 	ASSERT_TRUE(found, "expected_err_msg");
242574ee209SMartin KaFai Lau 
243574ee209SMartin KaFai Lau 	bpf_dctcp_release__destroy(rel_skel);
244574ee209SMartin KaFai Lau }
245574ee209SMartin KaFai Lau 
test_write_sk_pacing(void)2466e945d57SJörn-Thorben Hinz static void test_write_sk_pacing(void)
2476e945d57SJörn-Thorben Hinz {
2486e945d57SJörn-Thorben Hinz 	struct tcp_ca_write_sk_pacing *skel;
2496e945d57SJörn-Thorben Hinz 	struct bpf_link *link;
2506e945d57SJörn-Thorben Hinz 
2516e945d57SJörn-Thorben Hinz 	skel = tcp_ca_write_sk_pacing__open_and_load();
2526e945d57SJörn-Thorben Hinz 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
2536e945d57SJörn-Thorben Hinz 		return;
2546e945d57SJörn-Thorben Hinz 
2556e945d57SJörn-Thorben Hinz 	link = bpf_map__attach_struct_ops(skel->maps.write_sk_pacing);
2566e945d57SJörn-Thorben Hinz 	ASSERT_OK_PTR(link, "attach_struct_ops");
2576e945d57SJörn-Thorben Hinz 
2586e945d57SJörn-Thorben Hinz 	bpf_link__destroy(link);
2596e945d57SJörn-Thorben Hinz 	tcp_ca_write_sk_pacing__destroy(skel);
2606e945d57SJörn-Thorben Hinz }
2616e945d57SJörn-Thorben Hinz 
test_incompl_cong_ops(void)2620735627dSJörn-Thorben Hinz static void test_incompl_cong_ops(void)
2630735627dSJörn-Thorben Hinz {
2640735627dSJörn-Thorben Hinz 	struct tcp_ca_incompl_cong_ops *skel;
2650735627dSJörn-Thorben Hinz 	struct bpf_link *link;
2660735627dSJörn-Thorben Hinz 
2670735627dSJörn-Thorben Hinz 	skel = tcp_ca_incompl_cong_ops__open_and_load();
2680735627dSJörn-Thorben Hinz 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
2690735627dSJörn-Thorben Hinz 		return;
2700735627dSJörn-Thorben Hinz 
2710735627dSJörn-Thorben Hinz 	/* That cong_avoid() and cong_control() are missing is only reported at
2720735627dSJörn-Thorben Hinz 	 * this point:
2730735627dSJörn-Thorben Hinz 	 */
2740735627dSJörn-Thorben Hinz 	link = bpf_map__attach_struct_ops(skel->maps.incompl_cong_ops);
2750735627dSJörn-Thorben Hinz 	ASSERT_ERR_PTR(link, "attach_struct_ops");
2760735627dSJörn-Thorben Hinz 
2770735627dSJörn-Thorben Hinz 	bpf_link__destroy(link);
2780735627dSJörn-Thorben Hinz 	tcp_ca_incompl_cong_ops__destroy(skel);
2790735627dSJörn-Thorben Hinz }
2800735627dSJörn-Thorben Hinz 
test_unsupp_cong_op(void)281f14a3f64SJörn-Thorben Hinz static void test_unsupp_cong_op(void)
282f14a3f64SJörn-Thorben Hinz {
283f14a3f64SJörn-Thorben Hinz 	libbpf_print_fn_t old_print_fn;
284f14a3f64SJörn-Thorben Hinz 	struct tcp_ca_unsupp_cong_op *skel;
285f14a3f64SJörn-Thorben Hinz 
286f14a3f64SJörn-Thorben Hinz 	err_str = "attach to unsupported member get_info";
287f14a3f64SJörn-Thorben Hinz 	found = false;
288f14a3f64SJörn-Thorben Hinz 	old_print_fn = libbpf_set_print(libbpf_debug_print);
289f14a3f64SJörn-Thorben Hinz 
290f14a3f64SJörn-Thorben Hinz 	skel = tcp_ca_unsupp_cong_op__open_and_load();
291f14a3f64SJörn-Thorben Hinz 	ASSERT_NULL(skel, "open_and_load");
292f14a3f64SJörn-Thorben Hinz 	ASSERT_EQ(found, true, "expected_err_msg");
293f14a3f64SJörn-Thorben Hinz 
294f14a3f64SJörn-Thorben Hinz 	tcp_ca_unsupp_cong_op__destroy(skel);
295f14a3f64SJörn-Thorben Hinz 	libbpf_set_print(old_print_fn);
296f14a3f64SJörn-Thorben Hinz }
297f14a3f64SJörn-Thorben Hinz 
test_update_ca(void)29806da9f3bSKui-Feng Lee static void test_update_ca(void)
29906da9f3bSKui-Feng Lee {
30006da9f3bSKui-Feng Lee 	struct tcp_ca_update *skel;
30106da9f3bSKui-Feng Lee 	struct bpf_link *link;
30206da9f3bSKui-Feng Lee 	int saved_ca1_cnt;
30306da9f3bSKui-Feng Lee 	int err;
30406da9f3bSKui-Feng Lee 
30506da9f3bSKui-Feng Lee 	skel = tcp_ca_update__open_and_load();
30606da9f3bSKui-Feng Lee 	if (!ASSERT_OK_PTR(skel, "open"))
30706da9f3bSKui-Feng Lee 		return;
30806da9f3bSKui-Feng Lee 
30906da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_1);
31006da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops");
31106da9f3bSKui-Feng Lee 
31206da9f3bSKui-Feng Lee 	do_test("tcp_ca_update", NULL);
31306da9f3bSKui-Feng Lee 	saved_ca1_cnt = skel->bss->ca1_cnt;
31406da9f3bSKui-Feng Lee 	ASSERT_GT(saved_ca1_cnt, 0, "ca1_ca1_cnt");
31506da9f3bSKui-Feng Lee 
31606da9f3bSKui-Feng Lee 	err = bpf_link__update_map(link, skel->maps.ca_update_2);
31706da9f3bSKui-Feng Lee 	ASSERT_OK(err, "update_map");
31806da9f3bSKui-Feng Lee 
31906da9f3bSKui-Feng Lee 	do_test("tcp_ca_update", NULL);
32006da9f3bSKui-Feng Lee 	ASSERT_EQ(skel->bss->ca1_cnt, saved_ca1_cnt, "ca2_ca1_cnt");
32106da9f3bSKui-Feng Lee 	ASSERT_GT(skel->bss->ca2_cnt, 0, "ca2_ca2_cnt");
32206da9f3bSKui-Feng Lee 
32306da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
32406da9f3bSKui-Feng Lee 	tcp_ca_update__destroy(skel);
32506da9f3bSKui-Feng Lee }
32606da9f3bSKui-Feng Lee 
test_update_wrong(void)32706da9f3bSKui-Feng Lee static void test_update_wrong(void)
32806da9f3bSKui-Feng Lee {
32906da9f3bSKui-Feng Lee 	struct tcp_ca_update *skel;
33006da9f3bSKui-Feng Lee 	struct bpf_link *link;
33106da9f3bSKui-Feng Lee 	int saved_ca1_cnt;
33206da9f3bSKui-Feng Lee 	int err;
33306da9f3bSKui-Feng Lee 
33406da9f3bSKui-Feng Lee 	skel = tcp_ca_update__open_and_load();
33506da9f3bSKui-Feng Lee 	if (!ASSERT_OK_PTR(skel, "open"))
33606da9f3bSKui-Feng Lee 		return;
33706da9f3bSKui-Feng Lee 
33806da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_1);
33906da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops");
34006da9f3bSKui-Feng Lee 
34106da9f3bSKui-Feng Lee 	do_test("tcp_ca_update", NULL);
34206da9f3bSKui-Feng Lee 	saved_ca1_cnt = skel->bss->ca1_cnt;
34306da9f3bSKui-Feng Lee 	ASSERT_GT(saved_ca1_cnt, 0, "ca1_ca1_cnt");
34406da9f3bSKui-Feng Lee 
34506da9f3bSKui-Feng Lee 	err = bpf_link__update_map(link, skel->maps.ca_wrong);
34606da9f3bSKui-Feng Lee 	ASSERT_ERR(err, "update_map");
34706da9f3bSKui-Feng Lee 
34806da9f3bSKui-Feng Lee 	do_test("tcp_ca_update", NULL);
34906da9f3bSKui-Feng Lee 	ASSERT_GT(skel->bss->ca1_cnt, saved_ca1_cnt, "ca2_ca1_cnt");
35006da9f3bSKui-Feng Lee 
35106da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
35206da9f3bSKui-Feng Lee 	tcp_ca_update__destroy(skel);
35306da9f3bSKui-Feng Lee }
35406da9f3bSKui-Feng Lee 
test_mixed_links(void)35506da9f3bSKui-Feng Lee static void test_mixed_links(void)
35606da9f3bSKui-Feng Lee {
35706da9f3bSKui-Feng Lee 	struct tcp_ca_update *skel;
35806da9f3bSKui-Feng Lee 	struct bpf_link *link, *link_nl;
35906da9f3bSKui-Feng Lee 	int err;
36006da9f3bSKui-Feng Lee 
36106da9f3bSKui-Feng Lee 	skel = tcp_ca_update__open_and_load();
36206da9f3bSKui-Feng Lee 	if (!ASSERT_OK_PTR(skel, "open"))
36306da9f3bSKui-Feng Lee 		return;
36406da9f3bSKui-Feng Lee 
36506da9f3bSKui-Feng Lee 	link_nl = bpf_map__attach_struct_ops(skel->maps.ca_no_link);
36606da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link_nl, "attach_struct_ops_nl");
36706da9f3bSKui-Feng Lee 
36806da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_1);
36906da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops");
37006da9f3bSKui-Feng Lee 
37106da9f3bSKui-Feng Lee 	do_test("tcp_ca_update", NULL);
37206da9f3bSKui-Feng Lee 	ASSERT_GT(skel->bss->ca1_cnt, 0, "ca1_ca1_cnt");
37306da9f3bSKui-Feng Lee 
37406da9f3bSKui-Feng Lee 	err = bpf_link__update_map(link, skel->maps.ca_no_link);
37506da9f3bSKui-Feng Lee 	ASSERT_ERR(err, "update_map");
37606da9f3bSKui-Feng Lee 
37706da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
37806da9f3bSKui-Feng Lee 	bpf_link__destroy(link_nl);
37906da9f3bSKui-Feng Lee 	tcp_ca_update__destroy(skel);
38006da9f3bSKui-Feng Lee }
38106da9f3bSKui-Feng Lee 
test_multi_links(void)38206da9f3bSKui-Feng Lee static void test_multi_links(void)
38306da9f3bSKui-Feng Lee {
38406da9f3bSKui-Feng Lee 	struct tcp_ca_update *skel;
38506da9f3bSKui-Feng Lee 	struct bpf_link *link;
38606da9f3bSKui-Feng Lee 
38706da9f3bSKui-Feng Lee 	skel = tcp_ca_update__open_and_load();
38806da9f3bSKui-Feng Lee 	if (!ASSERT_OK_PTR(skel, "open"))
38906da9f3bSKui-Feng Lee 		return;
39006da9f3bSKui-Feng Lee 
39106da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_1);
39206da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops_1st");
39306da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
39406da9f3bSKui-Feng Lee 
39506da9f3bSKui-Feng Lee 	/* A map should be able to be used to create links multiple
39606da9f3bSKui-Feng Lee 	 * times.
39706da9f3bSKui-Feng Lee 	 */
39806da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_1);
39906da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops_2nd");
40006da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
40106da9f3bSKui-Feng Lee 
40206da9f3bSKui-Feng Lee 	tcp_ca_update__destroy(skel);
40306da9f3bSKui-Feng Lee }
40406da9f3bSKui-Feng Lee 
test_link_replace(void)40506da9f3bSKui-Feng Lee static void test_link_replace(void)
40606da9f3bSKui-Feng Lee {
40706da9f3bSKui-Feng Lee 	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, opts);
40806da9f3bSKui-Feng Lee 	struct tcp_ca_update *skel;
40906da9f3bSKui-Feng Lee 	struct bpf_link *link;
41006da9f3bSKui-Feng Lee 	int err;
41106da9f3bSKui-Feng Lee 
41206da9f3bSKui-Feng Lee 	skel = tcp_ca_update__open_and_load();
41306da9f3bSKui-Feng Lee 	if (!ASSERT_OK_PTR(skel, "open"))
41406da9f3bSKui-Feng Lee 		return;
41506da9f3bSKui-Feng Lee 
41606da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_1);
41706da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops_1st");
41806da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
41906da9f3bSKui-Feng Lee 
42006da9f3bSKui-Feng Lee 	link = bpf_map__attach_struct_ops(skel->maps.ca_update_2);
42106da9f3bSKui-Feng Lee 	ASSERT_OK_PTR(link, "attach_struct_ops_2nd");
42206da9f3bSKui-Feng Lee 
42306da9f3bSKui-Feng Lee 	/* BPF_F_REPLACE with a wrong old map Fd. It should fail!
42406da9f3bSKui-Feng Lee 	 *
42506da9f3bSKui-Feng Lee 	 * With BPF_F_REPLACE, the link should be updated only if the
42606da9f3bSKui-Feng Lee 	 * old map fd given here matches the map backing the link.
42706da9f3bSKui-Feng Lee 	 */
42806da9f3bSKui-Feng Lee 	opts.old_map_fd = bpf_map__fd(skel->maps.ca_update_1);
42906da9f3bSKui-Feng Lee 	opts.flags = BPF_F_REPLACE;
43006da9f3bSKui-Feng Lee 	err = bpf_link_update(bpf_link__fd(link),
43106da9f3bSKui-Feng Lee 			      bpf_map__fd(skel->maps.ca_update_1),
43206da9f3bSKui-Feng Lee 			      &opts);
43306da9f3bSKui-Feng Lee 	ASSERT_ERR(err, "bpf_link_update_fail");
43406da9f3bSKui-Feng Lee 
43506da9f3bSKui-Feng Lee 	/* BPF_F_REPLACE with a correct old map Fd. It should success! */
43606da9f3bSKui-Feng Lee 	opts.old_map_fd = bpf_map__fd(skel->maps.ca_update_2);
43706da9f3bSKui-Feng Lee 	err = bpf_link_update(bpf_link__fd(link),
43806da9f3bSKui-Feng Lee 			      bpf_map__fd(skel->maps.ca_update_1),
43906da9f3bSKui-Feng Lee 			      &opts);
44006da9f3bSKui-Feng Lee 	ASSERT_OK(err, "bpf_link_update_success");
44106da9f3bSKui-Feng Lee 
44206da9f3bSKui-Feng Lee 	bpf_link__destroy(link);
44306da9f3bSKui-Feng Lee 
44406da9f3bSKui-Feng Lee 	tcp_ca_update__destroy(skel);
44506da9f3bSKui-Feng Lee }
44606da9f3bSKui-Feng Lee 
test_tcp_ca_kfunc(void)4475da7fb04SMartin KaFai Lau static void test_tcp_ca_kfunc(void)
4485da7fb04SMartin KaFai Lau {
4495da7fb04SMartin KaFai Lau 	struct tcp_ca_kfunc *skel;
4505da7fb04SMartin KaFai Lau 
4515da7fb04SMartin KaFai Lau 	skel = tcp_ca_kfunc__open_and_load();
4525da7fb04SMartin KaFai Lau 	ASSERT_OK_PTR(skel, "tcp_ca_kfunc__open_and_load");
4535da7fb04SMartin KaFai Lau 	tcp_ca_kfunc__destroy(skel);
4545da7fb04SMartin KaFai Lau }
4555da7fb04SMartin KaFai Lau 
test_cc_cubic(void)456*96c3490dSMiao Xu static void test_cc_cubic(void)
457*96c3490dSMiao Xu {
458*96c3490dSMiao Xu 	struct bpf_cc_cubic *cc_cubic_skel;
459*96c3490dSMiao Xu 	struct bpf_link *link;
460*96c3490dSMiao Xu 
461*96c3490dSMiao Xu 	cc_cubic_skel = bpf_cc_cubic__open_and_load();
462*96c3490dSMiao Xu 	if (!ASSERT_OK_PTR(cc_cubic_skel, "bpf_cc_cubic__open_and_load"))
463*96c3490dSMiao Xu 		return;
464*96c3490dSMiao Xu 
465*96c3490dSMiao Xu 	link = bpf_map__attach_struct_ops(cc_cubic_skel->maps.cc_cubic);
466*96c3490dSMiao Xu 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
467*96c3490dSMiao Xu 		bpf_cc_cubic__destroy(cc_cubic_skel);
468*96c3490dSMiao Xu 		return;
469*96c3490dSMiao Xu 	}
470*96c3490dSMiao Xu 
471*96c3490dSMiao Xu 	do_test("bpf_cc_cubic", NULL);
472*96c3490dSMiao Xu 
473*96c3490dSMiao Xu 	bpf_link__destroy(link);
474*96c3490dSMiao Xu 	bpf_cc_cubic__destroy(cc_cubic_skel);
475*96c3490dSMiao Xu }
476*96c3490dSMiao Xu 
test_bpf_tcp_ca(void)47709903869SMartin KaFai Lau void test_bpf_tcp_ca(void)
47809903869SMartin KaFai Lau {
47909903869SMartin KaFai Lau 	if (test__start_subtest("dctcp"))
48009903869SMartin KaFai Lau 		test_dctcp();
4816de4a9c4SMartin KaFai Lau 	if (test__start_subtest("cubic"))
4826de4a9c4SMartin KaFai Lau 		test_cubic();
483d8e8052eSToke Høiland-Jørgensen 	if (test__start_subtest("invalid_license"))
484d8e8052eSToke Høiland-Jørgensen 		test_invalid_license();
485574ee209SMartin KaFai Lau 	if (test__start_subtest("dctcp_fallback"))
486574ee209SMartin KaFai Lau 		test_dctcp_fallback();
487574ee209SMartin KaFai Lau 	if (test__start_subtest("rel_setsockopt"))
488574ee209SMartin KaFai Lau 		test_rel_setsockopt();
4896e945d57SJörn-Thorben Hinz 	if (test__start_subtest("write_sk_pacing"))
4906e945d57SJörn-Thorben Hinz 		test_write_sk_pacing();
4910735627dSJörn-Thorben Hinz 	if (test__start_subtest("incompl_cong_ops"))
4920735627dSJörn-Thorben Hinz 		test_incompl_cong_ops();
493f14a3f64SJörn-Thorben Hinz 	if (test__start_subtest("unsupp_cong_op"))
494f14a3f64SJörn-Thorben Hinz 		test_unsupp_cong_op();
49506da9f3bSKui-Feng Lee 	if (test__start_subtest("update_ca"))
49606da9f3bSKui-Feng Lee 		test_update_ca();
49706da9f3bSKui-Feng Lee 	if (test__start_subtest("update_wrong"))
49806da9f3bSKui-Feng Lee 		test_update_wrong();
49906da9f3bSKui-Feng Lee 	if (test__start_subtest("mixed_links"))
50006da9f3bSKui-Feng Lee 		test_mixed_links();
50106da9f3bSKui-Feng Lee 	if (test__start_subtest("multi_links"))
50206da9f3bSKui-Feng Lee 		test_multi_links();
50306da9f3bSKui-Feng Lee 	if (test__start_subtest("link_replace"))
50406da9f3bSKui-Feng Lee 		test_link_replace();
5055da7fb04SMartin KaFai Lau 	if (test__start_subtest("tcp_ca_kfunc"))
5065da7fb04SMartin KaFai Lau 		test_tcp_ca_kfunc();
507*96c3490dSMiao Xu 	if (test__start_subtest("cc_cubic"))
508*96c3490dSMiao Xu 		test_cc_cubic();
50909903869SMartin KaFai Lau }
510