Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Martin KaFai Lau | 2597 | 97.30% | 7 | 70.00% |
Wang Yufen | 61 | 2.29% | 1 | 10.00% |
Andrii Nakryiko | 10 | 0.37% | 1 | 10.00% |
Lu Hongfei | 1 | 0.04% | 1 | 10.00% |
Total | 2669 | 10 |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2020 Facebook */ #define _GNU_SOURCE #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <linux/compiler.h> #include "test_progs.h" #include "cgroup_helpers.h" #include "network_helpers.h" #include "test_tcp_hdr_options.h" #include "test_tcp_hdr_options.skel.h" #include "test_misc_tcp_hdr_options.skel.h" #define LO_ADDR6 "::1" #define CG_NAME "/tcpbpf-hdr-opt-test" static struct bpf_test_option exp_passive_estab_in; static struct bpf_test_option exp_active_estab_in; static struct bpf_test_option exp_passive_fin_in; static struct bpf_test_option exp_active_fin_in; static struct hdr_stg exp_passive_hdr_stg; static struct hdr_stg exp_active_hdr_stg = { .active = true, }; static struct test_misc_tcp_hdr_options *misc_skel; static struct test_tcp_hdr_options *skel; static int lport_linum_map_fd; static int hdr_stg_map_fd; static __u32 duration; static int cg_fd; struct sk_fds { int srv_fd; int passive_fd; int active_fd; int passive_lport; int active_lport; }; static int create_netns(void) { if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) return -1; if (!ASSERT_OK(system("ip link set dev lo up"), "run ip cmd")) return -1; return 0; } static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix) { fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n", prefix ? : "", hdr_stg->active, hdr_stg->resend_syn, hdr_stg->syncookie, hdr_stg->fastopen); } static void print_option(const struct bpf_test_option *opt, const char *prefix) { fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n", prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand); } static void sk_fds_close(struct sk_fds *sk_fds) { close(sk_fds->srv_fd); close(sk_fds->passive_fd); close(sk_fds->active_fd); } static int sk_fds_shutdown(struct sk_fds *sk_fds) { int ret, abyte; shutdown(sk_fds->active_fd, SHUT_WR); ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte)); if (!ASSERT_EQ(ret, 0, "read-after-shutdown(passive_fd):")) return -1; shutdown(sk_fds->passive_fd, SHUT_WR); ret = read(sk_fds->active_fd, &abyte, sizeof(abyte)); if (!ASSERT_EQ(ret, 0, "read-after-shutdown(active_fd):")) return -1; return 0; } static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open) { const char fast[] = "FAST!!!"; struct sockaddr_in6 addr6; socklen_t len; sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0); if (!ASSERT_NEQ(sk_fds->srv_fd, -1, "start_server")) goto error; if (fast_open) sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast, sizeof(fast), 0); else sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0); if (!ASSERT_NEQ(sk_fds->active_fd, -1, "")) { close(sk_fds->srv_fd); goto error; } len = sizeof(addr6); if (!ASSERT_OK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6, &len), "getsockname(srv_fd)")) goto error_close; sk_fds->passive_lport = ntohs(addr6.sin6_port); len = sizeof(addr6); if (!ASSERT_OK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6, &len), "getsockname(active_fd)")) goto error_close; sk_fds->active_lport = ntohs(addr6.sin6_port); sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0); if (!ASSERT_NEQ(sk_fds->passive_fd, -1, "accept(srv_fd)")) goto error_close; if (fast_open) { char bytes_in[sizeof(fast)]; int ret; ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in)); if (!ASSERT_EQ(ret, sizeof(fast), "read fastopen syn data")) { close(sk_fds->passive_fd); goto error_close; } } return 0; error_close: close(sk_fds->active_fd); close(sk_fds->srv_fd); error: memset(sk_fds, -1, sizeof(*sk_fds)); return -1; } static int check_hdr_opt(const struct bpf_test_option *exp, const struct bpf_test_option *act, const char *hdr_desc) { if (!ASSERT_EQ(memcmp(exp, act, sizeof(*exp)), 0, hdr_desc)) { print_option(exp, "expected: "); print_option(act, " actual: "); return -1; } return 0; } static int check_hdr_stg(const struct hdr_stg *exp, int fd, const char *stg_desc) { struct hdr_stg act; if (!ASSERT_OK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act), "map_lookup(hdr_stg_map_fd)")) return -1; if (!ASSERT_EQ(memcmp(exp, &act, sizeof(*exp)), 0, stg_desc)) { print_hdr_stg(exp, "expected: "); print_hdr_stg(&act, " actual: "); return -1; } return 0; } static int check_error_linum(const struct sk_fds *sk_fds) { unsigned int nr_errors = 0; struct linum_err linum_err; int lport; lport = sk_fds->passive_lport; if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) { fprintf(stderr, "bpf prog error out at lport:passive(%d), linum:%u err:%d\n", lport, linum_err.linum, linum_err.err); nr_errors++; } lport = sk_fds->active_lport; if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) { fprintf(stderr, "bpf prog error out at lport:active(%d), linum:%u err:%d\n", lport, linum_err.linum, linum_err.err); nr_errors++; } return nr_errors; } static void check_hdr_and_close_fds(struct sk_fds *sk_fds) { const __u32 expected_inherit_cb_flags = BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG | BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG | BPF_SOCK_OPS_STATE_CB_FLAG; if (sk_fds_shutdown(sk_fds)) goto check_linum; if (!ASSERT_EQ(expected_inherit_cb_flags, skel->bss->inherit_cb_flags, "inherit_cb_flags")) goto check_linum; if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd, "passive_hdr_stg")) goto check_linum; if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd, "active_hdr_stg")) goto check_linum; if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in, "passive_estab_in")) goto check_linum; if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in, "active_estab_in")) goto check_linum; if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in, "passive_fin_in")) goto check_linum; check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in, "active_fin_in"); check_linum: ASSERT_FALSE(check_error_linum(sk_fds), "check_error_linum"); sk_fds_close(sk_fds); } static void prepare_out(void) { skel->bss->active_syn_out = exp_passive_estab_in; skel->bss->passive_synack_out = exp_active_estab_in; skel->bss->active_fin_out = exp_passive_fin_in; skel->bss->passive_fin_out = exp_active_fin_in; } static void reset_test(void) { size_t optsize = sizeof(struct bpf_test_option); int lport, err; memset(&skel->bss->passive_synack_out, 0, optsize); memset(&skel->bss->passive_fin_out, 0, optsize); memset(&skel->bss->passive_estab_in, 0, optsize); memset(&skel->bss->passive_fin_in, 0, optsize); memset(&skel->bss->active_syn_out, 0, optsize); memset(&skel->bss->active_fin_out, 0, optsize); memset(&skel->bss->active_estab_in, 0, optsize); memset(&skel->bss->active_fin_in, 0, optsize); skel->bss->inherit_cb_flags = 0; skel->data->test_kind = TCPOPT_EXP; skel->data->test_magic = 0xeB9F; memset(&exp_passive_estab_in, 0, optsize); memset(&exp_active_estab_in, 0, optsize); memset(&exp_passive_fin_in, 0, optsize); memset(&exp_active_fin_in, 0, optsize); memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg)); memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg)); exp_active_hdr_stg.active = true; err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport); while (!err) { bpf_map_delete_elem(lport_linum_map_fd, &lport); err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport); } } static void fastopen_estab(void) { struct bpf_link *link; struct sk_fds sk_fds; hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map); lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map); exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS; exp_passive_estab_in.rand = 0xfa; exp_passive_estab_in.max_delack_ms = 11; exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS; exp_active_estab_in.rand = 0xce; exp_active_estab_in.max_delack_ms = 22; exp_passive_hdr_stg.fastopen = true; prepare_out(); /* Allow fastopen without fastopen cookie */ if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543")) return; link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd); if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)")) return; if (sk_fds_connect(&sk_fds, true)) { bpf_link__destroy(link); return; } check_hdr_and_close_fds(&sk_fds); bpf_link__destroy(link); } static void syncookie_estab(void) { struct bpf_link *link; struct sk_fds sk_fds; hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map); lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map); exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS; exp_passive_estab_in.rand = 0xfa; exp_passive_estab_in.max_delack_ms = 11; exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS | OPTION_F_RESEND; exp_active_estab_in.rand = 0xce; exp_active_estab_in.max_delack_ms = 22; exp_passive_hdr_stg.syncookie = true; exp_active_hdr_stg.resend_syn = true; prepare_out(); /* Clear the RESEND to ensure the bpf prog can learn * want_cookie and set the RESEND by itself. */ skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND; /* Enforce syncookie mode */ if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2")) return; link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd); if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)")) return; if (sk_fds_connect(&sk_fds, false)) { bpf_link__destroy(link); return; } check_hdr_and_close_fds(&sk_fds); bpf_link__destroy(link); } static void fin(void) { struct bpf_link *link; struct sk_fds sk_fds; hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map); lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map); exp_passive_fin_in.flags = OPTION_F_RAND; exp_passive_fin_in.rand = 0xfa; exp_active_fin_in.flags = OPTION_F_RAND; exp_active_fin_in.rand = 0xce; prepare_out(); if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1")) return; link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd); if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)")) return; if (sk_fds_connect(&sk_fds, false)) { bpf_link__destroy(link); return; } check_hdr_and_close_fds(&sk_fds); bpf_link__destroy(link); } static void __simple_estab(bool exprm) { struct bpf_link *link; struct sk_fds sk_fds; hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map); lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map); exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS; exp_passive_estab_in.rand = 0xfa; exp_passive_estab_in.max_delack_ms = 11; exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS; exp_active_estab_in.rand = 0xce; exp_active_estab_in.max_delack_ms = 22; prepare_out(); if (!exprm) { skel->data->test_kind = 0xB9; skel->data->test_magic = 0; } if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1")) return; link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd); if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)")) return; if (sk_fds_connect(&sk_fds, false)) { bpf_link__destroy(link); return; } check_hdr_and_close_fds(&sk_fds); bpf_link__destroy(link); } static void no_exprm_estab(void) { __simple_estab(false); } static void simple_estab(void) { __simple_estab(true); } static void misc(void) { const char send_msg[] = "MISC!!!"; char recv_msg[sizeof(send_msg)]; const unsigned int nr_data = 2; struct bpf_link *link; struct sk_fds sk_fds; int i, ret; lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map); if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1")) return; link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd); if (!ASSERT_OK_PTR(link, "attach_cgroup(misc_estab)")) return; if (sk_fds_connect(&sk_fds, false)) { bpf_link__destroy(link); return; } for (i = 0; i < nr_data; i++) { /* MSG_EOR to ensure skb will not be combined */ ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg), MSG_EOR); if (!ASSERT_EQ(ret, sizeof(send_msg), "send(msg)")) goto check_linum; ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg)); if (!ASSERT_EQ(ret, sizeof(send_msg), "read(msg)")) goto check_linum; } if (sk_fds_shutdown(&sk_fds)) goto check_linum; ASSERT_EQ(misc_skel->bss->nr_syn, 1, "unexpected nr_syn"); ASSERT_EQ(misc_skel->bss->nr_data, nr_data, "unexpected nr_data"); /* The last ACK may have been delayed, so it is either 1 or 2. */ CHECK(misc_skel->bss->nr_pure_ack != 1 && misc_skel->bss->nr_pure_ack != 2, "unexpected nr_pure_ack", "expected (1 or 2) != actual (%u)\n", misc_skel->bss->nr_pure_ack); ASSERT_EQ(misc_skel->bss->nr_fin, 1, "unexpected nr_fin"); ASSERT_EQ(misc_skel->bss->nr_hwtstamp, 0, "nr_hwtstamp"); check_linum: ASSERT_FALSE(check_error_linum(&sk_fds), "check_error_linum"); sk_fds_close(&sk_fds); bpf_link__destroy(link); } struct test { const char *desc; void (*run)(void); }; #define DEF_TEST(name) { #name, name } static struct test tests[] = { DEF_TEST(simple_estab), DEF_TEST(no_exprm_estab), DEF_TEST(syncookie_estab), DEF_TEST(fastopen_estab), DEF_TEST(fin), DEF_TEST(misc), }; void test_tcp_hdr_options(void) { int i; skel = test_tcp_hdr_options__open_and_load(); if (!ASSERT_OK_PTR(skel, "open and load skel")) return; misc_skel = test_misc_tcp_hdr_options__open_and_load(); if (!ASSERT_OK_PTR(misc_skel, "open and load misc test skel")) goto skel_destroy; cg_fd = test__join_cgroup(CG_NAME); if (!ASSERT_GE(cg_fd, 0, "join_cgroup")) goto skel_destroy; for (i = 0; i < ARRAY_SIZE(tests); i++) { if (!test__start_subtest(tests[i].desc)) continue; if (create_netns()) break; tests[i].run(); reset_test(); } close(cg_fd); skel_destroy: test_misc_tcp_hdr_options__destroy(misc_skel); test_tcp_hdr_options__destroy(skel); }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1