Home | History | Annotate | Line # | Download | only in bpfjit
t_extmem.c revision 1.2
      1 /*	$NetBSD: t_extmem.c,v 1.2 2017/01/13 21:30:42 christos Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 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_extmem.c,v 1.2 2017/01/13 21:30:42 christos Exp $");
     34 
     35 #include <stdint.h>
     36 #include <string.h>
     37 
     38 #define __BPF_PRIVATE
     39 #include <net/bpf.h>
     40 #include <net/bpfjit.h>
     41 
     42 #include "../../net/bpf/h_bpf.h"
     43 
     44 /* XXX: atf-c.h has collisions with mbuf */
     45 #undef m_type
     46 #undef m_data
     47 #include <atf-c.h>
     48 
     49 #include "h_macros.h"
     50 
     51 static uint32_t retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
     52 
     53 static const bpf_copfunc_t copfuncs[] = {
     54 	&retM
     55 };
     56 
     57 static const bpf_ctx_t ctx = {
     58 	.copfuncs = copfuncs,
     59 	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
     60 	.extwords = 4,
     61 	.preinited = BPF_MEMWORD_INIT(0) | BPF_MEMWORD_INIT(3),
     62 };
     63 
     64 static uint32_t
     65 retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
     66 {
     67 
     68 	return args->mem[(uintptr_t)args->arg];
     69 }
     70 
     71 
     72 ATF_TC(bpfjit_extmem_load_preinited);
     73 ATF_TC_HEAD(bpfjit_extmem_load_preinited, tc)
     74 {
     75 	atf_tc_set_md_var(tc, "descr", "Test a load of external "
     76 	    "pre-initialized memory");
     77 }
     78 
     79 ATF_TC_BODY(bpfjit_extmem_load_preinited, tc)
     80 {
     81 	static struct bpf_insn insns[] = {
     82 		BPF_STMT(BPF_LD+BPF_MEM, 3),
     83 		BPF_STMT(BPF_RET+BPF_A, 0)
     84 	};
     85 
     86 	bpfjit_func_t code;
     87 	uint8_t pkt[1] = { 0 };
     88 	uint32_t mem[ctx.extwords];
     89 
     90 	/* Pre-inited words. */
     91 	mem[0] = 0;
     92 	mem[3] = 3;
     93 
     94 	bpf_args_t args = {
     95 		.pkt = pkt,
     96 		.buflen = sizeof(pkt),
     97 		.wirelen = sizeof(pkt),
     98 		.mem = mem,
     99 	};
    100 
    101 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    102 
    103 	RZ(rump_init());
    104 
    105 	rump_schedule();
    106 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    107 	rump_unschedule();
    108 	ATF_REQUIRE(code != NULL);
    109 
    110 	ATF_CHECK(code(&ctx, &args) == 3);
    111 
    112 	rump_schedule();
    113 	rumpns_bpfjit_free_code(code);
    114 	rump_unschedule();
    115 }
    116 
    117 ATF_TC(bpfjit_extmem_invalid_load);
    118 ATF_TC_HEAD(bpfjit_extmem_invalid_load, tc)
    119 {
    120 	atf_tc_set_md_var(tc, "descr", "Test that out-of-range load "
    121 	    "fails validation");
    122 }
    123 
    124 ATF_TC_BODY(bpfjit_extmem_invalid_load, tc)
    125 {
    126 	static struct bpf_insn insns[] = {
    127 		BPF_STMT(BPF_LD+BPF_MEM, 4),
    128 		BPF_STMT(BPF_RET+BPF_A, 0)
    129 	};
    130 
    131 	bpfjit_func_t code;
    132 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    133 
    134 	RZ(rump_init());
    135 
    136 	rump_schedule();
    137 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    138 	rump_unschedule();
    139 	ATF_CHECK(code == NULL);
    140 }
    141 
    142 ATF_TC(bpfjit_extmem_store);
    143 ATF_TC_HEAD(bpfjit_extmem_store, tc)
    144 {
    145 	atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
    146 }
    147 
    148 ATF_TC_BODY(bpfjit_extmem_store, tc)
    149 {
    150 	static struct bpf_insn insns[] = {
    151 		BPF_STMT(BPF_LD+BPF_IMM, 1),        /* A <- 1     */
    152 		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
    153 		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
    154 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
    155 		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
    156 		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
    157 		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
    158 	};
    159 
    160 	bpfjit_func_t code;
    161 	uint8_t pkt[1] = { 0 };
    162 	uint32_t mem[ctx.extwords];
    163 
    164 	/* Pre-inited words. */
    165 	mem[0] = 0;
    166 	mem[3] = 7;
    167 
    168 	mem[1] = mem[2] = 0xdeadbeef;
    169 
    170 	bpf_args_t args = {
    171 		.pkt = pkt,
    172 		.buflen = sizeof(pkt),
    173 		.wirelen = sizeof(pkt),
    174 		.mem = mem,
    175 	};
    176 
    177 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    178 
    179 	RZ(rump_init());
    180 
    181 	rump_schedule();
    182 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    183 	rump_unschedule();
    184 	ATF_REQUIRE(code != NULL);
    185 
    186 	ATF_CHECK(code(&ctx, &args) == 3);
    187 
    188 	rump_schedule();
    189 	rumpns_bpfjit_free_code(code);
    190 	rump_unschedule();
    191 
    192 	ATF_CHECK(mem[0] == 0);
    193 	ATF_CHECK(mem[1] == 1);
    194 	ATF_CHECK(mem[2] == 2);
    195 	ATF_CHECK(mem[3] == 3);
    196 }
    197 
    198 ATF_TC(bpfjit_extmem_side_effect);
    199 ATF_TC_HEAD(bpfjit_extmem_side_effect, tc)
    200 {
    201 	atf_tc_set_md_var(tc, "descr", "Test that ABC optimization doesn\'t "
    202 	    "skip stores to external memory");
    203 }
    204 
    205 ATF_TC_BODY(bpfjit_extmem_side_effect, tc)
    206 {
    207 	static struct bpf_insn insns[] = {
    208 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),  /* A <- P[0]  */
    209 		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
    210 		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
    211 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
    212 		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
    213 		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
    214 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */
    215 		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
    216 	};
    217 
    218 	bpfjit_func_t code;
    219 	uint8_t pkt[1] = { 1 };
    220 	uint32_t mem[ctx.extwords];
    221 
    222 	/* Pre-inited words. */
    223 	mem[0] = 0;
    224 	mem[3] = 7;
    225 
    226 	mem[1] = mem[2] = 0xdeadbeef;
    227 
    228 	bpf_args_t args = {
    229 		.pkt = pkt,
    230 		.buflen = sizeof(pkt),
    231 		.wirelen = sizeof(pkt),
    232 		.mem = mem,
    233 	};
    234 
    235 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    236 
    237 	RZ(rump_init());
    238 
    239 	rump_schedule();
    240 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    241 	rump_unschedule();
    242 	ATF_REQUIRE(code != NULL);
    243 
    244 	ATF_CHECK(code(&ctx, &args) == 0);
    245 
    246 	rump_schedule();
    247 	rumpns_bpfjit_free_code(code);
    248 	rump_unschedule();
    249 
    250 	ATF_CHECK(mem[0] == 0);
    251 	ATF_CHECK(mem[1] == 1);
    252 	ATF_CHECK(mem[2] == 2);
    253 	ATF_CHECK(mem[3] == 3);
    254 }
    255 
    256 ATF_TC(bpfjit_extmem_invalid_store);
    257 ATF_TC_HEAD(bpfjit_extmem_invalid_store, tc)
    258 {
    259 	atf_tc_set_md_var(tc, "descr", "Test that out-of-range store "
    260 	    "fails validation");
    261 }
    262 
    263 ATF_TC_BODY(bpfjit_extmem_invalid_store, tc)
    264 {
    265 	static struct bpf_insn insns[] = {
    266 		BPF_STMT(BPF_ST, 4),
    267 		BPF_STMT(BPF_RET+BPF_A, 0)
    268 	};
    269 
    270 	bpfjit_func_t code;
    271 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    272 
    273 	RZ(rump_init());
    274 
    275 	rump_schedule();
    276 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    277 	rump_unschedule();
    278 	ATF_CHECK(code == NULL);
    279 }
    280 
    281 ATF_TC(bpfjit_cop_ret_mem);
    282 ATF_TC_HEAD(bpfjit_cop_ret_mem, tc)
    283 {
    284 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
    285 	    "that returns a content of external memory word");
    286 }
    287 
    288 ATF_TC_BODY(bpfjit_cop_ret_mem, tc)
    289 {
    290 	static struct bpf_insn insns[] = {
    291 		BPF_STMT(BPF_LD+BPF_IMM, 13),
    292 		BPF_STMT(BPF_ST, 2),
    293 		BPF_STMT(BPF_LD+BPF_IMM, 137),
    294 		BPF_STMT(BPF_ST, 1),
    295 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
    296 		BPF_STMT(BPF_RET+BPF_A, 0)
    297 	};
    298 
    299 	bpfjit_func_t code;
    300 	uint8_t pkt[1] = { 0 };
    301 	uint32_t mem[ctx.extwords];
    302 	void *arg = (void*)(uintptr_t)2;
    303 
    304 	/* Pre-inited words. */
    305 	mem[0] = 0;
    306 	mem[3] = 3;
    307 
    308 	bpf_args_t args = {
    309 		.pkt = pkt,
    310 		.buflen = sizeof(pkt),
    311 		.wirelen = sizeof(pkt),
    312 		.arg = arg,
    313 		.mem = mem,
    314 	};
    315 
    316 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    317 
    318 	RZ(rump_init());
    319 
    320 	rump_schedule();
    321 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    322 	rump_unschedule();
    323 	ATF_REQUIRE(code != NULL);
    324 
    325 	ATF_CHECK(code(&ctx, &args) == 13);
    326 
    327 	rump_schedule();
    328 	rumpns_bpfjit_free_code(code);
    329 	rump_unschedule();
    330 }
    331 
    332 ATF_TC(bpfjit_cop_ret_preinited_mem);
    333 ATF_TC_HEAD(bpfjit_cop_ret_preinited_mem, tc)
    334 {
    335 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
    336 	    "returns a content of external pre-initialized memory word");
    337 }
    338 
    339 ATF_TC_BODY(bpfjit_cop_ret_preinited_mem, tc)
    340 {
    341 	static struct bpf_insn insns[] = {
    342 		BPF_STMT(BPF_LD+BPF_IMM, 13),
    343 		BPF_STMT(BPF_ST, 2),
    344 		BPF_STMT(BPF_LD+BPF_IMM, 137),
    345 		BPF_STMT(BPF_ST, 1),
    346 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
    347 		BPF_STMT(BPF_RET+BPF_A, 0)
    348 	};
    349 
    350 	bpfjit_func_t code;
    351 	uint8_t pkt[1] = { 0 };
    352 	uint32_t mem[ctx.extwords];
    353 	void *arg = (void*)(uintptr_t)3;
    354 
    355 	/* Pre-inited words. */
    356 	mem[0] = 0;
    357 	mem[3] = 3;
    358 
    359 	bpf_args_t args = {
    360 		.pkt = pkt,
    361 		.buflen = sizeof(pkt),
    362 		.wirelen = sizeof(pkt),
    363 		.arg = arg,
    364 		.mem = mem,
    365 	};
    366 
    367 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    368 
    369 	RZ(rump_init());
    370 
    371 	rump_schedule();
    372 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    373 	rump_unschedule();
    374 	ATF_REQUIRE(code != NULL);
    375 
    376 	ATF_CHECK(code(&ctx, &args) == 3);
    377 
    378 	rump_schedule();
    379 	rumpns_bpfjit_free_code(code);
    380 	rump_unschedule();
    381 }
    382 
    383 ATF_TC(bpfjit_copx_ret_mem);
    384 ATF_TC_HEAD(bpfjit_copx_ret_mem, tc)
    385 {
    386 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
    387 	    "that returns a content of external memory word");
    388 }
    389 
    390 ATF_TC_BODY(bpfjit_copx_ret_mem, tc)
    391 {
    392 	static struct bpf_insn insns[] = {
    393 		BPF_STMT(BPF_LD+BPF_IMM, 13),
    394 		BPF_STMT(BPF_ST, 2),
    395 		BPF_STMT(BPF_LD+BPF_IMM, 137),
    396 		BPF_STMT(BPF_ST, 1),
    397 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
    398 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
    399 		BPF_STMT(BPF_RET+BPF_A, 0)
    400 	};
    401 
    402 	bpfjit_func_t code;
    403 	uint8_t pkt[1] = { 0 };
    404 	uint32_t mem[ctx.extwords];
    405 	void *arg = (void*)(uintptr_t)2;
    406 
    407 	/* Pre-inited words. */
    408 	mem[0] = 0;
    409 	mem[3] = 3;
    410 
    411 	bpf_args_t args = {
    412 		.pkt = pkt,
    413 		.buflen = sizeof(pkt),
    414 		.wirelen = sizeof(pkt),
    415 		.arg = arg,
    416 		.mem = mem,
    417 	};
    418 
    419 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    420 
    421 	RZ(rump_init());
    422 
    423 	rump_schedule();
    424 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    425 	rump_unschedule();
    426 	ATF_REQUIRE(code != NULL);
    427 
    428 	ATF_CHECK(code(&ctx, &args) == 13);
    429 
    430 	rump_schedule();
    431 	rumpns_bpfjit_free_code(code);
    432 	rump_unschedule();
    433 }
    434 
    435 ATF_TC(bpfjit_copx_ret_preinited_mem);
    436 ATF_TC_HEAD(bpfjit_copx_ret_preinited_mem, tc)
    437 {
    438 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
    439 	    "returns a content of external pre-initialized memory word");
    440 }
    441 
    442 ATF_TC_BODY(bpfjit_copx_ret_preinited_mem, tc)
    443 {
    444 	static struct bpf_insn insns[] = {
    445 		BPF_STMT(BPF_LD+BPF_IMM, 13),
    446 		BPF_STMT(BPF_ST, 2),
    447 		BPF_STMT(BPF_LD+BPF_IMM, 137),
    448 		BPF_STMT(BPF_ST, 1),
    449 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
    450 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
    451 		BPF_STMT(BPF_RET+BPF_A, 0)
    452 	};
    453 
    454 	bpfjit_func_t code;
    455 	uint8_t pkt[1] = { 0 };
    456 	uint32_t mem[ctx.extwords];
    457 	void *arg = (void*)(uintptr_t)3;
    458 
    459 	/* Pre-inited words. */
    460 	mem[0] = 0;
    461 	mem[3] = 3;
    462 
    463 	bpf_args_t args = {
    464 		.pkt = pkt,
    465 		.buflen = sizeof(pkt),
    466 		.wirelen = sizeof(pkt),
    467 		.arg = arg,
    468 		.mem = mem,
    469 	};
    470 
    471 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
    472 
    473 	RZ(rump_init());
    474 
    475 	rump_schedule();
    476 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
    477 	rump_unschedule();
    478 	ATF_REQUIRE(code != NULL);
    479 
    480 	ATF_CHECK(code(&ctx, &args) == 3);
    481 
    482 	rump_schedule();
    483 	rumpns_bpfjit_free_code(code);
    484 	rump_unschedule();
    485 }
    486 
    487 ATF_TP_ADD_TCS(tp)
    488 {
    489 
    490 	/*
    491 	 * For every new test please also add a similar test
    492 	 * to ../../lib/libbpfjit/t_extmem.c
    493 	 */
    494 	//ATF_TP_ADD_TC(tp, bpfjit_extmem_load_default);
    495 	ATF_TP_ADD_TC(tp, bpfjit_extmem_load_preinited);
    496 	ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_load);
    497 	ATF_TP_ADD_TC(tp, bpfjit_extmem_store);
    498 	ATF_TP_ADD_TC(tp, bpfjit_extmem_side_effect);
    499 	ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_store);
    500 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_mem);
    501 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_preinited_mem);
    502 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_mem);
    503 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_preinited_mem);
    504 
    505 	return atf_no_error();
    506 }
    507