1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
8 #include <sys/socket.h>
9 #include <linux/compiler.h>
11 #include "test_progs.h"
12 #include "cgroup_helpers.h"
13 #include "network_helpers.h"
14 #include "test_tcp_hdr_options.h"
15 #include "test_tcp_hdr_options.skel.h"
16 #include "test_misc_tcp_hdr_options.skel.h"
18 #define LO_ADDR6 "::1"
19 #define CG_NAME "/tcpbpf-hdr-opt-test"
21 static struct bpf_test_option exp_passive_estab_in;
22 static struct bpf_test_option exp_active_estab_in;
23 static struct bpf_test_option exp_passive_fin_in;
24 static struct bpf_test_option exp_active_fin_in;
25 static struct hdr_stg exp_passive_hdr_stg;
26 static struct hdr_stg exp_active_hdr_stg = { .active = true, };
28 static struct test_misc_tcp_hdr_options *misc_skel;
29 static struct test_tcp_hdr_options *skel;
30 static int lport_linum_map_fd;
31 static int hdr_stg_map_fd;
32 static __u32 duration;
43 static int create_netns(void)
45 if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
48 if (!ASSERT_OK(system("ip link set dev lo up"), "run ip cmd"))
54 static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix)
56 fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n",
57 prefix ? : "", hdr_stg->active, hdr_stg->resend_syn,
58 hdr_stg->syncookie, hdr_stg->fastopen);
61 static void print_option(const struct bpf_test_option *opt, const char *prefix)
63 fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n",
64 prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand);
67 static void sk_fds_close(struct sk_fds *sk_fds)
69 close(sk_fds->srv_fd);
70 close(sk_fds->passive_fd);
71 close(sk_fds->active_fd);
74 static int sk_fds_shutdown(struct sk_fds *sk_fds)
78 shutdown(sk_fds->active_fd, SHUT_WR);
79 ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte));
80 if (!ASSERT_EQ(ret, 0, "read-after-shutdown(passive_fd):"))
83 shutdown(sk_fds->passive_fd, SHUT_WR);
84 ret = read(sk_fds->active_fd, &abyte, sizeof(abyte));
85 if (!ASSERT_EQ(ret, 0, "read-after-shutdown(active_fd):"))
91 static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open)
93 const char fast[] = "FAST!!!";
94 struct sockaddr_in6 addr6;
97 sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);
98 if (!ASSERT_NEQ(sk_fds->srv_fd, -1, "start_server"))
102 sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast,
105 sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0);
107 if (!ASSERT_NEQ(sk_fds->active_fd, -1, "")) {
108 close(sk_fds->srv_fd);
113 if (!ASSERT_OK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6,
114 &len), "getsockname(srv_fd)"))
116 sk_fds->passive_lport = ntohs(addr6.sin6_port);
119 if (!ASSERT_OK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6,
120 &len), "getsockname(active_fd)"))
122 sk_fds->active_lport = ntohs(addr6.sin6_port);
124 sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0);
125 if (!ASSERT_NEQ(sk_fds->passive_fd, -1, "accept(srv_fd)"))
129 char bytes_in[sizeof(fast)];
132 ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in));
133 if (!ASSERT_EQ(ret, sizeof(fast), "read fastopen syn data")) {
134 close(sk_fds->passive_fd);
142 close(sk_fds->active_fd);
143 close(sk_fds->srv_fd);
146 memset(sk_fds, -1, sizeof(*sk_fds));
150 static int check_hdr_opt(const struct bpf_test_option *exp,
151 const struct bpf_test_option *act,
152 const char *hdr_desc)
154 if (!ASSERT_EQ(memcmp(exp, act, sizeof(*exp)), 0, hdr_desc)) {
155 print_option(exp, "expected: ");
156 print_option(act, " actual: ");
163 static int check_hdr_stg(const struct hdr_stg *exp, int fd,
164 const char *stg_desc)
168 if (!ASSERT_OK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act),
169 "map_lookup(hdr_stg_map_fd)"))
172 if (!ASSERT_EQ(memcmp(exp, &act, sizeof(*exp)), 0, stg_desc)) {
173 print_hdr_stg(exp, "expected: ");
174 print_hdr_stg(&act, " actual: ");
181 static int check_error_linum(const struct sk_fds *sk_fds)
183 unsigned int nr_errors = 0;
184 struct linum_err linum_err;
187 lport = sk_fds->passive_lport;
188 if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
190 "bpf prog error out at lport:passive(%d), linum:%u err:%d\n",
191 lport, linum_err.linum, linum_err.err);
195 lport = sk_fds->active_lport;
196 if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
198 "bpf prog error out at lport:active(%d), linum:%u err:%d\n",
199 lport, linum_err.linum, linum_err.err);
206 static void check_hdr_and_close_fds(struct sk_fds *sk_fds)
208 const __u32 expected_inherit_cb_flags =
209 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
210 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
211 BPF_SOCK_OPS_STATE_CB_FLAG;
213 if (sk_fds_shutdown(sk_fds))
216 if (!ASSERT_EQ(expected_inherit_cb_flags, skel->bss->inherit_cb_flags,
220 if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,
224 if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd,
228 if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in,
232 if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in,
236 if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in,
240 check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in,
244 ASSERT_FALSE(check_error_linum(sk_fds), "check_error_linum");
245 sk_fds_close(sk_fds);
248 static void prepare_out(void)
250 skel->bss->active_syn_out = exp_passive_estab_in;
251 skel->bss->passive_synack_out = exp_active_estab_in;
253 skel->bss->active_fin_out = exp_passive_fin_in;
254 skel->bss->passive_fin_out = exp_active_fin_in;
257 static void reset_test(void)
259 size_t optsize = sizeof(struct bpf_test_option);
262 memset(&skel->bss->passive_synack_out, 0, optsize);
263 memset(&skel->bss->passive_fin_out, 0, optsize);
265 memset(&skel->bss->passive_estab_in, 0, optsize);
266 memset(&skel->bss->passive_fin_in, 0, optsize);
268 memset(&skel->bss->active_syn_out, 0, optsize);
269 memset(&skel->bss->active_fin_out, 0, optsize);
271 memset(&skel->bss->active_estab_in, 0, optsize);
272 memset(&skel->bss->active_fin_in, 0, optsize);
274 skel->bss->inherit_cb_flags = 0;
276 skel->data->test_kind = TCPOPT_EXP;
277 skel->data->test_magic = 0xeB9F;
279 memset(&exp_passive_estab_in, 0, optsize);
280 memset(&exp_active_estab_in, 0, optsize);
281 memset(&exp_passive_fin_in, 0, optsize);
282 memset(&exp_active_fin_in, 0, optsize);
284 memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg));
285 memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg));
286 exp_active_hdr_stg.active = true;
288 err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport);
290 bpf_map_delete_elem(lport_linum_map_fd, &lport);
291 err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport);
295 static void fastopen_estab(void)
297 struct bpf_link *link;
298 struct sk_fds sk_fds;
300 hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
301 lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
303 exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
304 exp_passive_estab_in.rand = 0xfa;
305 exp_passive_estab_in.max_delack_ms = 11;
307 exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
308 exp_active_estab_in.rand = 0xce;
309 exp_active_estab_in.max_delack_ms = 22;
311 exp_passive_hdr_stg.fastopen = true;
315 /* Allow fastopen without fastopen cookie */
316 if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543"))
319 link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
320 if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
323 if (sk_fds_connect(&sk_fds, true)) {
324 bpf_link__destroy(link);
328 check_hdr_and_close_fds(&sk_fds);
329 bpf_link__destroy(link);
332 static void syncookie_estab(void)
334 struct bpf_link *link;
335 struct sk_fds sk_fds;
337 hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
338 lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
340 exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
341 exp_passive_estab_in.rand = 0xfa;
342 exp_passive_estab_in.max_delack_ms = 11;
344 exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS |
346 exp_active_estab_in.rand = 0xce;
347 exp_active_estab_in.max_delack_ms = 22;
349 exp_passive_hdr_stg.syncookie = true;
350 exp_active_hdr_stg.resend_syn = true;
354 /* Clear the RESEND to ensure the bpf prog can learn
355 * want_cookie and set the RESEND by itself.
357 skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND;
359 /* Enforce syncookie mode */
360 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
363 link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
364 if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
367 if (sk_fds_connect(&sk_fds, false)) {
368 bpf_link__destroy(link);
372 check_hdr_and_close_fds(&sk_fds);
373 bpf_link__destroy(link);
376 static void fin(void)
378 struct bpf_link *link;
379 struct sk_fds sk_fds;
381 hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
382 lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
384 exp_passive_fin_in.flags = OPTION_F_RAND;
385 exp_passive_fin_in.rand = 0xfa;
387 exp_active_fin_in.flags = OPTION_F_RAND;
388 exp_active_fin_in.rand = 0xce;
392 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
395 link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
396 if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
399 if (sk_fds_connect(&sk_fds, false)) {
400 bpf_link__destroy(link);
404 check_hdr_and_close_fds(&sk_fds);
405 bpf_link__destroy(link);
408 static void __simple_estab(bool exprm)
410 struct bpf_link *link;
411 struct sk_fds sk_fds;
413 hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
414 lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
416 exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
417 exp_passive_estab_in.rand = 0xfa;
418 exp_passive_estab_in.max_delack_ms = 11;
420 exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
421 exp_active_estab_in.rand = 0xce;
422 exp_active_estab_in.max_delack_ms = 22;
427 skel->data->test_kind = 0xB9;
428 skel->data->test_magic = 0;
431 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
434 link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
435 if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
438 if (sk_fds_connect(&sk_fds, false)) {
439 bpf_link__destroy(link);
443 check_hdr_and_close_fds(&sk_fds);
444 bpf_link__destroy(link);
447 static void no_exprm_estab(void)
449 __simple_estab(false);
452 static void simple_estab(void)
454 __simple_estab(true);
457 static void misc(void)
459 const char send_msg[] = "MISC!!!";
460 char recv_msg[sizeof(send_msg)];
461 const unsigned int nr_data = 2;
462 struct bpf_link *link;
463 struct sk_fds sk_fds;
466 lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map);
468 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
471 link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd);
472 if (!ASSERT_OK_PTR(link, "attach_cgroup(misc_estab)"))
475 if (sk_fds_connect(&sk_fds, false)) {
476 bpf_link__destroy(link);
480 for (i = 0; i < nr_data; i++) {
481 /* MSG_EOR to ensure skb will not be combined */
482 ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg),
484 if (!ASSERT_EQ(ret, sizeof(send_msg), "send(msg)"))
487 ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg));
488 if (!ASSERT_EQ(ret, sizeof(send_msg), "read(msg)"))
492 if (sk_fds_shutdown(&sk_fds))
495 ASSERT_EQ(misc_skel->bss->nr_syn, 1, "unexpected nr_syn");
497 ASSERT_EQ(misc_skel->bss->nr_data, nr_data, "unexpected nr_data");
499 /* The last ACK may have been delayed, so it is either 1 or 2. */
500 CHECK(misc_skel->bss->nr_pure_ack != 1 &&
501 misc_skel->bss->nr_pure_ack != 2,
502 "unexpected nr_pure_ack",
503 "expected (1 or 2) != actual (%u)\n",
504 misc_skel->bss->nr_pure_ack);
506 ASSERT_EQ(misc_skel->bss->nr_fin, 1, "unexpected nr_fin");
508 ASSERT_EQ(misc_skel->bss->nr_hwtstamp, 0, "nr_hwtstamp");
511 ASSERT_FALSE(check_error_linum(&sk_fds), "check_error_linum");
512 sk_fds_close(&sk_fds);
513 bpf_link__destroy(link);
521 #define DEF_TEST(name) { #name, name }
522 static struct test tests[] = {
523 DEF_TEST(simple_estab),
524 DEF_TEST(no_exprm_estab),
525 DEF_TEST(syncookie_estab),
526 DEF_TEST(fastopen_estab),
531 void test_tcp_hdr_options(void)
535 skel = test_tcp_hdr_options__open_and_load();
536 if (!ASSERT_OK_PTR(skel, "open and load skel"))
539 misc_skel = test_misc_tcp_hdr_options__open_and_load();
540 if (!ASSERT_OK_PTR(misc_skel, "open and load misc test skel"))
543 cg_fd = test__join_cgroup(CG_NAME);
544 if (!ASSERT_GE(cg_fd, 0, "join_cgroup"))
547 for (i = 0; i < ARRAY_SIZE(tests); i++) {
548 if (!test__start_subtest(tests[i].desc))
561 test_misc_tcp_hdr_options__destroy(misc_skel);
562 test_tcp_hdr_options__destroy(skel);