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