1 /* $NetBSD: t_cop.c,v 1.4 2017/01/13 21:30:42 christos Exp $ */
4 * Copyright (c) 2014 Alexander Nasonov.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_cop.c,v 1.4 2017/01/13 21:30:42 christos Exp $");
40 #include <net/bpfjit.h>
42 #include "../../net/bpf/h_bpf.h"
44 /* XXX: atf-c.h has collisions with mbuf */
51 static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
52 static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
53 static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
54 static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
55 static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
57 static const bpf_copfunc_t copfuncs[] = {
65 static const bpf_ctx_t ctx = {
67 .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
72 retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
79 retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
86 retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
93 retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
100 * COP function with a side effect.
103 setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
105 bool *arg = (bool *)args->arg;
112 ATF_TC(bpfjit_cop_no_ctx);
113 ATF_TC_HEAD(bpfjit_cop_no_ctx, tc)
115 atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
116 "instruction isn't valid without a context");
119 ATF_TC_BODY(bpfjit_cop_no_ctx, tc)
121 static struct bpf_insn insns[] = {
122 BPF_STMT(BPF_MISC+BPF_COP, 0),
123 BPF_STMT(BPF_RET+BPF_K, 7)
128 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
132 ATF_CHECK(!prog_validate(insns, insn_count));
135 code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
137 ATF_CHECK(code == NULL);
140 ATF_TC(bpfjit_cop_ret_A);
141 ATF_TC_HEAD(bpfjit_cop_ret_A, tc)
143 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
144 "that returns a content of the A register");
147 ATF_TC_BODY(bpfjit_cop_ret_A, tc)
149 static struct bpf_insn insns[] = {
150 BPF_STMT(BPF_LD+BPF_IMM, 13),
151 BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
152 BPF_STMT(BPF_RET+BPF_A, 0)
156 uint8_t pkt[1] = { 0 };
159 .buflen = sizeof(pkt),
160 .wirelen = sizeof(pkt),
163 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
168 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
170 ATF_REQUIRE(code != NULL);
172 ATF_CHECK(code(&ctx, &args) == 13);
175 rumpns_bpfjit_free_code(code);
179 ATF_TC(bpfjit_cop_ret_buflen);
180 ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc)
182 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
183 "that returns the buflen argument");
186 ATF_TC_BODY(bpfjit_cop_ret_buflen, tc)
188 static struct bpf_insn insns[] = {
189 BPF_STMT(BPF_LD+BPF_IMM, 13),
190 BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
191 BPF_STMT(BPF_RET+BPF_A, 0)
195 uint8_t pkt[1] = { 0 };
198 .buflen = sizeof(pkt),
199 .wirelen = sizeof(pkt)
202 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
207 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
209 ATF_REQUIRE(code != NULL);
211 ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
214 rumpns_bpfjit_free_code(code);
218 ATF_TC(bpfjit_cop_ret_wirelen);
219 ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc)
221 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
222 "that returns the wirelen argument");
225 ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc)
227 static struct bpf_insn insns[] = {
228 BPF_STMT(BPF_LD+BPF_IMM, 13),
229 BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
230 BPF_STMT(BPF_RET+BPF_A, 0)
234 uint8_t pkt[1] = { 0 };
237 .buflen = sizeof(pkt),
238 .wirelen = sizeof(pkt)
241 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
246 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
248 ATF_REQUIRE(code != NULL);
250 ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
253 rumpns_bpfjit_free_code(code);
257 ATF_TC(bpfjit_cop_ret_nfuncs);
258 ATF_TC_HEAD(bpfjit_cop_ret_nfuncs, tc)
260 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
261 "that returns nfuncs member of the context argument");
264 ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc)
266 static struct bpf_insn insns[] = {
267 BPF_STMT(BPF_LD+BPF_IMM, 13),
268 BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
269 BPF_STMT(BPF_RET+BPF_A, 0)
273 uint8_t pkt[1] = { 0 };
276 .buflen = sizeof(pkt),
277 .wirelen = sizeof(pkt)
280 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
285 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
287 ATF_REQUIRE(code != NULL);
289 ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
292 rumpns_bpfjit_free_code(code);
296 ATF_TC(bpfjit_cop_side_effect);
297 ATF_TC_HEAD(bpfjit_cop_side_effect, tc)
299 atf_tc_set_md_var(tc, "descr",
300 "Test that ABC optimization doesn't skip BPF_COP call");
303 ATF_TC_BODY(bpfjit_cop_side_effect, tc)
305 static struct bpf_insn insns[] = {
306 BPF_STMT(BPF_LD+BPF_IMM, 13),
307 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
308 BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
309 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
310 BPF_STMT(BPF_RET+BPF_A, 0)
315 uint8_t pkt[1] = { 0 };
318 .buflen = sizeof(pkt),
319 .wirelen = sizeof(pkt),
324 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
329 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
331 ATF_REQUIRE(code != NULL);
333 ATF_CHECK(code(&ctx, &args) == 0);
334 ATF_CHECK(arg == true);
337 rumpns_bpfjit_free_code(code);
341 ATF_TC(bpfjit_cop_copx);
342 ATF_TC_HEAD(bpfjit_cop_copx, tc)
344 atf_tc_set_md_var(tc, "descr",
345 "Test BPF_COP call followed by BPF_COPX call");
348 ATF_TC_BODY(bpfjit_cop_copx, tc)
350 static struct bpf_insn insns[] = {
351 BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */
352 BPF_STMT(BPF_MISC+BPF_COP, 0), /* retA */
353 BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
354 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */
355 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
356 BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
357 BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retNF */
358 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
359 BPF_STMT(BPF_RET+BPF_A, 0)
363 uint8_t pkt[1] = { 2 };
366 .buflen = sizeof(pkt),
367 .wirelen = sizeof(pkt),
370 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
375 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
377 ATF_REQUIRE(code != NULL);
379 ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
382 rumpns_bpfjit_free_code(code);
386 ATF_TC(bpfjit_cop_invalid_index);
387 ATF_TC_HEAD(bpfjit_cop_invalid_index, tc)
389 atf_tc_set_md_var(tc, "descr",
390 "Test that out-of-range coprocessor function fails validation");
393 ATF_TC_BODY(bpfjit_cop_invalid_index, tc)
395 static struct bpf_insn insns[] = {
396 BPF_STMT(BPF_LD+BPF_IMM, 13),
397 BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
398 BPF_STMT(BPF_RET+BPF_K, 27)
402 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
407 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
409 ATF_CHECK(code == NULL);
412 ATF_TC(bpfjit_copx_no_ctx);
413 ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
415 atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
416 "instruction isn't valid without a context");
419 ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
421 static struct bpf_insn insns[] = {
422 BPF_STMT(BPF_MISC+BPF_COP, 0),
423 BPF_STMT(BPF_RET+BPF_K, 7)
428 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
432 ATF_CHECK(!prog_validate(insns, insn_count));
435 code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
437 ATF_CHECK(code == NULL);
440 ATF_TC(bpfjit_copx_ret_A);
441 ATF_TC_HEAD(bpfjit_copx_ret_A, tc)
443 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
444 "that returns a content of the A register");
447 ATF_TC_BODY(bpfjit_copx_ret_A, tc)
449 static struct bpf_insn insns[] = {
450 BPF_STMT(BPF_LD+BPF_IMM, 13),
451 BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
452 BPF_STMT(BPF_MISC+BPF_COPX, 0),
453 BPF_STMT(BPF_RET+BPF_A, 0)
457 uint8_t pkt[1] = { 0 };
460 .buflen = sizeof(pkt),
461 .wirelen = sizeof(pkt),
464 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
469 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
471 ATF_REQUIRE(code != NULL);
473 ATF_CHECK(code(&ctx, &args) == 13);
476 rumpns_bpfjit_free_code(code);
480 ATF_TC(bpfjit_copx_ret_buflen);
481 ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc)
483 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
484 "that returns the buflen argument");
487 ATF_TC_BODY(bpfjit_copx_ret_buflen, tc)
489 static struct bpf_insn insns[] = {
490 BPF_STMT(BPF_LD+BPF_IMM, 13),
491 BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
492 BPF_STMT(BPF_MISC+BPF_COPX, 0),
493 BPF_STMT(BPF_RET+BPF_A, 0)
497 uint8_t pkt[1] = { 0 };
500 .buflen = sizeof(pkt),
501 .wirelen = sizeof(pkt)
504 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
509 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
511 ATF_REQUIRE(code != NULL);
513 ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
516 rumpns_bpfjit_free_code(code);
520 ATF_TC(bpfjit_copx_ret_wirelen);
521 ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc)
523 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
524 "that returns the wirelen argument");
527 ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc)
529 static struct bpf_insn insns[] = {
530 BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
531 BPF_STMT(BPF_LD+BPF_IMM, 13),
532 BPF_STMT(BPF_MISC+BPF_COPX, 0),
533 BPF_STMT(BPF_RET+BPF_A, 0)
537 uint8_t pkt[1] = { 0 };
540 .buflen = sizeof(pkt),
541 .wirelen = sizeof(pkt)
544 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
549 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
551 ATF_REQUIRE(code != NULL);
553 ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
556 rumpns_bpfjit_free_code(code);
560 ATF_TC(bpfjit_copx_ret_nfuncs);
561 ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc)
563 atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
564 "that returns nfuncs member of the context argument");
567 ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc)
569 static struct bpf_insn insns[] = {
570 BPF_STMT(BPF_LD+BPF_IMM, 13),
571 BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
572 BPF_STMT(BPF_MISC+BPF_COPX, 0),
573 BPF_STMT(BPF_RET+BPF_A, 0)
577 uint8_t pkt[1] = { 0 };
580 .buflen = sizeof(pkt),
581 .wirelen = sizeof(pkt)
584 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
589 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
591 ATF_REQUIRE(code != NULL);
593 ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
596 rumpns_bpfjit_free_code(code);
600 ATF_TC(bpfjit_copx_side_effect);
601 ATF_TC_HEAD(bpfjit_copx_side_effect, tc)
603 atf_tc_set_md_var(tc, "descr",
604 "Test that ABC optimization doesn't skip BPF_COPX call");
607 ATF_TC_BODY(bpfjit_copx_side_effect, tc)
609 static struct bpf_insn insns[] = {
610 BPF_STMT(BPF_LD+BPF_IMM, 13),
611 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
612 BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
613 BPF_STMT(BPF_MISC+BPF_COPX, 0),
614 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
615 BPF_STMT(BPF_RET+BPF_A, 0)
620 uint8_t pkt[1] = { 0 };
623 .buflen = sizeof(pkt),
624 .wirelen = sizeof(pkt),
629 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
634 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
636 ATF_REQUIRE(code != NULL);
638 ATF_CHECK(code(&ctx, &args) == 0);
639 ATF_CHECK(arg == true);
642 rumpns_bpfjit_free_code(code);
646 ATF_TC(bpfjit_copx_cop);
647 ATF_TC_HEAD(bpfjit_copx_cop, tc)
649 atf_tc_set_md_var(tc, "descr",
650 "Test BPF_COPX call followed by BPF_COP call");
653 ATF_TC_BODY(bpfjit_copx_cop, tc)
655 static struct bpf_insn insns[] = {
656 BPF_STMT(BPF_LDX+BPF_IMM, 2), /* X <- 2 */
657 BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retWL */
658 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
659 BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
660 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */
661 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
662 BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
663 BPF_STMT(BPF_MISC+BPF_COP, 3), /* retNF */
664 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
665 BPF_STMT(BPF_RET+BPF_A, 0)
669 uint8_t pkt[1] = { 2 };
672 .buflen = sizeof(pkt),
673 .wirelen = sizeof(pkt),
676 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
681 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
683 ATF_REQUIRE(code != NULL);
685 ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
688 rumpns_bpfjit_free_code(code);
692 ATF_TC(bpfjit_copx_invalid_index);
693 ATF_TC_HEAD(bpfjit_copx_invalid_index, tc)
695 atf_tc_set_md_var(tc, "descr",
696 "Test that out-of-range BPF_COPX call fails at runtime");
699 ATF_TC_BODY(bpfjit_copx_invalid_index, tc)
701 static struct bpf_insn insns[] = {
702 BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
703 BPF_STMT(BPF_MISC+BPF_COPX, 0),
704 BPF_STMT(BPF_RET+BPF_K, 27)
708 uint8_t pkt[1] = { 0 };
711 .buflen = sizeof(pkt),
712 .wirelen = sizeof(pkt)
715 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
720 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
722 ATF_REQUIRE(code != NULL);
724 ATF_CHECK(code(&ctx, &args) == 0);
727 rumpns_bpfjit_free_code(code);
735 * For every new test please also add a similar test
736 * to ../../lib/libbpfjit/t_cop.c
738 ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx);
739 ATF_TP_ADD_TC(tp, bpfjit_cop_ret_A);
740 ATF_TP_ADD_TC(tp, bpfjit_cop_ret_buflen);
741 ATF_TP_ADD_TC(tp, bpfjit_cop_ret_wirelen);
742 ATF_TP_ADD_TC(tp, bpfjit_cop_ret_nfuncs);
743 ATF_TP_ADD_TC(tp, bpfjit_cop_side_effect);
744 ATF_TP_ADD_TC(tp, bpfjit_cop_copx);
745 ATF_TP_ADD_TC(tp, bpfjit_cop_invalid_index);
747 ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx);
748 ATF_TP_ADD_TC(tp, bpfjit_copx_ret_A);
749 ATF_TP_ADD_TC(tp, bpfjit_copx_ret_buflen);
750 ATF_TP_ADD_TC(tp, bpfjit_copx_ret_wirelen);
751 ATF_TP_ADD_TC(tp, bpfjit_copx_ret_nfuncs);
752 ATF_TP_ADD_TC(tp, bpfjit_copx_side_effect);
753 ATF_TP_ADD_TC(tp, bpfjit_copx_cop);
754 ATF_TP_ADD_TC(tp, bpfjit_copx_invalid_index);
756 return atf_no_error();