1 1.4 alnsn /* $NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $ */ 2 1.1 alnsn 3 1.1 alnsn /*- 4 1.2 alnsn * Copyright (c) 2013-2014 Alexander Nasonov. 5 1.1 alnsn * All rights reserved. 6 1.1 alnsn * 7 1.1 alnsn * Redistribution and use in source and binary forms, with or without 8 1.1 alnsn * modification, are permitted provided that the following conditions 9 1.1 alnsn * are met: 10 1.1 alnsn * 11 1.1 alnsn * 1. Redistributions of source code must retain the above copyright 12 1.1 alnsn * notice, this list of conditions and the following disclaimer. 13 1.1 alnsn * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 alnsn * notice, this list of conditions and the following disclaimer in 15 1.1 alnsn * the documentation and/or other materials provided with the 16 1.1 alnsn * distribution. 17 1.1 alnsn * 18 1.1 alnsn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 1.1 alnsn * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 1.1 alnsn * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 1.1 alnsn * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 1.1 alnsn * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 alnsn * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 1.1 alnsn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 1.1 alnsn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 1.1 alnsn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 1.1 alnsn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 1.1 alnsn * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 alnsn * SUCH DAMAGE. 30 1.1 alnsn */ 31 1.1 alnsn 32 1.1 alnsn #include <sys/cdefs.h> 33 1.4 alnsn __RCSID("$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $"); 34 1.1 alnsn 35 1.1 alnsn #include <atf-c.h> 36 1.1 alnsn #include <stdint.h> 37 1.1 alnsn #include <string.h> 38 1.1 alnsn 39 1.1 alnsn #define __BPF_PRIVATE 40 1.1 alnsn #include <net/bpf.h> 41 1.1 alnsn #include <net/bpfjit.h> 42 1.1 alnsn 43 1.1 alnsn static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 44 1.1 alnsn static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 45 1.1 alnsn static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 46 1.1 alnsn static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 47 1.1 alnsn static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 48 1.1 alnsn 49 1.1 alnsn static const bpf_copfunc_t copfuncs[] = { 50 1.1 alnsn &retA, 51 1.1 alnsn &retBL, 52 1.1 alnsn &retWL, 53 1.1 alnsn &retNF, 54 1.1 alnsn &setARG 55 1.1 alnsn }; 56 1.1 alnsn 57 1.1 alnsn static const bpf_ctx_t ctx = { 58 1.1 alnsn .copfuncs = copfuncs, 59 1.1 alnsn .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]), 60 1.1 alnsn .extwords = 0 61 1.1 alnsn }; 62 1.1 alnsn 63 1.1 alnsn static uint32_t 64 1.1 alnsn retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 65 1.1 alnsn { 66 1.1 alnsn 67 1.1 alnsn return A; 68 1.1 alnsn } 69 1.1 alnsn 70 1.1 alnsn static uint32_t 71 1.1 alnsn retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 72 1.1 alnsn { 73 1.1 alnsn 74 1.1 alnsn return args->buflen; 75 1.1 alnsn } 76 1.1 alnsn 77 1.1 alnsn static uint32_t 78 1.1 alnsn retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 79 1.1 alnsn { 80 1.1 alnsn 81 1.1 alnsn return args->wirelen; 82 1.1 alnsn } 83 1.1 alnsn 84 1.1 alnsn static uint32_t 85 1.1 alnsn retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 86 1.1 alnsn { 87 1.1 alnsn 88 1.1 alnsn return bc->nfuncs; 89 1.1 alnsn } 90 1.1 alnsn 91 1.1 alnsn /* 92 1.1 alnsn * COP function with a side effect. 93 1.1 alnsn */ 94 1.1 alnsn static uint32_t 95 1.1 alnsn setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 96 1.1 alnsn { 97 1.1 alnsn bool *arg = (bool *)args->arg; 98 1.1 alnsn bool old = *arg; 99 1.1 alnsn 100 1.1 alnsn *arg = true; 101 1.1 alnsn return old; 102 1.1 alnsn } 103 1.1 alnsn 104 1.3 alnsn ATF_TC(libbpfjit_cop_no_ctx); 105 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_no_ctx, tc) 106 1.1 alnsn { 107 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP " 108 1.1 alnsn "instruction isn't valid without a context"); 109 1.1 alnsn } 110 1.1 alnsn 111 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_no_ctx, tc) 112 1.1 alnsn { 113 1.1 alnsn static struct bpf_insn insns[] = { 114 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), 115 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 7) 116 1.1 alnsn }; 117 1.1 alnsn 118 1.1 alnsn bpfjit_func_t code; 119 1.1 alnsn 120 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 121 1.1 alnsn 122 1.1 alnsn ATF_CHECK(!bpf_validate(insns, insn_count)); 123 1.1 alnsn 124 1.1 alnsn code = bpfjit_generate_code(NULL, insns, insn_count); 125 1.1 alnsn ATF_CHECK(code == NULL); 126 1.1 alnsn } 127 1.1 alnsn 128 1.3 alnsn ATF_TC(libbpfjit_cop_ret_A); 129 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_ret_A, tc) 130 1.1 alnsn { 131 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 132 1.1 alnsn "that returns a content of the A register"); 133 1.1 alnsn } 134 1.1 alnsn 135 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_ret_A, tc) 136 1.1 alnsn { 137 1.1 alnsn static struct bpf_insn insns[] = { 138 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 139 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), // retA 140 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 141 1.1 alnsn }; 142 1.1 alnsn 143 1.1 alnsn bpfjit_func_t code; 144 1.1 alnsn uint8_t pkt[1] = { 0 }; 145 1.1 alnsn bpf_args_t args = { 146 1.1 alnsn .pkt = pkt, 147 1.1 alnsn .buflen = sizeof(pkt), 148 1.1 alnsn .wirelen = sizeof(pkt), 149 1.1 alnsn }; 150 1.1 alnsn 151 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 152 1.1 alnsn 153 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 154 1.1 alnsn ATF_REQUIRE(code != NULL); 155 1.1 alnsn 156 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 13); 157 1.1 alnsn 158 1.1 alnsn bpfjit_free_code(code); 159 1.1 alnsn } 160 1.1 alnsn 161 1.3 alnsn ATF_TC(libbpfjit_cop_ret_buflen); 162 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_ret_buflen, tc) 163 1.1 alnsn { 164 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 165 1.1 alnsn "that returns the buflen argument"); 166 1.1 alnsn } 167 1.1 alnsn 168 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_ret_buflen, tc) 169 1.1 alnsn { 170 1.1 alnsn static struct bpf_insn insns[] = { 171 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 172 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL 173 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 174 1.1 alnsn }; 175 1.1 alnsn 176 1.1 alnsn bpfjit_func_t code; 177 1.1 alnsn uint8_t pkt[1] = { 0 }; 178 1.1 alnsn bpf_args_t args = { 179 1.1 alnsn .pkt = pkt, 180 1.1 alnsn .buflen = sizeof(pkt), 181 1.1 alnsn .wirelen = sizeof(pkt) 182 1.1 alnsn }; 183 1.1 alnsn 184 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 185 1.1 alnsn 186 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 187 1.1 alnsn ATF_REQUIRE(code != NULL); 188 1.1 alnsn 189 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 190 1.1 alnsn 191 1.1 alnsn bpfjit_free_code(code); 192 1.1 alnsn } 193 1.1 alnsn 194 1.3 alnsn ATF_TC(libbpfjit_cop_ret_wirelen); 195 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_ret_wirelen, tc) 196 1.1 alnsn { 197 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 198 1.1 alnsn "that returns the wirelen argument"); 199 1.1 alnsn } 200 1.1 alnsn 201 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_ret_wirelen, tc) 202 1.1 alnsn { 203 1.1 alnsn static struct bpf_insn insns[] = { 204 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 205 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL 206 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 207 1.1 alnsn }; 208 1.1 alnsn 209 1.1 alnsn bpfjit_func_t code; 210 1.1 alnsn uint8_t pkt[1] = { 0 }; 211 1.1 alnsn bpf_args_t args = { 212 1.1 alnsn .pkt = pkt, 213 1.1 alnsn .buflen = sizeof(pkt), 214 1.1 alnsn .wirelen = sizeof(pkt) 215 1.1 alnsn }; 216 1.1 alnsn 217 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 218 1.1 alnsn 219 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 220 1.1 alnsn ATF_REQUIRE(code != NULL); 221 1.1 alnsn 222 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 223 1.1 alnsn 224 1.1 alnsn bpfjit_free_code(code); 225 1.1 alnsn } 226 1.1 alnsn 227 1.3 alnsn ATF_TC(libbpfjit_cop_ret_nfuncs); 228 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs, tc) 229 1.1 alnsn { 230 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 231 1.1 alnsn "that returns nfuncs member of the context argument"); 232 1.1 alnsn } 233 1.1 alnsn 234 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_ret_nfuncs, tc) 235 1.1 alnsn { 236 1.1 alnsn static struct bpf_insn insns[] = { 237 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 238 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF 239 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 240 1.1 alnsn }; 241 1.1 alnsn 242 1.1 alnsn bpfjit_func_t code; 243 1.1 alnsn uint8_t pkt[1] = { 0 }; 244 1.1 alnsn bpf_args_t args = { 245 1.1 alnsn .pkt = pkt, 246 1.1 alnsn .buflen = sizeof(pkt), 247 1.1 alnsn .wirelen = sizeof(pkt) 248 1.1 alnsn }; 249 1.1 alnsn 250 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 251 1.1 alnsn 252 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 253 1.1 alnsn ATF_REQUIRE(code != NULL); 254 1.1 alnsn 255 1.1 alnsn ATF_CHECK(code(&ctx, &args) == ctx.nfuncs); 256 1.1 alnsn 257 1.1 alnsn bpfjit_free_code(code); 258 1.1 alnsn } 259 1.1 alnsn 260 1.3 alnsn ATF_TC(libbpfjit_cop_side_effect); 261 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_side_effect, tc) 262 1.1 alnsn { 263 1.1 alnsn atf_tc_set_md_var(tc, "descr", 264 1.1 alnsn "Test that ABC optimization doesn't skip BPF_COP call"); 265 1.1 alnsn } 266 1.1 alnsn 267 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_side_effect, tc) 268 1.1 alnsn { 269 1.1 alnsn static struct bpf_insn insns[] = { 270 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 271 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), 272 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG 273 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999), 274 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 275 1.1 alnsn }; 276 1.1 alnsn 277 1.1 alnsn bpfjit_func_t code; 278 1.1 alnsn bool arg = false; 279 1.1 alnsn uint8_t pkt[1] = { 0 }; 280 1.1 alnsn bpf_args_t args = { 281 1.1 alnsn .pkt = pkt, 282 1.1 alnsn .buflen = sizeof(pkt), 283 1.1 alnsn .wirelen = sizeof(pkt), 284 1.1 alnsn .mem = NULL, 285 1.1 alnsn .arg = &arg 286 1.1 alnsn }; 287 1.1 alnsn 288 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 289 1.1 alnsn 290 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 291 1.1 alnsn ATF_REQUIRE(code != NULL); 292 1.1 alnsn 293 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0); 294 1.1 alnsn ATF_CHECK(arg == true); 295 1.1 alnsn 296 1.1 alnsn bpfjit_free_code(code); 297 1.1 alnsn } 298 1.1 alnsn 299 1.4 alnsn ATF_TC(libbpfjit_cop_copx); 300 1.4 alnsn ATF_TC_HEAD(libbpfjit_cop_copx, tc) 301 1.4 alnsn { 302 1.4 alnsn atf_tc_set_md_var(tc, "descr", 303 1.4 alnsn "Test BPF_COP call followed by BPF_COPX call"); 304 1.4 alnsn } 305 1.4 alnsn 306 1.4 alnsn ATF_TC_BODY(libbpfjit_cop_copx, tc) 307 1.4 alnsn { 308 1.4 alnsn static struct bpf_insn insns[] = { 309 1.4 alnsn BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */ 310 1.4 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), /* retA */ 311 1.4 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 312 1.4 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */ 313 1.4 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 314 1.4 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 315 1.4 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retNF */ 316 1.4 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 317 1.4 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 318 1.4 alnsn }; 319 1.4 alnsn 320 1.4 alnsn bpfjit_func_t code; 321 1.4 alnsn uint8_t pkt[1] = { 2 }; 322 1.4 alnsn bpf_args_t args = { 323 1.4 alnsn .pkt = pkt, 324 1.4 alnsn .buflen = sizeof(pkt), 325 1.4 alnsn .wirelen = sizeof(pkt), 326 1.4 alnsn }; 327 1.4 alnsn 328 1.4 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 329 1.4 alnsn 330 1.4 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 331 1.4 alnsn ATF_REQUIRE(code != NULL); 332 1.4 alnsn 333 1.4 alnsn ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs); 334 1.4 alnsn 335 1.4 alnsn bpfjit_free_code(code); 336 1.4 alnsn } 337 1.4 alnsn 338 1.3 alnsn ATF_TC(libbpfjit_cop_invalid_index); 339 1.3 alnsn ATF_TC_HEAD(libbpfjit_cop_invalid_index, tc) 340 1.1 alnsn { 341 1.1 alnsn atf_tc_set_md_var(tc, "descr", 342 1.1 alnsn "Test that out-of-range coprocessor function fails validation"); 343 1.1 alnsn } 344 1.1 alnsn 345 1.3 alnsn ATF_TC_BODY(libbpfjit_cop_invalid_index, tc) 346 1.1 alnsn { 347 1.1 alnsn static struct bpf_insn insns[] = { 348 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 349 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index 350 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 27) 351 1.1 alnsn }; 352 1.1 alnsn 353 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 354 1.1 alnsn 355 1.1 alnsn ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL); 356 1.1 alnsn } 357 1.1 alnsn 358 1.3 alnsn ATF_TC(libbpfjit_copx_no_ctx); 359 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_no_ctx, tc) 360 1.1 alnsn { 361 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX " 362 1.1 alnsn "instruction isn't valid without a context"); 363 1.1 alnsn } 364 1.1 alnsn 365 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_no_ctx, tc) 366 1.1 alnsn { 367 1.1 alnsn static struct bpf_insn insns[] = { 368 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), 369 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 7) 370 1.1 alnsn }; 371 1.1 alnsn 372 1.1 alnsn bpfjit_func_t code; 373 1.1 alnsn 374 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 375 1.1 alnsn 376 1.1 alnsn ATF_CHECK(!bpf_validate(insns, insn_count)); 377 1.1 alnsn 378 1.1 alnsn code = bpfjit_generate_code(NULL, insns, insn_count); 379 1.1 alnsn ATF_CHECK(code == NULL); 380 1.1 alnsn } 381 1.1 alnsn 382 1.3 alnsn ATF_TC(libbpfjit_copx_ret_A); 383 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_ret_A, tc) 384 1.1 alnsn { 385 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 386 1.1 alnsn "that returns a content of the A register"); 387 1.1 alnsn } 388 1.1 alnsn 389 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_ret_A, tc) 390 1.1 alnsn { 391 1.1 alnsn static struct bpf_insn insns[] = { 392 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 393 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA 394 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 395 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 396 1.1 alnsn }; 397 1.1 alnsn 398 1.1 alnsn bpfjit_func_t code; 399 1.1 alnsn uint8_t pkt[1] = { 0 }; 400 1.1 alnsn bpf_args_t args = { 401 1.1 alnsn .pkt = pkt, 402 1.1 alnsn .buflen = sizeof(pkt), 403 1.1 alnsn .wirelen = sizeof(pkt), 404 1.1 alnsn }; 405 1.1 alnsn 406 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 407 1.1 alnsn 408 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 409 1.1 alnsn ATF_REQUIRE(code != NULL); 410 1.1 alnsn 411 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 13); 412 1.1 alnsn 413 1.1 alnsn bpfjit_free_code(code); 414 1.1 alnsn } 415 1.1 alnsn 416 1.3 alnsn ATF_TC(libbpfjit_copx_ret_buflen); 417 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_ret_buflen, tc) 418 1.1 alnsn { 419 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 420 1.1 alnsn "that returns the buflen argument"); 421 1.1 alnsn } 422 1.1 alnsn 423 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_ret_buflen, tc) 424 1.1 alnsn { 425 1.1 alnsn static struct bpf_insn insns[] = { 426 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 427 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL 428 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 429 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 430 1.1 alnsn }; 431 1.1 alnsn 432 1.1 alnsn bpfjit_func_t code; 433 1.1 alnsn uint8_t pkt[1] = { 0 }; 434 1.1 alnsn bpf_args_t args = { 435 1.1 alnsn .pkt = pkt, 436 1.1 alnsn .buflen = sizeof(pkt), 437 1.1 alnsn .wirelen = sizeof(pkt) 438 1.1 alnsn }; 439 1.1 alnsn 440 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 441 1.1 alnsn 442 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 443 1.1 alnsn ATF_REQUIRE(code != NULL); 444 1.1 alnsn 445 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 446 1.1 alnsn 447 1.1 alnsn bpfjit_free_code(code); 448 1.1 alnsn } 449 1.1 alnsn 450 1.3 alnsn ATF_TC(libbpfjit_copx_ret_wirelen); 451 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_ret_wirelen, tc) 452 1.1 alnsn { 453 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 454 1.1 alnsn "that returns the wirelen argument"); 455 1.1 alnsn } 456 1.1 alnsn 457 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_ret_wirelen, tc) 458 1.1 alnsn { 459 1.1 alnsn static struct bpf_insn insns[] = { 460 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL 461 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 462 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 463 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 464 1.1 alnsn }; 465 1.1 alnsn 466 1.1 alnsn bpfjit_func_t code; 467 1.1 alnsn uint8_t pkt[1] = { 0 }; 468 1.1 alnsn bpf_args_t args = { 469 1.1 alnsn .pkt = pkt, 470 1.1 alnsn .buflen = sizeof(pkt), 471 1.1 alnsn .wirelen = sizeof(pkt) 472 1.1 alnsn }; 473 1.1 alnsn 474 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 475 1.1 alnsn 476 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 477 1.1 alnsn ATF_REQUIRE(code != NULL); 478 1.1 alnsn 479 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 480 1.1 alnsn 481 1.1 alnsn bpfjit_free_code(code); 482 1.1 alnsn } 483 1.1 alnsn 484 1.3 alnsn ATF_TC(libbpfjit_copx_ret_nfuncs); 485 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs, tc) 486 1.1 alnsn { 487 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 488 1.1 alnsn "that returns nfuncs member of the context argument"); 489 1.1 alnsn } 490 1.1 alnsn 491 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_ret_nfuncs, tc) 492 1.1 alnsn { 493 1.1 alnsn static struct bpf_insn insns[] = { 494 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 495 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF 496 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 497 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 498 1.1 alnsn }; 499 1.1 alnsn 500 1.1 alnsn bpfjit_func_t code; 501 1.1 alnsn uint8_t pkt[1] = { 0 }; 502 1.1 alnsn bpf_args_t args = { 503 1.1 alnsn .pkt = pkt, 504 1.1 alnsn .buflen = sizeof(pkt), 505 1.1 alnsn .wirelen = sizeof(pkt) 506 1.1 alnsn }; 507 1.1 alnsn 508 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 509 1.1 alnsn 510 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 511 1.1 alnsn ATF_REQUIRE(code != NULL); 512 1.1 alnsn 513 1.1 alnsn ATF_CHECK(code(&ctx, &args) == ctx.nfuncs); 514 1.1 alnsn 515 1.1 alnsn bpfjit_free_code(code); 516 1.1 alnsn } 517 1.1 alnsn 518 1.3 alnsn ATF_TC(libbpfjit_copx_side_effect); 519 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_side_effect, tc) 520 1.1 alnsn { 521 1.1 alnsn atf_tc_set_md_var(tc, "descr", 522 1.1 alnsn "Test that ABC optimization doesn't skip BPF_COPX call"); 523 1.1 alnsn } 524 1.1 alnsn 525 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_side_effect, tc) 526 1.1 alnsn { 527 1.1 alnsn static struct bpf_insn insns[] = { 528 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 529 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), 530 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG 531 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 532 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999), 533 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 534 1.1 alnsn }; 535 1.1 alnsn 536 1.1 alnsn bpfjit_func_t code; 537 1.1 alnsn bool arg = false; 538 1.1 alnsn uint8_t pkt[1] = { 0 }; 539 1.1 alnsn bpf_args_t args = { 540 1.1 alnsn .pkt = pkt, 541 1.1 alnsn .buflen = sizeof(pkt), 542 1.1 alnsn .wirelen = sizeof(pkt), 543 1.1 alnsn .mem = NULL, 544 1.1 alnsn .arg = &arg 545 1.1 alnsn }; 546 1.1 alnsn 547 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 548 1.1 alnsn 549 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 550 1.1 alnsn ATF_REQUIRE(code != NULL); 551 1.1 alnsn 552 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0); 553 1.1 alnsn ATF_CHECK(arg == true); 554 1.1 alnsn 555 1.1 alnsn bpfjit_free_code(code); 556 1.1 alnsn } 557 1.1 alnsn 558 1.4 alnsn ATF_TC(libbpfjit_copx_cop); 559 1.4 alnsn ATF_TC_HEAD(libbpfjit_copx_cop, tc) 560 1.4 alnsn { 561 1.4 alnsn atf_tc_set_md_var(tc, "descr", 562 1.4 alnsn "Test BPF_COPX call followed by BPF_COP call"); 563 1.4 alnsn } 564 1.4 alnsn 565 1.4 alnsn ATF_TC_BODY(libbpfjit_copx_cop, tc) 566 1.4 alnsn { 567 1.4 alnsn static struct bpf_insn insns[] = { 568 1.4 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 2), /* X <- 2 */ 569 1.4 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retWL */ 570 1.4 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 571 1.4 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 572 1.4 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */ 573 1.4 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 574 1.4 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 575 1.4 alnsn BPF_STMT(BPF_MISC+BPF_COP, 3), /* retNF */ 576 1.4 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 577 1.4 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 578 1.4 alnsn }; 579 1.4 alnsn 580 1.4 alnsn bpfjit_func_t code; 581 1.4 alnsn uint8_t pkt[1] = { 2 }; 582 1.4 alnsn bpf_args_t args = { 583 1.4 alnsn .pkt = pkt, 584 1.4 alnsn .buflen = sizeof(pkt), 585 1.4 alnsn .wirelen = sizeof(pkt), 586 1.4 alnsn }; 587 1.4 alnsn 588 1.4 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 589 1.4 alnsn 590 1.4 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 591 1.4 alnsn ATF_REQUIRE(code != NULL); 592 1.4 alnsn 593 1.4 alnsn ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs); 594 1.4 alnsn 595 1.4 alnsn bpfjit_free_code(code); 596 1.4 alnsn } 597 1.4 alnsn 598 1.3 alnsn ATF_TC(libbpfjit_copx_invalid_index); 599 1.3 alnsn ATF_TC_HEAD(libbpfjit_copx_invalid_index, tc) 600 1.1 alnsn { 601 1.1 alnsn atf_tc_set_md_var(tc, "descr", 602 1.1 alnsn "Test that out-of-range BPF_COPX call fails at runtime"); 603 1.1 alnsn } 604 1.1 alnsn 605 1.3 alnsn ATF_TC_BODY(libbpfjit_copx_invalid_index, tc) 606 1.1 alnsn { 607 1.1 alnsn static struct bpf_insn insns[] = { 608 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index 609 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 610 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 27) 611 1.1 alnsn }; 612 1.1 alnsn 613 1.1 alnsn bpfjit_func_t code; 614 1.1 alnsn uint8_t pkt[1] = { 0 }; 615 1.1 alnsn bpf_args_t args = { 616 1.1 alnsn .pkt = pkt, 617 1.1 alnsn .buflen = sizeof(pkt), 618 1.1 alnsn .wirelen = sizeof(pkt) 619 1.1 alnsn }; 620 1.1 alnsn 621 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 622 1.1 alnsn 623 1.1 alnsn code = bpfjit_generate_code(&ctx, insns, insn_count); 624 1.1 alnsn ATF_REQUIRE(code != NULL); 625 1.1 alnsn 626 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0); 627 1.1 alnsn 628 1.1 alnsn bpfjit_free_code(code); 629 1.1 alnsn } 630 1.1 alnsn 631 1.1 alnsn ATF_TP_ADD_TCS(tp) 632 1.1 alnsn { 633 1.1 alnsn 634 1.4 alnsn /* 635 1.4 alnsn * For every new test please also add a similar test 636 1.4 alnsn * to ../../net/bpfjit/t_cop.c 637 1.4 alnsn */ 638 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_no_ctx); 639 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_A); 640 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_buflen); 641 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_wirelen); 642 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_nfuncs); 643 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_side_effect); 644 1.4 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_copx); 645 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_cop_invalid_index); 646 1.3 alnsn 647 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_no_ctx); 648 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_A); 649 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_buflen); 650 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_wirelen); 651 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_nfuncs); 652 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_side_effect); 653 1.4 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_cop); 654 1.3 alnsn ATF_TP_ADD_TC(tp, libbpfjit_copx_invalid_index); 655 1.1 alnsn 656 1.1 alnsn return atf_no_error(); 657 1.1 alnsn } 658