| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright (c) 2020 Jesper Dangaard Brouer */ |
| 3 | |
| 4 | #include <linux/if_link.h> /* before test_progs.h, avoid bpf_util.h redefines */ |
| 5 | #include <test_progs.h> |
| 6 | #include "test_check_mtu.skel.h" |
| 7 | #include "network_helpers.h" |
| 8 | |
| 9 | #include <stdlib.h> |
| 10 | #include <inttypes.h> |
| 11 | |
| 12 | #define IFINDEX_LO 1 |
| 13 | |
| 14 | static __u32 duration; /* Hint: needed for CHECK macro */ |
| 15 | |
| 16 | static int read_mtu_device_lo(void) |
| 17 | { |
| 18 | const char *filename = "/sys/class/net/lo/mtu" ; |
| 19 | char buf[11] = {}; |
| 20 | int value, n, fd; |
| 21 | |
| 22 | fd = open(filename, 0, O_RDONLY); |
| 23 | if (fd == -1) |
| 24 | return -1; |
| 25 | |
| 26 | n = read(fd, buf, sizeof(buf)); |
| 27 | close(fd); |
| 28 | |
| 29 | if (n == -1) |
| 30 | return -2; |
| 31 | |
| 32 | value = strtoimax(buf, NULL, 10); |
| 33 | if (errno == ERANGE) |
| 34 | return -3; |
| 35 | |
| 36 | return value; |
| 37 | } |
| 38 | |
| 39 | static void test_check_mtu_xdp_attach(void) |
| 40 | { |
| 41 | struct bpf_link_info link_info; |
| 42 | __u32 link_info_len = sizeof(link_info); |
| 43 | struct test_check_mtu *skel; |
| 44 | struct bpf_program *prog; |
| 45 | struct bpf_link *link; |
| 46 | int err = 0; |
| 47 | int fd; |
| 48 | |
| 49 | skel = test_check_mtu__open_and_load(); |
| 50 | if (CHECK(!skel, "open and load skel" , "failed" )) |
| 51 | return; /* Exit if e.g. helper unknown to kernel */ |
| 52 | |
| 53 | prog = skel->progs.xdp_use_helper_basic; |
| 54 | |
| 55 | link = bpf_program__attach_xdp(prog, IFINDEX_LO); |
| 56 | if (!ASSERT_OK_PTR(link, "link_attach" )) |
| 57 | goto out; |
| 58 | skel->links.xdp_use_helper_basic = link; |
| 59 | |
| 60 | memset(&link_info, 0, sizeof(link_info)); |
| 61 | fd = bpf_link__fd(link); |
| 62 | err = bpf_link_get_info_by_fd(fd, &link_info, &link_info_len); |
| 63 | if (CHECK(err, "link_info" , "failed: %d\n" , err)) |
| 64 | goto out; |
| 65 | |
| 66 | CHECK(link_info.type != BPF_LINK_TYPE_XDP, "link_type" , |
| 67 | "got %u != exp %u\n" , link_info.type, BPF_LINK_TYPE_XDP); |
| 68 | CHECK(link_info.xdp.ifindex != IFINDEX_LO, "link_ifindex" , |
| 69 | "got %u != exp %u\n" , link_info.xdp.ifindex, IFINDEX_LO); |
| 70 | |
| 71 | err = bpf_link__detach(link); |
| 72 | CHECK(err, "link_detach" , "failed %d\n" , err); |
| 73 | |
| 74 | out: |
| 75 | test_check_mtu__destroy(skel); |
| 76 | } |
| 77 | |
| 78 | static void test_check_mtu_run_xdp(struct test_check_mtu *skel, |
| 79 | struct bpf_program *prog, |
| 80 | __u32 mtu_expect) |
| 81 | { |
| 82 | int retval_expect = XDP_PASS; |
| 83 | __u32 mtu_result = 0; |
| 84 | char buf[256] = {}; |
| 85 | int err, prog_fd = bpf_program__fd(prog); |
| 86 | LIBBPF_OPTS(bpf_test_run_opts, topts, |
| 87 | .repeat = 1, |
| 88 | .data_in = &pkt_v4, |
| 89 | .data_size_in = sizeof(pkt_v4), |
| 90 | .data_out = buf, |
| 91 | .data_size_out = sizeof(buf), |
| 92 | ); |
| 93 | |
| 94 | err = bpf_prog_test_run_opts(prog_fd, &topts); |
| 95 | ASSERT_OK(err, "test_run" ); |
| 96 | ASSERT_EQ(topts.retval, retval_expect, "retval" ); |
| 97 | |
| 98 | /* Extract MTU that BPF-prog got */ |
| 99 | mtu_result = skel->bss->global_bpf_mtu_xdp; |
| 100 | ASSERT_EQ(mtu_result, mtu_expect, "MTU-compare-user" ); |
| 101 | } |
| 102 | |
| 103 | |
| 104 | static void test_check_mtu_xdp(__u32 mtu, __u32 ifindex) |
| 105 | { |
| 106 | struct test_check_mtu *skel; |
| 107 | int err; |
| 108 | |
| 109 | skel = test_check_mtu__open(); |
| 110 | if (CHECK(!skel, "skel_open" , "failed" )) |
| 111 | return; |
| 112 | |
| 113 | /* Update "constants" in BPF-prog *BEFORE* libbpf load */ |
| 114 | skel->rodata->GLOBAL_USER_MTU = mtu; |
| 115 | skel->rodata->GLOBAL_USER_IFINDEX = ifindex; |
| 116 | |
| 117 | err = test_check_mtu__load(skel); |
| 118 | if (CHECK(err, "skel_load" , "failed: %d\n" , err)) |
| 119 | goto cleanup; |
| 120 | |
| 121 | test_check_mtu_run_xdp(skel, prog: skel->progs.xdp_use_helper, mtu_expect: mtu); |
| 122 | test_check_mtu_run_xdp(skel, prog: skel->progs.xdp_exceed_mtu, mtu_expect: mtu); |
| 123 | test_check_mtu_run_xdp(skel, prog: skel->progs.xdp_minus_delta, mtu_expect: mtu); |
| 124 | test_check_mtu_run_xdp(skel, prog: skel->progs.xdp_input_len, mtu_expect: mtu); |
| 125 | test_check_mtu_run_xdp(skel, prog: skel->progs.xdp_input_len_exceed, mtu_expect: mtu); |
| 126 | |
| 127 | cleanup: |
| 128 | test_check_mtu__destroy(skel); |
| 129 | } |
| 130 | |
| 131 | static void test_check_mtu_run_tc(struct test_check_mtu *skel, |
| 132 | struct bpf_program *prog, |
| 133 | __u32 mtu_expect) |
| 134 | { |
| 135 | int retval_expect = BPF_OK; |
| 136 | __u32 mtu_result = 0; |
| 137 | char buf[256] = {}; |
| 138 | int err, prog_fd = bpf_program__fd(prog); |
| 139 | LIBBPF_OPTS(bpf_test_run_opts, topts, |
| 140 | .data_in = &pkt_v4, |
| 141 | .data_size_in = sizeof(pkt_v4), |
| 142 | .data_out = buf, |
| 143 | .data_size_out = sizeof(buf), |
| 144 | .repeat = 1, |
| 145 | ); |
| 146 | |
| 147 | err = bpf_prog_test_run_opts(prog_fd, &topts); |
| 148 | ASSERT_OK(err, "test_run" ); |
| 149 | ASSERT_EQ(topts.retval, retval_expect, "retval" ); |
| 150 | |
| 151 | /* Extract MTU that BPF-prog got */ |
| 152 | mtu_result = skel->bss->global_bpf_mtu_tc; |
| 153 | ASSERT_EQ(mtu_result, mtu_expect, "MTU-compare-user" ); |
| 154 | } |
| 155 | |
| 156 | static void test_chk_segs_flag(struct test_check_mtu *skel, __u32 mtu) |
| 157 | { |
| 158 | int err, prog_fd = bpf_program__fd(skel->progs.tc_chk_segs_flag); |
| 159 | struct __sk_buff skb = { |
| 160 | .gso_size = 10, |
| 161 | }; |
| 162 | LIBBPF_OPTS(bpf_test_run_opts, topts, |
| 163 | .data_in = &pkt_v4, |
| 164 | .data_size_in = sizeof(pkt_v4), |
| 165 | .ctx_in = &skb, |
| 166 | .ctx_size_in = sizeof(skb), |
| 167 | ); |
| 168 | |
| 169 | /* Lower the mtu to test the BPF_MTU_CHK_SEGS */ |
| 170 | SYS_NOFAIL("ip link set dev lo mtu 10" ); |
| 171 | err = bpf_prog_test_run_opts(prog_fd, &topts); |
| 172 | SYS_NOFAIL("ip link set dev lo mtu %u" , mtu); |
| 173 | ASSERT_OK(err, "test_run" ); |
| 174 | ASSERT_EQ(topts.retval, BPF_OK, "retval" ); |
| 175 | } |
| 176 | |
| 177 | static void test_check_mtu_tc(__u32 mtu, __u32 ifindex) |
| 178 | { |
| 179 | struct test_check_mtu *skel; |
| 180 | int err; |
| 181 | |
| 182 | skel = test_check_mtu__open(); |
| 183 | if (CHECK(!skel, "skel_open" , "failed" )) |
| 184 | return; |
| 185 | |
| 186 | /* Update "constants" in BPF-prog *BEFORE* libbpf load */ |
| 187 | skel->rodata->GLOBAL_USER_MTU = mtu; |
| 188 | skel->rodata->GLOBAL_USER_IFINDEX = ifindex; |
| 189 | |
| 190 | err = test_check_mtu__load(skel); |
| 191 | if (CHECK(err, "skel_load" , "failed: %d\n" , err)) |
| 192 | goto cleanup; |
| 193 | |
| 194 | test_check_mtu_run_tc(skel, prog: skel->progs.tc_use_helper, mtu_expect: mtu); |
| 195 | test_check_mtu_run_tc(skel, prog: skel->progs.tc_exceed_mtu, mtu_expect: mtu); |
| 196 | test_check_mtu_run_tc(skel, prog: skel->progs.tc_exceed_mtu_da, mtu_expect: mtu); |
| 197 | test_check_mtu_run_tc(skel, prog: skel->progs.tc_minus_delta, mtu_expect: mtu); |
| 198 | test_check_mtu_run_tc(skel, prog: skel->progs.tc_input_len, mtu_expect: mtu); |
| 199 | test_check_mtu_run_tc(skel, prog: skel->progs.tc_input_len_exceed, mtu_expect: mtu); |
| 200 | test_chk_segs_flag(skel, mtu); |
| 201 | cleanup: |
| 202 | test_check_mtu__destroy(skel); |
| 203 | } |
| 204 | |
| 205 | void test_ns_check_mtu(void) |
| 206 | { |
| 207 | int mtu_lo; |
| 208 | |
| 209 | if (test__start_subtest("bpf_check_mtu XDP-attach" )) |
| 210 | test_check_mtu_xdp_attach(); |
| 211 | |
| 212 | mtu_lo = read_mtu_device_lo(); |
| 213 | if (CHECK(mtu_lo < 0, "reading MTU value" , "failed (err:%d)" , mtu_lo)) |
| 214 | return; |
| 215 | |
| 216 | if (test__start_subtest("bpf_check_mtu XDP-run" )) |
| 217 | test_check_mtu_xdp(mtu: mtu_lo, ifindex: 0); |
| 218 | |
| 219 | if (test__start_subtest("bpf_check_mtu XDP-run ifindex-lookup" )) |
| 220 | test_check_mtu_xdp(mtu: mtu_lo, IFINDEX_LO); |
| 221 | |
| 222 | if (test__start_subtest("bpf_check_mtu TC-run" )) |
| 223 | test_check_mtu_tc(mtu: mtu_lo, ifindex: 0); |
| 224 | |
| 225 | if (test__start_subtest("bpf_check_mtu TC-run ifindex-lookup" )) |
| 226 | test_check_mtu_tc(mtu: mtu_lo, IFINDEX_LO); |
| 227 | } |
| 228 | |