Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020 Facebook */
0003 
0004 #define _GNU_SOURCE
0005 #include <sched.h>
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <sys/socket.h>
0009 #include <linux/compiler.h>
0010 
0011 #include "test_progs.h"
0012 #include "cgroup_helpers.h"
0013 #include "network_helpers.h"
0014 #include "test_tcp_hdr_options.h"
0015 #include "test_tcp_hdr_options.skel.h"
0016 #include "test_misc_tcp_hdr_options.skel.h"
0017 
0018 #define LO_ADDR6 "::1"
0019 #define CG_NAME "/tcpbpf-hdr-opt-test"
0020 
0021 static struct bpf_test_option exp_passive_estab_in;
0022 static struct bpf_test_option exp_active_estab_in;
0023 static struct bpf_test_option exp_passive_fin_in;
0024 static struct bpf_test_option exp_active_fin_in;
0025 static struct hdr_stg exp_passive_hdr_stg;
0026 static struct hdr_stg exp_active_hdr_stg = { .active = true, };
0027 
0028 static struct test_misc_tcp_hdr_options *misc_skel;
0029 static struct test_tcp_hdr_options *skel;
0030 static int lport_linum_map_fd;
0031 static int hdr_stg_map_fd;
0032 static __u32 duration;
0033 static int cg_fd;
0034 
0035 struct sk_fds {
0036     int srv_fd;
0037     int passive_fd;
0038     int active_fd;
0039     int passive_lport;
0040     int active_lport;
0041 };
0042 
0043 static int create_netns(void)
0044 {
0045     if (CHECK(unshare(CLONE_NEWNET), "create netns",
0046           "unshare(CLONE_NEWNET): %s (%d)",
0047           strerror(errno), errno))
0048         return -1;
0049 
0050     if (CHECK(system("ip link set dev lo up"), "run ip cmd",
0051           "failed to bring lo link up\n"))
0052         return -1;
0053 
0054     return 0;
0055 }
0056 
0057 static int write_sysctl(const char *sysctl, const char *value)
0058 {
0059     int fd, err, len;
0060 
0061     fd = open(sysctl, O_WRONLY);
0062     if (CHECK(fd == -1, "open sysctl", "open(%s): %s (%d)\n",
0063           sysctl, strerror(errno), errno))
0064         return -1;
0065 
0066     len = strlen(value);
0067     err = write(fd, value, len);
0068     close(fd);
0069     if (CHECK(err != len, "write sysctl",
0070           "write(%s, %s): err:%d %s (%d)\n",
0071           sysctl, value, err, strerror(errno), errno))
0072         return -1;
0073 
0074     return 0;
0075 }
0076 
0077 static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix)
0078 {
0079     fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n",
0080         prefix ? : "", hdr_stg->active, hdr_stg->resend_syn,
0081         hdr_stg->syncookie, hdr_stg->fastopen);
0082 }
0083 
0084 static void print_option(const struct bpf_test_option *opt, const char *prefix)
0085 {
0086     fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n",
0087         prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand);
0088 }
0089 
0090 static void sk_fds_close(struct sk_fds *sk_fds)
0091 {
0092     close(sk_fds->srv_fd);
0093     close(sk_fds->passive_fd);
0094     close(sk_fds->active_fd);
0095 }
0096 
0097 static int sk_fds_shutdown(struct sk_fds *sk_fds)
0098 {
0099     int ret, abyte;
0100 
0101     shutdown(sk_fds->active_fd, SHUT_WR);
0102     ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte));
0103     if (CHECK(ret != 0, "read-after-shutdown(passive_fd):",
0104           "ret:%d %s (%d)\n",
0105           ret, strerror(errno), errno))
0106         return -1;
0107 
0108     shutdown(sk_fds->passive_fd, SHUT_WR);
0109     ret = read(sk_fds->active_fd, &abyte, sizeof(abyte));
0110     if (CHECK(ret != 0, "read-after-shutdown(active_fd):",
0111           "ret:%d %s (%d)\n",
0112           ret, strerror(errno), errno))
0113         return -1;
0114 
0115     return 0;
0116 }
0117 
0118 static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open)
0119 {
0120     const char fast[] = "FAST!!!";
0121     struct sockaddr_in6 addr6;
0122     socklen_t len;
0123 
0124     sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);
0125     if (CHECK(sk_fds->srv_fd == -1, "start_server", "%s (%d)\n",
0126           strerror(errno), errno))
0127         goto error;
0128 
0129     if (fast_open)
0130         sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast,
0131                              sizeof(fast), 0);
0132     else
0133         sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0);
0134 
0135     if (CHECK_FAIL(sk_fds->active_fd == -1)) {
0136         close(sk_fds->srv_fd);
0137         goto error;
0138     }
0139 
0140     len = sizeof(addr6);
0141     if (CHECK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6,
0142                   &len), "getsockname(srv_fd)", "%s (%d)\n",
0143           strerror(errno), errno))
0144         goto error_close;
0145     sk_fds->passive_lport = ntohs(addr6.sin6_port);
0146 
0147     len = sizeof(addr6);
0148     if (CHECK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6,
0149                   &len), "getsockname(active_fd)", "%s (%d)\n",
0150           strerror(errno), errno))
0151         goto error_close;
0152     sk_fds->active_lport = ntohs(addr6.sin6_port);
0153 
0154     sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0);
0155     if (CHECK(sk_fds->passive_fd == -1, "accept(srv_fd)", "%s (%d)\n",
0156           strerror(errno), errno))
0157         goto error_close;
0158 
0159     if (fast_open) {
0160         char bytes_in[sizeof(fast)];
0161         int ret;
0162 
0163         ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in));
0164         if (CHECK(ret != sizeof(fast), "read fastopen syn data",
0165               "expected=%lu actual=%d\n", sizeof(fast), ret)) {
0166             close(sk_fds->passive_fd);
0167             goto error_close;
0168         }
0169     }
0170 
0171     return 0;
0172 
0173 error_close:
0174     close(sk_fds->active_fd);
0175     close(sk_fds->srv_fd);
0176 
0177 error:
0178     memset(sk_fds, -1, sizeof(*sk_fds));
0179     return -1;
0180 }
0181 
0182 static int check_hdr_opt(const struct bpf_test_option *exp,
0183              const struct bpf_test_option *act,
0184              const char *hdr_desc)
0185 {
0186     if (CHECK(memcmp(exp, act, sizeof(*exp)),
0187           "expected-vs-actual", "unexpected %s\n", hdr_desc)) {
0188         print_option(exp, "expected: ");
0189         print_option(act, "  actual: ");
0190         return -1;
0191     }
0192 
0193     return 0;
0194 }
0195 
0196 static int check_hdr_stg(const struct hdr_stg *exp, int fd,
0197              const char *stg_desc)
0198 {
0199     struct hdr_stg act;
0200 
0201     if (CHECK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act),
0202           "map_lookup(hdr_stg_map_fd)", "%s %s (%d)\n",
0203           stg_desc, strerror(errno), errno))
0204         return -1;
0205 
0206     if (CHECK(memcmp(exp, &act, sizeof(*exp)),
0207           "expected-vs-actual", "unexpected %s\n", stg_desc)) {
0208         print_hdr_stg(exp, "expected: ");
0209         print_hdr_stg(&act, "  actual: ");
0210         return -1;
0211     }
0212 
0213     return 0;
0214 }
0215 
0216 static int check_error_linum(const struct sk_fds *sk_fds)
0217 {
0218     unsigned int nr_errors = 0;
0219     struct linum_err linum_err;
0220     int lport;
0221 
0222     lport = sk_fds->passive_lport;
0223     if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
0224         fprintf(stderr,
0225             "bpf prog error out at lport:passive(%d), linum:%u err:%d\n",
0226             lport, linum_err.linum, linum_err.err);
0227         nr_errors++;
0228     }
0229 
0230     lport = sk_fds->active_lport;
0231     if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
0232         fprintf(stderr,
0233             "bpf prog error out at lport:active(%d), linum:%u err:%d\n",
0234             lport, linum_err.linum, linum_err.err);
0235         nr_errors++;
0236     }
0237 
0238     return nr_errors;
0239 }
0240 
0241 static void check_hdr_and_close_fds(struct sk_fds *sk_fds)
0242 {
0243     const __u32 expected_inherit_cb_flags =
0244         BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
0245         BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
0246         BPF_SOCK_OPS_STATE_CB_FLAG;
0247 
0248     if (sk_fds_shutdown(sk_fds))
0249         goto check_linum;
0250 
0251     if (CHECK(expected_inherit_cb_flags != skel->bss->inherit_cb_flags,
0252           "Unexpected inherit_cb_flags", "0x%x != 0x%x\n",
0253           skel->bss->inherit_cb_flags, expected_inherit_cb_flags))
0254         goto check_linum;
0255 
0256     if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,
0257               "passive_hdr_stg"))
0258         goto check_linum;
0259 
0260     if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd,
0261               "active_hdr_stg"))
0262         goto check_linum;
0263 
0264     if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in,
0265               "passive_estab_in"))
0266         goto check_linum;
0267 
0268     if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in,
0269               "active_estab_in"))
0270         goto check_linum;
0271 
0272     if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in,
0273               "passive_fin_in"))
0274         goto check_linum;
0275 
0276     check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in,
0277               "active_fin_in");
0278 
0279 check_linum:
0280     CHECK_FAIL(check_error_linum(sk_fds));
0281     sk_fds_close(sk_fds);
0282 }
0283 
0284 static void prepare_out(void)
0285 {
0286     skel->bss->active_syn_out = exp_passive_estab_in;
0287     skel->bss->passive_synack_out = exp_active_estab_in;
0288 
0289     skel->bss->active_fin_out = exp_passive_fin_in;
0290     skel->bss->passive_fin_out = exp_active_fin_in;
0291 }
0292 
0293 static void reset_test(void)
0294 {
0295     size_t optsize = sizeof(struct bpf_test_option);
0296     int lport, err;
0297 
0298     memset(&skel->bss->passive_synack_out, 0, optsize);
0299     memset(&skel->bss->passive_fin_out, 0, optsize);
0300 
0301     memset(&skel->bss->passive_estab_in, 0, optsize);
0302     memset(&skel->bss->passive_fin_in, 0, optsize);
0303 
0304     memset(&skel->bss->active_syn_out, 0, optsize);
0305     memset(&skel->bss->active_fin_out, 0, optsize);
0306 
0307     memset(&skel->bss->active_estab_in, 0, optsize);
0308     memset(&skel->bss->active_fin_in, 0, optsize);
0309 
0310     skel->bss->inherit_cb_flags = 0;
0311 
0312     skel->data->test_kind = TCPOPT_EXP;
0313     skel->data->test_magic = 0xeB9F;
0314 
0315     memset(&exp_passive_estab_in, 0, optsize);
0316     memset(&exp_active_estab_in, 0, optsize);
0317     memset(&exp_passive_fin_in, 0, optsize);
0318     memset(&exp_active_fin_in, 0, optsize);
0319 
0320     memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg));
0321     memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg));
0322     exp_active_hdr_stg.active = true;
0323 
0324     err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport);
0325     while (!err) {
0326         bpf_map_delete_elem(lport_linum_map_fd, &lport);
0327         err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport);
0328     }
0329 }
0330 
0331 static void fastopen_estab(void)
0332 {
0333     struct bpf_link *link;
0334     struct sk_fds sk_fds;
0335 
0336     hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
0337     lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
0338 
0339     exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
0340     exp_passive_estab_in.rand = 0xfa;
0341     exp_passive_estab_in.max_delack_ms = 11;
0342 
0343     exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
0344     exp_active_estab_in.rand = 0xce;
0345     exp_active_estab_in.max_delack_ms = 22;
0346 
0347     exp_passive_hdr_stg.fastopen = true;
0348 
0349     prepare_out();
0350 
0351     /* Allow fastopen without fastopen cookie */
0352     if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543"))
0353         return;
0354 
0355     link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
0356     if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
0357         return;
0358 
0359     if (sk_fds_connect(&sk_fds, true)) {
0360         bpf_link__destroy(link);
0361         return;
0362     }
0363 
0364     check_hdr_and_close_fds(&sk_fds);
0365     bpf_link__destroy(link);
0366 }
0367 
0368 static void syncookie_estab(void)
0369 {
0370     struct bpf_link *link;
0371     struct sk_fds sk_fds;
0372 
0373     hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
0374     lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
0375 
0376     exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
0377     exp_passive_estab_in.rand = 0xfa;
0378     exp_passive_estab_in.max_delack_ms = 11;
0379 
0380     exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS |
0381                     OPTION_F_RESEND;
0382     exp_active_estab_in.rand = 0xce;
0383     exp_active_estab_in.max_delack_ms = 22;
0384 
0385     exp_passive_hdr_stg.syncookie = true;
0386     exp_active_hdr_stg.resend_syn = true,
0387 
0388     prepare_out();
0389 
0390     /* Clear the RESEND to ensure the bpf prog can learn
0391      * want_cookie and set the RESEND by itself.
0392      */
0393     skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND;
0394 
0395     /* Enforce syncookie mode */
0396     if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
0397         return;
0398 
0399     link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
0400     if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
0401         return;
0402 
0403     if (sk_fds_connect(&sk_fds, false)) {
0404         bpf_link__destroy(link);
0405         return;
0406     }
0407 
0408     check_hdr_and_close_fds(&sk_fds);
0409     bpf_link__destroy(link);
0410 }
0411 
0412 static void fin(void)
0413 {
0414     struct bpf_link *link;
0415     struct sk_fds sk_fds;
0416 
0417     hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
0418     lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
0419 
0420     exp_passive_fin_in.flags = OPTION_F_RAND;
0421     exp_passive_fin_in.rand = 0xfa;
0422 
0423     exp_active_fin_in.flags = OPTION_F_RAND;
0424     exp_active_fin_in.rand = 0xce;
0425 
0426     prepare_out();
0427 
0428     if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
0429         return;
0430 
0431     link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
0432     if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
0433         return;
0434 
0435     if (sk_fds_connect(&sk_fds, false)) {
0436         bpf_link__destroy(link);
0437         return;
0438     }
0439 
0440     check_hdr_and_close_fds(&sk_fds);
0441     bpf_link__destroy(link);
0442 }
0443 
0444 static void __simple_estab(bool exprm)
0445 {
0446     struct bpf_link *link;
0447     struct sk_fds sk_fds;
0448 
0449     hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
0450     lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
0451 
0452     exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
0453     exp_passive_estab_in.rand = 0xfa;
0454     exp_passive_estab_in.max_delack_ms = 11;
0455 
0456     exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
0457     exp_active_estab_in.rand = 0xce;
0458     exp_active_estab_in.max_delack_ms = 22;
0459 
0460     prepare_out();
0461 
0462     if (!exprm) {
0463         skel->data->test_kind = 0xB9;
0464         skel->data->test_magic = 0;
0465     }
0466 
0467     if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
0468         return;
0469 
0470     link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
0471     if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
0472         return;
0473 
0474     if (sk_fds_connect(&sk_fds, false)) {
0475         bpf_link__destroy(link);
0476         return;
0477     }
0478 
0479     check_hdr_and_close_fds(&sk_fds);
0480     bpf_link__destroy(link);
0481 }
0482 
0483 static void no_exprm_estab(void)
0484 {
0485     __simple_estab(false);
0486 }
0487 
0488 static void simple_estab(void)
0489 {
0490     __simple_estab(true);
0491 }
0492 
0493 static void misc(void)
0494 {
0495     const char send_msg[] = "MISC!!!";
0496     char recv_msg[sizeof(send_msg)];
0497     const unsigned int nr_data = 2;
0498     struct bpf_link *link;
0499     struct sk_fds sk_fds;
0500     int i, ret;
0501 
0502     lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map);
0503 
0504     if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
0505         return;
0506 
0507     link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd);
0508     if (!ASSERT_OK_PTR(link, "attach_cgroup(misc_estab)"))
0509         return;
0510 
0511     if (sk_fds_connect(&sk_fds, false)) {
0512         bpf_link__destroy(link);
0513         return;
0514     }
0515 
0516     for (i = 0; i < nr_data; i++) {
0517         /* MSG_EOR to ensure skb will not be combined */
0518         ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg),
0519                MSG_EOR);
0520         if (CHECK(ret != sizeof(send_msg), "send(msg)", "ret:%d\n",
0521               ret))
0522             goto check_linum;
0523 
0524         ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg));
0525         if (CHECK(ret != sizeof(send_msg), "read(msg)", "ret:%d\n",
0526               ret))
0527             goto check_linum;
0528     }
0529 
0530     if (sk_fds_shutdown(&sk_fds))
0531         goto check_linum;
0532 
0533     CHECK(misc_skel->bss->nr_syn != 1, "unexpected nr_syn",
0534           "expected (1) != actual (%u)\n",
0535         misc_skel->bss->nr_syn);
0536 
0537     CHECK(misc_skel->bss->nr_data != nr_data, "unexpected nr_data",
0538           "expected (%u) != actual (%u)\n",
0539           nr_data, misc_skel->bss->nr_data);
0540 
0541     /* The last ACK may have been delayed, so it is either 1 or 2. */
0542     CHECK(misc_skel->bss->nr_pure_ack != 1 &&
0543           misc_skel->bss->nr_pure_ack != 2,
0544           "unexpected nr_pure_ack",
0545           "expected (1 or 2) != actual (%u)\n",
0546         misc_skel->bss->nr_pure_ack);
0547 
0548     CHECK(misc_skel->bss->nr_fin != 1, "unexpected nr_fin",
0549           "expected (1) != actual (%u)\n",
0550           misc_skel->bss->nr_fin);
0551 
0552 check_linum:
0553     CHECK_FAIL(check_error_linum(&sk_fds));
0554     sk_fds_close(&sk_fds);
0555     bpf_link__destroy(link);
0556 }
0557 
0558 struct test {
0559     const char *desc;
0560     void (*run)(void);
0561 };
0562 
0563 #define DEF_TEST(name) { #name, name }
0564 static struct test tests[] = {
0565     DEF_TEST(simple_estab),
0566     DEF_TEST(no_exprm_estab),
0567     DEF_TEST(syncookie_estab),
0568     DEF_TEST(fastopen_estab),
0569     DEF_TEST(fin),
0570     DEF_TEST(misc),
0571 };
0572 
0573 void test_tcp_hdr_options(void)
0574 {
0575     int i;
0576 
0577     skel = test_tcp_hdr_options__open_and_load();
0578     if (CHECK(!skel, "open and load skel", "failed"))
0579         return;
0580 
0581     misc_skel = test_misc_tcp_hdr_options__open_and_load();
0582     if (CHECK(!misc_skel, "open and load misc test skel", "failed"))
0583         goto skel_destroy;
0584 
0585     cg_fd = test__join_cgroup(CG_NAME);
0586     if (CHECK_FAIL(cg_fd < 0))
0587         goto skel_destroy;
0588 
0589     for (i = 0; i < ARRAY_SIZE(tests); i++) {
0590         if (!test__start_subtest(tests[i].desc))
0591             continue;
0592 
0593         if (create_netns())
0594             break;
0595 
0596         tests[i].run();
0597 
0598         reset_test();
0599     }
0600 
0601     close(cg_fd);
0602 skel_destroy:
0603     test_misc_tcp_hdr_options__destroy(misc_skel);
0604     test_tcp_hdr_options__destroy(skel);
0605 }