1 /* $NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn 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.3 2014/07/13 21:35:33 alnsn Exp $");
40 #include <net/bpfjit.h>
42 #include "../../net/bpf/h_bpf.h"
44 /* XXX: atf-c.h has collisions with mbuf */
49 #include "../../h_macros.h"
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();