1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include <network_helpers.h> 4 5 static void test_xdp_adjust_tail_shrink(void) 6 { 7 const char *file = "./test_xdp_adjust_tail_shrink.o"; 8 __u32 duration, retval, size, expect_sz; 9 struct bpf_object *obj; 10 int err, prog_fd; 11 char buf[128]; 12 13 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); 14 if (ASSERT_OK(err, "test_xdp_adjust_tail_shrink")) 15 return; 16 17 err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), 18 buf, &size, &retval, &duration); 19 ASSERT_OK(err, "ipv4"); 20 ASSERT_EQ(retval, XDP_DROP, "ipv4 retval"); 21 22 expect_sz = sizeof(pkt_v6) - 20; /* Test shrink with 20 bytes */ 23 err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), 24 buf, &size, &retval, &duration); 25 ASSERT_OK(err, "ipv6"); 26 ASSERT_EQ(retval, XDP_TX, "ipv6 retval"); 27 ASSERT_EQ(size, expect_sz, "ipv6 size"); 28 29 bpf_object__close(obj); 30 } 31 32 static void test_xdp_adjust_tail_grow(void) 33 { 34 const char *file = "./test_xdp_adjust_tail_grow.o"; 35 struct bpf_object *obj; 36 char buf[4096]; /* avoid segfault: large buf to hold grow results */ 37 __u32 duration, retval, size, expect_sz; 38 int err, prog_fd; 39 40 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); 41 if (ASSERT_OK(err, "test_xdp_adjust_tail_grow")) 42 return; 43 44 err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), 45 buf, &size, &retval, &duration); 46 ASSERT_OK(err, "ipv4"); 47 ASSERT_EQ(retval, XDP_DROP, "ipv4 retval"); 48 49 expect_sz = sizeof(pkt_v6) + 40; /* Test grow with 40 bytes */ 50 err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6) /* 74 */, 51 buf, &size, &retval, &duration); 52 ASSERT_OK(err, "ipv6"); 53 ASSERT_EQ(retval, XDP_TX, "ipv6 retval"); 54 ASSERT_EQ(size, expect_sz, "ipv6 size"); 55 56 bpf_object__close(obj); 57 } 58 59 static void test_xdp_adjust_tail_grow2(void) 60 { 61 const char *file = "./test_xdp_adjust_tail_grow.o"; 62 char buf[4096]; /* avoid segfault: large buf to hold grow results */ 63 int tailroom = 320; /* SKB_DATA_ALIGN(sizeof(struct skb_shared_info))*/; 64 struct bpf_object *obj; 65 int err, cnt, i; 66 int max_grow; 67 68 struct bpf_prog_test_run_attr tattr = { 69 .repeat = 1, 70 .data_in = &buf, 71 .data_out = &buf, 72 .data_size_in = 0, /* Per test */ 73 .data_size_out = 0, /* Per test */ 74 }; 75 76 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &tattr.prog_fd); 77 if (ASSERT_OK(err, "test_xdp_adjust_tail_grow")) 78 return; 79 80 /* Test case-64 */ 81 memset(buf, 1, sizeof(buf)); 82 tattr.data_size_in = 64; /* Determine test case via pkt size */ 83 tattr.data_size_out = 128; /* Limit copy_size */ 84 /* Kernel side alloc packet memory area that is zero init */ 85 err = bpf_prog_test_run_xattr(&tattr); 86 87 ASSERT_EQ(errno, ENOSPC, "case-64 errno"); /* Due limit copy_size in bpf_test_finish */ 88 ASSERT_EQ(tattr.retval, XDP_TX, "case-64 retval"); 89 ASSERT_EQ(tattr.data_size_out, 192, "case-64 data_size_out"); /* Expected grow size */ 90 91 /* Extra checks for data contents */ 92 ASSERT_EQ(buf[0], 1, "case-64-data buf[0]"); /* 0-63 memset to 1 */ 93 ASSERT_EQ(buf[63], 1, "case-64-data buf[63]"); 94 ASSERT_EQ(buf[64], 0, "case-64-data buf[64]"); /* 64-127 memset to 0 */ 95 ASSERT_EQ(buf[127], 0, "case-64-data buf[127]"); 96 ASSERT_EQ(buf[128], 1, "case-64-data buf[128]"); /* 128-191 memset to 1 */ 97 ASSERT_EQ(buf[191], 1, "case-64-data buf[191]"); 98 99 /* Test case-128 */ 100 memset(buf, 2, sizeof(buf)); 101 tattr.data_size_in = 128; /* Determine test case via pkt size */ 102 tattr.data_size_out = sizeof(buf); /* Copy everything */ 103 err = bpf_prog_test_run_xattr(&tattr); 104 105 max_grow = 4096 - XDP_PACKET_HEADROOM - tailroom; /* 3520 */ 106 ASSERT_OK(err, "case-128"); 107 ASSERT_EQ(tattr.retval, XDP_TX, "case-128 retval"); 108 ASSERT_EQ(tattr.data_size_out, max_grow, "case-128 data_size_out"); /* Expect max grow */ 109 110 /* Extra checks for data content: Count grow size, will contain zeros */ 111 for (i = 0, cnt = 0; i < sizeof(buf); i++) { 112 if (buf[i] == 0) 113 cnt++; 114 } 115 ASSERT_EQ(cnt, max_grow - tattr.data_size_in, "case-128-data cnt"); /* Grow increase */ 116 ASSERT_EQ(tattr.data_size_out, max_grow, "case-128-data data_size_out"); /* Total grow */ 117 118 bpf_object__close(obj); 119 } 120 121 void test_xdp_adjust_frags_tail_shrink(void) 122 { 123 const char *file = "./test_xdp_adjust_tail_shrink.o"; 124 __u32 duration, retval, size, exp_size; 125 struct bpf_program *prog; 126 struct bpf_object *obj; 127 int err, prog_fd; 128 __u8 *buf; 129 130 /* For the individual test cases, the first byte in the packet 131 * indicates which test will be run. 132 */ 133 obj = bpf_object__open(file); 134 if (libbpf_get_error(obj)) 135 return; 136 137 prog = bpf_object__next_program(obj, NULL); 138 if (bpf_object__load(obj)) 139 return; 140 141 prog_fd = bpf_program__fd(prog); 142 143 buf = malloc(9000); 144 if (!ASSERT_OK_PTR(buf, "alloc buf 9Kb")) 145 goto out; 146 147 memset(buf, 0, 9000); 148 149 /* Test case removing 10 bytes from last frag, NOT freeing it */ 150 exp_size = 8990; /* 9000 - 10 */ 151 err = bpf_prog_test_run(prog_fd, 1, buf, 9000, 152 buf, &size, &retval, &duration); 153 154 ASSERT_OK(err, "9Kb-10b"); 155 ASSERT_EQ(retval, XDP_TX, "9Kb-10b retval"); 156 ASSERT_EQ(size, exp_size, "9Kb-10b size"); 157 158 /* Test case removing one of two pages, assuming 4K pages */ 159 buf[0] = 1; 160 exp_size = 4900; /* 9000 - 4100 */ 161 err = bpf_prog_test_run(prog_fd, 1, buf, 9000, 162 buf, &size, &retval, &duration); 163 164 ASSERT_OK(err, "9Kb-4Kb"); 165 ASSERT_EQ(retval, XDP_TX, "9Kb-4Kb retval"); 166 ASSERT_EQ(size, exp_size, "9Kb-4Kb size"); 167 168 /* Test case removing two pages resulting in a linear xdp_buff */ 169 buf[0] = 2; 170 exp_size = 800; /* 9000 - 8200 */ 171 err = bpf_prog_test_run(prog_fd, 1, buf, 9000, 172 buf, &size, &retval, &duration); 173 174 ASSERT_OK(err, "9Kb-9Kb"); 175 ASSERT_EQ(retval, XDP_TX, "9Kb-9Kb retval"); 176 ASSERT_EQ(size, exp_size, "9Kb-9Kb size"); 177 178 free(buf); 179 out: 180 bpf_object__close(obj); 181 } 182 183 void test_xdp_adjust_frags_tail_grow(void) 184 { 185 const char *file = "./test_xdp_adjust_tail_grow.o"; 186 __u32 duration, retval, size, exp_size; 187 struct bpf_program *prog; 188 struct bpf_object *obj; 189 int err, i, prog_fd; 190 __u8 *buf; 191 192 obj = bpf_object__open(file); 193 if (libbpf_get_error(obj)) 194 return; 195 196 prog = bpf_object__next_program(obj, NULL); 197 if (bpf_object__load(obj)) 198 return; 199 200 prog_fd = bpf_program__fd(prog); 201 202 buf = malloc(16384); 203 if (!ASSERT_OK_PTR(buf, "alloc buf 16Kb")) 204 goto out; 205 206 /* Test case add 10 bytes to last frag */ 207 memset(buf, 1, 16384); 208 size = 9000; 209 exp_size = size + 10; 210 err = bpf_prog_test_run(prog_fd, 1, buf, size, 211 buf, &size, &retval, &duration); 212 213 ASSERT_OK(err, "9Kb+10b"); 214 ASSERT_EQ(retval, XDP_TX, "9Kb+10b retval"); 215 ASSERT_EQ(size, exp_size, "9Kb+10b size"); 216 217 for (i = 0; i < 9000; i++) 218 ASSERT_EQ(buf[i], 1, "9Kb+10b-old"); 219 220 for (i = 9000; i < 9010; i++) 221 ASSERT_EQ(buf[i], 0, "9Kb+10b-new"); 222 223 for (i = 9010; i < 16384; i++) 224 ASSERT_EQ(buf[i], 1, "9Kb+10b-untouched"); 225 226 /* Test a too large grow */ 227 memset(buf, 1, 16384); 228 size = 9001; 229 exp_size = size; 230 err = bpf_prog_test_run(prog_fd, 1, buf, size, 231 buf, &size, &retval, &duration); 232 233 ASSERT_OK(err, "9Kb+10b"); 234 ASSERT_EQ(retval, XDP_DROP, "9Kb+10b retval"); 235 ASSERT_EQ(size, exp_size, "9Kb+10b size"); 236 237 free(buf); 238 out: 239 bpf_object__close(obj); 240 } 241 242 void test_xdp_adjust_tail(void) 243 { 244 if (test__start_subtest("xdp_adjust_tail_shrink")) 245 test_xdp_adjust_tail_shrink(); 246 if (test__start_subtest("xdp_adjust_tail_grow")) 247 test_xdp_adjust_tail_grow(); 248 if (test__start_subtest("xdp_adjust_tail_grow2")) 249 test_xdp_adjust_tail_grow2(); 250 if (test__start_subtest("xdp_adjust_frags_tail_shrink")) 251 test_xdp_adjust_frags_tail_shrink(); 252 if (test__start_subtest("xdp_adjust_frags_tail_grow")) 253 test_xdp_adjust_frags_tail_grow(); 254 } 255