xref: /netbsd-src/tests/lib/libbpfjit/t_cop.c (revision 2b2f4a0ebefc03e1a27985a73fa6b061af207fa1)
1*2b2f4a0eSalnsn /*	$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $ */
25990d54cSalnsn 
35990d54cSalnsn /*-
45b6fcae7Salnsn  * Copyright (c) 2013-2014 Alexander Nasonov.
55990d54cSalnsn  * All rights reserved.
65990d54cSalnsn  *
75990d54cSalnsn  * Redistribution and use in source and binary forms, with or without
85990d54cSalnsn  * modification, are permitted provided that the following conditions
95990d54cSalnsn  * are met:
105990d54cSalnsn  *
115990d54cSalnsn  * 1. Redistributions of source code must retain the above copyright
125990d54cSalnsn  *    notice, this list of conditions and the following disclaimer.
135990d54cSalnsn  * 2. Redistributions in binary form must reproduce the above copyright
145990d54cSalnsn  *    notice, this list of conditions and the following disclaimer in
155990d54cSalnsn  *    the documentation and/or other materials provided with the
165990d54cSalnsn  *    distribution.
175990d54cSalnsn  *
185990d54cSalnsn  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195990d54cSalnsn  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205990d54cSalnsn  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
215990d54cSalnsn  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
225990d54cSalnsn  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
235990d54cSalnsn  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
245990d54cSalnsn  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
255990d54cSalnsn  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
265990d54cSalnsn  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
275990d54cSalnsn  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
285990d54cSalnsn  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
295990d54cSalnsn  * SUCH DAMAGE.
305990d54cSalnsn  */
315990d54cSalnsn 
325990d54cSalnsn #include <sys/cdefs.h>
33*2b2f4a0eSalnsn __RCSID("$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $");
345990d54cSalnsn 
355990d54cSalnsn #include <atf-c.h>
365990d54cSalnsn #include <stdint.h>
375990d54cSalnsn #include <string.h>
385990d54cSalnsn 
395990d54cSalnsn #define __BPF_PRIVATE
405990d54cSalnsn #include <net/bpf.h>
415990d54cSalnsn #include <net/bpfjit.h>
425990d54cSalnsn 
435990d54cSalnsn static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
445990d54cSalnsn static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
455990d54cSalnsn static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
465990d54cSalnsn static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
475990d54cSalnsn static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
485990d54cSalnsn 
495990d54cSalnsn static const bpf_copfunc_t copfuncs[] = {
505990d54cSalnsn 	&retA,
515990d54cSalnsn 	&retBL,
525990d54cSalnsn 	&retWL,
535990d54cSalnsn 	&retNF,
545990d54cSalnsn 	&setARG
555990d54cSalnsn };
565990d54cSalnsn 
575990d54cSalnsn static const bpf_ctx_t ctx = {
585990d54cSalnsn 	.copfuncs = copfuncs,
595990d54cSalnsn 	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
605990d54cSalnsn 	.extwords = 0
615990d54cSalnsn };
625990d54cSalnsn 
635990d54cSalnsn static uint32_t
retA(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)645990d54cSalnsn retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
655990d54cSalnsn {
665990d54cSalnsn 
675990d54cSalnsn 	return A;
685990d54cSalnsn }
695990d54cSalnsn 
705990d54cSalnsn static uint32_t
retBL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)715990d54cSalnsn retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
725990d54cSalnsn {
735990d54cSalnsn 
745990d54cSalnsn 	return args->buflen;
755990d54cSalnsn }
765990d54cSalnsn 
775990d54cSalnsn static uint32_t
retWL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)785990d54cSalnsn retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
795990d54cSalnsn {
805990d54cSalnsn 
815990d54cSalnsn 	return args->wirelen;
825990d54cSalnsn }
835990d54cSalnsn 
845990d54cSalnsn static uint32_t
retNF(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)855990d54cSalnsn retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
865990d54cSalnsn {
875990d54cSalnsn 
885990d54cSalnsn 	return bc->nfuncs;
895990d54cSalnsn }
905990d54cSalnsn 
915990d54cSalnsn /*
925990d54cSalnsn  * COP function with a side effect.
935990d54cSalnsn  */
945990d54cSalnsn static uint32_t
setARG(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)955990d54cSalnsn setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
965990d54cSalnsn {
975990d54cSalnsn 	bool *arg = (bool *)args->arg;
985990d54cSalnsn 	bool old = *arg;
995990d54cSalnsn 
1005990d54cSalnsn 	*arg = true;
1015990d54cSalnsn 	return old;
1025990d54cSalnsn }
1035990d54cSalnsn 
104f5874843Salnsn ATF_TC(libbpfjit_cop_no_ctx);
ATF_TC_HEAD(libbpfjit_cop_no_ctx,tc)105f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_no_ctx, tc)
1065990d54cSalnsn {
1075990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
1085990d54cSalnsn 	    "instruction isn't valid without a context");
1095990d54cSalnsn }
1105990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_no_ctx,tc)111f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_no_ctx, tc)
1125990d54cSalnsn {
1135990d54cSalnsn 	static struct bpf_insn insns[] = {
1145990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 0),
1155990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_K, 7)
1165990d54cSalnsn 	};
1175990d54cSalnsn 
1185990d54cSalnsn 	bpfjit_func_t code;
1195990d54cSalnsn 
1205990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
1215990d54cSalnsn 
1225990d54cSalnsn 	ATF_CHECK(!bpf_validate(insns, insn_count));
1235990d54cSalnsn 
1245990d54cSalnsn 	code = bpfjit_generate_code(NULL, insns, insn_count);
1255990d54cSalnsn 	ATF_CHECK(code == NULL);
1265990d54cSalnsn }
1275990d54cSalnsn 
128f5874843Salnsn ATF_TC(libbpfjit_cop_ret_A);
ATF_TC_HEAD(libbpfjit_cop_ret_A,tc)129f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_ret_A, tc)
1305990d54cSalnsn {
1315990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
1325990d54cSalnsn 	    "that returns a content of the A register");
1335990d54cSalnsn }
1345990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_ret_A,tc)135f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_ret_A, tc)
1365990d54cSalnsn {
1375990d54cSalnsn 	static struct bpf_insn insns[] = {
1385990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
1395990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
1405990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
1415990d54cSalnsn 	};
1425990d54cSalnsn 
1435990d54cSalnsn 	bpfjit_func_t code;
1445990d54cSalnsn 	uint8_t pkt[1] = { 0 };
1455990d54cSalnsn 	bpf_args_t args = {
1465990d54cSalnsn 		.pkt = pkt,
1475990d54cSalnsn 		.buflen = sizeof(pkt),
1485990d54cSalnsn 		.wirelen = sizeof(pkt),
1495990d54cSalnsn 	};
1505990d54cSalnsn 
1515990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
1525990d54cSalnsn 
1535990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
1545990d54cSalnsn 	ATF_REQUIRE(code != NULL);
1555990d54cSalnsn 
1565990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == 13);
1575990d54cSalnsn 
1585990d54cSalnsn 	bpfjit_free_code(code);
1595990d54cSalnsn }
1605990d54cSalnsn 
161f5874843Salnsn ATF_TC(libbpfjit_cop_ret_buflen);
ATF_TC_HEAD(libbpfjit_cop_ret_buflen,tc)162f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_ret_buflen, tc)
1635990d54cSalnsn {
1645990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
1655990d54cSalnsn 	    "that returns the buflen argument");
1665990d54cSalnsn }
1675990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_ret_buflen,tc)168f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_ret_buflen, tc)
1695990d54cSalnsn {
1705990d54cSalnsn 	static struct bpf_insn insns[] = {
1715990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
1725990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
1735990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
1745990d54cSalnsn 	};
1755990d54cSalnsn 
1765990d54cSalnsn 	bpfjit_func_t code;
1775990d54cSalnsn 	uint8_t pkt[1] = { 0 };
1785990d54cSalnsn 	bpf_args_t args = {
1795990d54cSalnsn 		.pkt = pkt,
1805990d54cSalnsn 		.buflen = sizeof(pkt),
1815990d54cSalnsn 		.wirelen = sizeof(pkt)
1825990d54cSalnsn 	};
1835990d54cSalnsn 
1845990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
1855990d54cSalnsn 
1865990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
1875990d54cSalnsn 	ATF_REQUIRE(code != NULL);
1885990d54cSalnsn 
1895990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
1905990d54cSalnsn 
1915990d54cSalnsn 	bpfjit_free_code(code);
1925990d54cSalnsn }
1935990d54cSalnsn 
194f5874843Salnsn ATF_TC(libbpfjit_cop_ret_wirelen);
ATF_TC_HEAD(libbpfjit_cop_ret_wirelen,tc)195f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_ret_wirelen, tc)
1965990d54cSalnsn {
1975990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
1985990d54cSalnsn 	    "that returns the wirelen argument");
1995990d54cSalnsn }
2005990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_ret_wirelen,tc)201f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_ret_wirelen, tc)
2025990d54cSalnsn {
2035990d54cSalnsn 	static struct bpf_insn insns[] = {
2045990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
2055990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
2065990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
2075990d54cSalnsn 	};
2085990d54cSalnsn 
2095990d54cSalnsn 	bpfjit_func_t code;
2105990d54cSalnsn 	uint8_t pkt[1] = { 0 };
2115990d54cSalnsn 	bpf_args_t args = {
2125990d54cSalnsn 		.pkt = pkt,
2135990d54cSalnsn 		.buflen = sizeof(pkt),
2145990d54cSalnsn 		.wirelen = sizeof(pkt)
2155990d54cSalnsn 	};
2165990d54cSalnsn 
2175990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
2185990d54cSalnsn 
2195990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
2205990d54cSalnsn 	ATF_REQUIRE(code != NULL);
2215990d54cSalnsn 
2225990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
2235990d54cSalnsn 
2245990d54cSalnsn 	bpfjit_free_code(code);
2255990d54cSalnsn }
2265990d54cSalnsn 
227f5874843Salnsn ATF_TC(libbpfjit_cop_ret_nfuncs);
ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs,tc)228f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs, tc)
2295990d54cSalnsn {
2305990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
2315990d54cSalnsn 	    "that returns nfuncs member of the context argument");
2325990d54cSalnsn }
2335990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_ret_nfuncs,tc)234f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_ret_nfuncs, tc)
2355990d54cSalnsn {
2365990d54cSalnsn 	static struct bpf_insn insns[] = {
2375990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
2385990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
2395990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
2405990d54cSalnsn 	};
2415990d54cSalnsn 
2425990d54cSalnsn 	bpfjit_func_t code;
2435990d54cSalnsn 	uint8_t pkt[1] = { 0 };
2445990d54cSalnsn 	bpf_args_t args = {
2455990d54cSalnsn 		.pkt = pkt,
2465990d54cSalnsn 		.buflen = sizeof(pkt),
2475990d54cSalnsn 		.wirelen = sizeof(pkt)
2485990d54cSalnsn 	};
2495990d54cSalnsn 
2505990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
2515990d54cSalnsn 
2525990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
2535990d54cSalnsn 	ATF_REQUIRE(code != NULL);
2545990d54cSalnsn 
2555990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
2565990d54cSalnsn 
2575990d54cSalnsn 	bpfjit_free_code(code);
2585990d54cSalnsn }
2595990d54cSalnsn 
260f5874843Salnsn ATF_TC(libbpfjit_cop_side_effect);
ATF_TC_HEAD(libbpfjit_cop_side_effect,tc)261f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_side_effect, tc)
2625990d54cSalnsn {
2635990d54cSalnsn 	atf_tc_set_md_var(tc, "descr",
2645990d54cSalnsn 	    "Test that ABC optimization doesn't skip BPF_COP call");
2655990d54cSalnsn }
2665990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_side_effect,tc)267f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_side_effect, tc)
2685990d54cSalnsn {
2695990d54cSalnsn 	static struct bpf_insn insns[] = {
2705990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
2715990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
2725990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
2735990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
2745990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
2755990d54cSalnsn 	};
2765990d54cSalnsn 
2775990d54cSalnsn 	bpfjit_func_t code;
2785990d54cSalnsn 	bool arg = false;
2795990d54cSalnsn 	uint8_t pkt[1] = { 0 };
2805990d54cSalnsn 	bpf_args_t args = {
2815990d54cSalnsn 		.pkt = pkt,
2825990d54cSalnsn 		.buflen = sizeof(pkt),
2835990d54cSalnsn 		.wirelen = sizeof(pkt),
2845990d54cSalnsn 		.mem = NULL,
2855990d54cSalnsn 		.arg = &arg
2865990d54cSalnsn 	};
2875990d54cSalnsn 
2885990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
2895990d54cSalnsn 
2905990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
2915990d54cSalnsn 	ATF_REQUIRE(code != NULL);
2925990d54cSalnsn 
2935990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == 0);
2945990d54cSalnsn 	ATF_CHECK(arg == true);
2955990d54cSalnsn 
2965990d54cSalnsn 	bpfjit_free_code(code);
2975990d54cSalnsn }
2985990d54cSalnsn 
299*2b2f4a0eSalnsn ATF_TC(libbpfjit_cop_copx);
ATF_TC_HEAD(libbpfjit_cop_copx,tc)300*2b2f4a0eSalnsn ATF_TC_HEAD(libbpfjit_cop_copx, tc)
301*2b2f4a0eSalnsn {
302*2b2f4a0eSalnsn 	atf_tc_set_md_var(tc, "descr",
303*2b2f4a0eSalnsn 	    "Test BPF_COP call followed by BPF_COPX call");
304*2b2f4a0eSalnsn }
305*2b2f4a0eSalnsn 
ATF_TC_BODY(libbpfjit_cop_copx,tc)306*2b2f4a0eSalnsn ATF_TC_BODY(libbpfjit_cop_copx, tc)
307*2b2f4a0eSalnsn {
308*2b2f4a0eSalnsn 	static struct bpf_insn insns[] = {
309*2b2f4a0eSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 1),         /* A <- 1    */
310*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 0),       /* retA      */
311*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
312*2b2f4a0eSalnsn 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
313*2b2f4a0eSalnsn 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
314*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
315*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retNF     */
316*2b2f4a0eSalnsn 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
317*2b2f4a0eSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
318*2b2f4a0eSalnsn 	};
319*2b2f4a0eSalnsn 
320*2b2f4a0eSalnsn 	bpfjit_func_t code;
321*2b2f4a0eSalnsn 	uint8_t pkt[1] = { 2 };
322*2b2f4a0eSalnsn 	bpf_args_t args = {
323*2b2f4a0eSalnsn 		.pkt = pkt,
324*2b2f4a0eSalnsn 		.buflen = sizeof(pkt),
325*2b2f4a0eSalnsn 		.wirelen = sizeof(pkt),
326*2b2f4a0eSalnsn 	};
327*2b2f4a0eSalnsn 
328*2b2f4a0eSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
329*2b2f4a0eSalnsn 
330*2b2f4a0eSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
331*2b2f4a0eSalnsn 	ATF_REQUIRE(code != NULL);
332*2b2f4a0eSalnsn 
333*2b2f4a0eSalnsn 	ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
334*2b2f4a0eSalnsn 
335*2b2f4a0eSalnsn 	bpfjit_free_code(code);
336*2b2f4a0eSalnsn }
337*2b2f4a0eSalnsn 
338f5874843Salnsn ATF_TC(libbpfjit_cop_invalid_index);
ATF_TC_HEAD(libbpfjit_cop_invalid_index,tc)339f5874843Salnsn ATF_TC_HEAD(libbpfjit_cop_invalid_index, tc)
3405990d54cSalnsn {
3415990d54cSalnsn 	atf_tc_set_md_var(tc, "descr",
3425990d54cSalnsn 	    "Test that out-of-range coprocessor function fails validation");
3435990d54cSalnsn }
3445990d54cSalnsn 
ATF_TC_BODY(libbpfjit_cop_invalid_index,tc)345f5874843Salnsn ATF_TC_BODY(libbpfjit_cop_invalid_index, tc)
3465990d54cSalnsn {
3475990d54cSalnsn 	static struct bpf_insn insns[] = {
3485990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
3495990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
3505990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_K, 27)
3515990d54cSalnsn 	};
3525990d54cSalnsn 
3535990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
3545990d54cSalnsn 
3555990d54cSalnsn 	ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
3565990d54cSalnsn }
3575990d54cSalnsn 
358f5874843Salnsn ATF_TC(libbpfjit_copx_no_ctx);
ATF_TC_HEAD(libbpfjit_copx_no_ctx,tc)359f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_no_ctx, tc)
3605990d54cSalnsn {
3615990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
3625990d54cSalnsn 	    "instruction isn't valid without a context");
3635990d54cSalnsn }
3645990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_no_ctx,tc)365f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_no_ctx, tc)
3665990d54cSalnsn {
3675990d54cSalnsn 	static struct bpf_insn insns[] = {
3685990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 0),
3695990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_K, 7)
3705990d54cSalnsn 	};
3715990d54cSalnsn 
3725990d54cSalnsn 	bpfjit_func_t code;
3735990d54cSalnsn 
3745990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
3755990d54cSalnsn 
3765990d54cSalnsn 	ATF_CHECK(!bpf_validate(insns, insn_count));
3775990d54cSalnsn 
3785990d54cSalnsn 	code = bpfjit_generate_code(NULL, insns, insn_count);
3795990d54cSalnsn 	ATF_CHECK(code == NULL);
3805990d54cSalnsn }
3815990d54cSalnsn 
382f5874843Salnsn ATF_TC(libbpfjit_copx_ret_A);
ATF_TC_HEAD(libbpfjit_copx_ret_A,tc)383f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_ret_A, tc)
3845990d54cSalnsn {
3855990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
3865990d54cSalnsn 	    "that returns a content of the A register");
3875990d54cSalnsn }
3885990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_ret_A,tc)389f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_ret_A, tc)
3905990d54cSalnsn {
3915990d54cSalnsn 	static struct bpf_insn insns[] = {
3925990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
3935990d54cSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
3945990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
3955990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
3965990d54cSalnsn 	};
3975990d54cSalnsn 
3985990d54cSalnsn 	bpfjit_func_t code;
3995990d54cSalnsn 	uint8_t pkt[1] = { 0 };
4005990d54cSalnsn 	bpf_args_t args = {
4015990d54cSalnsn 		.pkt = pkt,
4025990d54cSalnsn 		.buflen = sizeof(pkt),
4035990d54cSalnsn 		.wirelen = sizeof(pkt),
4045990d54cSalnsn 	};
4055990d54cSalnsn 
4065990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
4075990d54cSalnsn 
4085990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
4095990d54cSalnsn 	ATF_REQUIRE(code != NULL);
4105990d54cSalnsn 
4115990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == 13);
4125990d54cSalnsn 
4135990d54cSalnsn 	bpfjit_free_code(code);
4145990d54cSalnsn }
4155990d54cSalnsn 
416f5874843Salnsn ATF_TC(libbpfjit_copx_ret_buflen);
ATF_TC_HEAD(libbpfjit_copx_ret_buflen,tc)417f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_ret_buflen, tc)
4185990d54cSalnsn {
4195990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
4205990d54cSalnsn 	    "that returns the buflen argument");
4215990d54cSalnsn }
4225990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_ret_buflen,tc)423f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_ret_buflen, tc)
4245990d54cSalnsn {
4255990d54cSalnsn 	static struct bpf_insn insns[] = {
4265990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
4275990d54cSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
4285990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
4295990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
4305990d54cSalnsn 	};
4315990d54cSalnsn 
4325990d54cSalnsn 	bpfjit_func_t code;
4335990d54cSalnsn 	uint8_t pkt[1] = { 0 };
4345990d54cSalnsn 	bpf_args_t args = {
4355990d54cSalnsn 		.pkt = pkt,
4365990d54cSalnsn 		.buflen = sizeof(pkt),
4375990d54cSalnsn 		.wirelen = sizeof(pkt)
4385990d54cSalnsn 	};
4395990d54cSalnsn 
4405990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
4415990d54cSalnsn 
4425990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
4435990d54cSalnsn 	ATF_REQUIRE(code != NULL);
4445990d54cSalnsn 
4455990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
4465990d54cSalnsn 
4475990d54cSalnsn 	bpfjit_free_code(code);
4485990d54cSalnsn }
4495990d54cSalnsn 
450f5874843Salnsn ATF_TC(libbpfjit_copx_ret_wirelen);
ATF_TC_HEAD(libbpfjit_copx_ret_wirelen,tc)451f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_ret_wirelen, tc)
4525990d54cSalnsn {
4535990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
4545990d54cSalnsn 	    "that returns the wirelen argument");
4555990d54cSalnsn }
4565990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_ret_wirelen,tc)457f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_ret_wirelen, tc)
4585990d54cSalnsn {
4595990d54cSalnsn 	static struct bpf_insn insns[] = {
4605990d54cSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
4615990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
4625990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
4635990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
4645990d54cSalnsn 	};
4655990d54cSalnsn 
4665990d54cSalnsn 	bpfjit_func_t code;
4675990d54cSalnsn 	uint8_t pkt[1] = { 0 };
4685990d54cSalnsn 	bpf_args_t args = {
4695990d54cSalnsn 		.pkt = pkt,
4705990d54cSalnsn 		.buflen = sizeof(pkt),
4715990d54cSalnsn 		.wirelen = sizeof(pkt)
4725990d54cSalnsn 	};
4735990d54cSalnsn 
4745990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
4755990d54cSalnsn 
4765990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
4775990d54cSalnsn 	ATF_REQUIRE(code != NULL);
4785990d54cSalnsn 
4795990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
4805990d54cSalnsn 
4815990d54cSalnsn 	bpfjit_free_code(code);
4825990d54cSalnsn }
4835990d54cSalnsn 
484f5874843Salnsn ATF_TC(libbpfjit_copx_ret_nfuncs);
ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs,tc)485f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs, tc)
4865990d54cSalnsn {
4875990d54cSalnsn 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
4885990d54cSalnsn 	    "that returns nfuncs member of the context argument");
4895990d54cSalnsn }
4905990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_ret_nfuncs,tc)491f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_ret_nfuncs, tc)
4925990d54cSalnsn {
4935990d54cSalnsn 	static struct bpf_insn insns[] = {
4945990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
4955990d54cSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
4965990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
4975990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
4985990d54cSalnsn 	};
4995990d54cSalnsn 
5005990d54cSalnsn 	bpfjit_func_t code;
5015990d54cSalnsn 	uint8_t pkt[1] = { 0 };
5025990d54cSalnsn 	bpf_args_t args = {
5035990d54cSalnsn 		.pkt = pkt,
5045990d54cSalnsn 		.buflen = sizeof(pkt),
5055990d54cSalnsn 		.wirelen = sizeof(pkt)
5065990d54cSalnsn 	};
5075990d54cSalnsn 
5085990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
5095990d54cSalnsn 
5105990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
5115990d54cSalnsn 	ATF_REQUIRE(code != NULL);
5125990d54cSalnsn 
5135990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
5145990d54cSalnsn 
5155990d54cSalnsn 	bpfjit_free_code(code);
5165990d54cSalnsn }
5175990d54cSalnsn 
518f5874843Salnsn ATF_TC(libbpfjit_copx_side_effect);
ATF_TC_HEAD(libbpfjit_copx_side_effect,tc)519f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_side_effect, tc)
5205990d54cSalnsn {
5215990d54cSalnsn 	atf_tc_set_md_var(tc, "descr",
5225990d54cSalnsn 	    "Test that ABC optimization doesn't skip BPF_COPX call");
5235990d54cSalnsn }
5245990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_side_effect,tc)525f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_side_effect, tc)
5265990d54cSalnsn {
5275990d54cSalnsn 	static struct bpf_insn insns[] = {
5285990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_IMM, 13),
5295990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
5305990d54cSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
5315990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
5325990d54cSalnsn 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
5335990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
5345990d54cSalnsn 	};
5355990d54cSalnsn 
5365990d54cSalnsn 	bpfjit_func_t code;
5375990d54cSalnsn 	bool arg = false;
5385990d54cSalnsn 	uint8_t pkt[1] = { 0 };
5395990d54cSalnsn 	bpf_args_t args = {
5405990d54cSalnsn 		.pkt = pkt,
5415990d54cSalnsn 		.buflen = sizeof(pkt),
5425990d54cSalnsn 		.wirelen = sizeof(pkt),
5435990d54cSalnsn 		.mem = NULL,
5445990d54cSalnsn 		.arg = &arg
5455990d54cSalnsn 	};
5465990d54cSalnsn 
5475990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
5485990d54cSalnsn 
5495990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
5505990d54cSalnsn 	ATF_REQUIRE(code != NULL);
5515990d54cSalnsn 
5525990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == 0);
5535990d54cSalnsn 	ATF_CHECK(arg == true);
5545990d54cSalnsn 
5555990d54cSalnsn 	bpfjit_free_code(code);
5565990d54cSalnsn }
5575990d54cSalnsn 
558*2b2f4a0eSalnsn ATF_TC(libbpfjit_copx_cop);
ATF_TC_HEAD(libbpfjit_copx_cop,tc)559*2b2f4a0eSalnsn ATF_TC_HEAD(libbpfjit_copx_cop, tc)
560*2b2f4a0eSalnsn {
561*2b2f4a0eSalnsn 	atf_tc_set_md_var(tc, "descr",
562*2b2f4a0eSalnsn 	    "Test BPF_COPX call followed by BPF_COP call");
563*2b2f4a0eSalnsn }
564*2b2f4a0eSalnsn 
ATF_TC_BODY(libbpfjit_copx_cop,tc)565*2b2f4a0eSalnsn ATF_TC_BODY(libbpfjit_copx_cop, tc)
566*2b2f4a0eSalnsn {
567*2b2f4a0eSalnsn 	static struct bpf_insn insns[] = {
568*2b2f4a0eSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 2),        /* X <- 2    */
569*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retWL     */
570*2b2f4a0eSalnsn 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
571*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
572*2b2f4a0eSalnsn 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
573*2b2f4a0eSalnsn 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
574*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
575*2b2f4a0eSalnsn 		BPF_STMT(BPF_MISC+BPF_COP, 3),      /* retNF     */
576*2b2f4a0eSalnsn 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
577*2b2f4a0eSalnsn 		BPF_STMT(BPF_RET+BPF_A, 0)
578*2b2f4a0eSalnsn 	};
579*2b2f4a0eSalnsn 
580*2b2f4a0eSalnsn 	bpfjit_func_t code;
581*2b2f4a0eSalnsn 	uint8_t pkt[1] = { 2 };
582*2b2f4a0eSalnsn 	bpf_args_t args = {
583*2b2f4a0eSalnsn 		.pkt = pkt,
584*2b2f4a0eSalnsn 		.buflen = sizeof(pkt),
585*2b2f4a0eSalnsn 		.wirelen = sizeof(pkt),
586*2b2f4a0eSalnsn 	};
587*2b2f4a0eSalnsn 
588*2b2f4a0eSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
589*2b2f4a0eSalnsn 
590*2b2f4a0eSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
591*2b2f4a0eSalnsn 	ATF_REQUIRE(code != NULL);
592*2b2f4a0eSalnsn 
593*2b2f4a0eSalnsn 	ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
594*2b2f4a0eSalnsn 
595*2b2f4a0eSalnsn 	bpfjit_free_code(code);
596*2b2f4a0eSalnsn }
597*2b2f4a0eSalnsn 
598f5874843Salnsn ATF_TC(libbpfjit_copx_invalid_index);
ATF_TC_HEAD(libbpfjit_copx_invalid_index,tc)599f5874843Salnsn ATF_TC_HEAD(libbpfjit_copx_invalid_index, tc)
6005990d54cSalnsn {
6015990d54cSalnsn 	atf_tc_set_md_var(tc, "descr",
6025990d54cSalnsn 	    "Test that out-of-range BPF_COPX call fails at runtime");
6035990d54cSalnsn }
6045990d54cSalnsn 
ATF_TC_BODY(libbpfjit_copx_invalid_index,tc)605f5874843Salnsn ATF_TC_BODY(libbpfjit_copx_invalid_index, tc)
6065990d54cSalnsn {
6075990d54cSalnsn 	static struct bpf_insn insns[] = {
6085990d54cSalnsn 		BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
6095990d54cSalnsn 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
6105990d54cSalnsn 		BPF_STMT(BPF_RET+BPF_K, 27)
6115990d54cSalnsn 	};
6125990d54cSalnsn 
6135990d54cSalnsn 	bpfjit_func_t code;
6145990d54cSalnsn 	uint8_t pkt[1] = { 0 };
6155990d54cSalnsn 	bpf_args_t args = {
6165990d54cSalnsn 		.pkt = pkt,
6175990d54cSalnsn 		.buflen = sizeof(pkt),
6185990d54cSalnsn 		.wirelen = sizeof(pkt)
6195990d54cSalnsn 	};
6205990d54cSalnsn 
6215990d54cSalnsn 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
6225990d54cSalnsn 
6235990d54cSalnsn 	code = bpfjit_generate_code(&ctx, insns, insn_count);
6245990d54cSalnsn 	ATF_REQUIRE(code != NULL);
6255990d54cSalnsn 
6265990d54cSalnsn 	ATF_CHECK(code(&ctx, &args) == 0);
6275990d54cSalnsn 
6285990d54cSalnsn 	bpfjit_free_code(code);
6295990d54cSalnsn }
6305990d54cSalnsn 
ATF_TP_ADD_TCS(tp)6315990d54cSalnsn ATF_TP_ADD_TCS(tp)
6325990d54cSalnsn {
6335990d54cSalnsn 
634*2b2f4a0eSalnsn 	/*
635*2b2f4a0eSalnsn 	 * For every new test please also add a similar test
636*2b2f4a0eSalnsn 	 * to ../../net/bpfjit/t_cop.c
637*2b2f4a0eSalnsn 	 */
638f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_no_ctx);
639f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_A);
640f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_buflen);
641f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_wirelen);
642f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_nfuncs);
643f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_side_effect);
644*2b2f4a0eSalnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_copx);
645f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_cop_invalid_index);
6465990d54cSalnsn 
647f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_no_ctx);
648f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_A);
649f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_buflen);
650f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_wirelen);
651f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_nfuncs);
652f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_side_effect);
653*2b2f4a0eSalnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_cop);
654f5874843Salnsn 	ATF_TP_ADD_TC(tp, libbpfjit_copx_invalid_index);
6555990d54cSalnsn 
6565990d54cSalnsn 	return atf_no_error();
6575990d54cSalnsn }
658