1 /* $NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $ */
4 * Copyright (c) 2013-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 2014/07/13 21:35:33 alnsn Exp $");
41 #include <net/bpfjit.h>
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
);
49 static const bpf_copfunc_t copfuncs
[] = {
57 static const bpf_ctx_t ctx
= {
59 .nfuncs
= sizeof(copfuncs
) / sizeof(copfuncs
[0]),
64 retA(const bpf_ctx_t
*bc
, bpf_args_t
*args
, uint32_t A
)
71 retBL(const bpf_ctx_t
*bc
, bpf_args_t
*args
, uint32_t A
)
78 retWL(const bpf_ctx_t
*bc
, bpf_args_t
*args
, uint32_t A
)
85 retNF(const bpf_ctx_t
*bc
, bpf_args_t
*args
, uint32_t A
)
92 * COP function with a side effect.
95 setARG(const bpf_ctx_t
*bc
, bpf_args_t
*args
, uint32_t A
)
97 bool *arg
= (bool *)args
->arg
;
104 ATF_TC(libbpfjit_cop_no_ctx
);
105 ATF_TC_HEAD(libbpfjit_cop_no_ctx
, tc
)
107 atf_tc_set_md_var(tc
, "descr", "Test that bpf program with BPF_COP "
108 "instruction isn't valid without a context");
111 ATF_TC_BODY(libbpfjit_cop_no_ctx
, tc
)
113 static struct bpf_insn insns
[] = {
114 BPF_STMT(BPF_MISC
+BPF_COP
, 0),
115 BPF_STMT(BPF_RET
+BPF_K
, 7)
120 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
122 ATF_CHECK(!bpf_validate(insns
, insn_count
));
124 code
= bpfjit_generate_code(NULL
, insns
, insn_count
);
125 ATF_CHECK(code
== NULL
);
128 ATF_TC(libbpfjit_cop_ret_A
);
129 ATF_TC_HEAD(libbpfjit_cop_ret_A
, tc
)
131 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
132 "that returns a content of the A register");
135 ATF_TC_BODY(libbpfjit_cop_ret_A
, tc
)
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)
144 uint8_t pkt
[1] = { 0 };
147 .buflen
= sizeof(pkt
),
148 .wirelen
= sizeof(pkt
),
151 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
153 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
154 ATF_REQUIRE(code
!= NULL
);
156 ATF_CHECK(code(&ctx
, &args
) == 13);
158 bpfjit_free_code(code
);
161 ATF_TC(libbpfjit_cop_ret_buflen
);
162 ATF_TC_HEAD(libbpfjit_cop_ret_buflen
, tc
)
164 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
165 "that returns the buflen argument");
168 ATF_TC_BODY(libbpfjit_cop_ret_buflen
, tc
)
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)
177 uint8_t pkt
[1] = { 0 };
180 .buflen
= sizeof(pkt
),
181 .wirelen
= sizeof(pkt
)
184 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
186 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
187 ATF_REQUIRE(code
!= NULL
);
189 ATF_CHECK(code(&ctx
, &args
) == sizeof(pkt
));
191 bpfjit_free_code(code
);
194 ATF_TC(libbpfjit_cop_ret_wirelen
);
195 ATF_TC_HEAD(libbpfjit_cop_ret_wirelen
, tc
)
197 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
198 "that returns the wirelen argument");
201 ATF_TC_BODY(libbpfjit_cop_ret_wirelen
, tc
)
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)
210 uint8_t pkt
[1] = { 0 };
213 .buflen
= sizeof(pkt
),
214 .wirelen
= sizeof(pkt
)
217 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
219 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
220 ATF_REQUIRE(code
!= NULL
);
222 ATF_CHECK(code(&ctx
, &args
) == sizeof(pkt
));
224 bpfjit_free_code(code
);
227 ATF_TC(libbpfjit_cop_ret_nfuncs
);
228 ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs
, tc
)
230 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
231 "that returns nfuncs member of the context argument");
234 ATF_TC_BODY(libbpfjit_cop_ret_nfuncs
, tc
)
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)
243 uint8_t pkt
[1] = { 0 };
246 .buflen
= sizeof(pkt
),
247 .wirelen
= sizeof(pkt
)
250 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
252 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
253 ATF_REQUIRE(code
!= NULL
);
255 ATF_CHECK(code(&ctx
, &args
) == ctx
.nfuncs
);
257 bpfjit_free_code(code
);
260 ATF_TC(libbpfjit_cop_side_effect
);
261 ATF_TC_HEAD(libbpfjit_cop_side_effect
, tc
)
263 atf_tc_set_md_var(tc
, "descr",
264 "Test that ABC optimization doesn't skip BPF_COP call");
267 ATF_TC_BODY(libbpfjit_cop_side_effect
, tc
)
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)
279 uint8_t pkt
[1] = { 0 };
282 .buflen
= sizeof(pkt
),
283 .wirelen
= sizeof(pkt
),
288 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
290 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
291 ATF_REQUIRE(code
!= NULL
);
293 ATF_CHECK(code(&ctx
, &args
) == 0);
294 ATF_CHECK(arg
== true);
296 bpfjit_free_code(code
);
299 ATF_TC(libbpfjit_cop_copx
);
300 ATF_TC_HEAD(libbpfjit_cop_copx
, tc
)
302 atf_tc_set_md_var(tc
, "descr",
303 "Test BPF_COP call followed by BPF_COPX call");
306 ATF_TC_BODY(libbpfjit_cop_copx
, tc
)
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)
321 uint8_t pkt
[1] = { 2 };
324 .buflen
= sizeof(pkt
),
325 .wirelen
= sizeof(pkt
),
328 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
330 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
331 ATF_REQUIRE(code
!= NULL
);
333 ATF_CHECK(code(&ctx
, &args
) == 3 + ctx
.nfuncs
);
335 bpfjit_free_code(code
);
338 ATF_TC(libbpfjit_cop_invalid_index
);
339 ATF_TC_HEAD(libbpfjit_cop_invalid_index
, tc
)
341 atf_tc_set_md_var(tc
, "descr",
342 "Test that out-of-range coprocessor function fails validation");
345 ATF_TC_BODY(libbpfjit_cop_invalid_index
, tc
)
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)
353 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
355 ATF_CHECK(bpfjit_generate_code(&ctx
, insns
, insn_count
) == NULL
);
358 ATF_TC(libbpfjit_copx_no_ctx
);
359 ATF_TC_HEAD(libbpfjit_copx_no_ctx
, tc
)
361 atf_tc_set_md_var(tc
, "descr", "Test that bpf program with BPF_COPX "
362 "instruction isn't valid without a context");
365 ATF_TC_BODY(libbpfjit_copx_no_ctx
, tc
)
367 static struct bpf_insn insns
[] = {
368 BPF_STMT(BPF_MISC
+BPF_COP
, 0),
369 BPF_STMT(BPF_RET
+BPF_K
, 7)
374 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
376 ATF_CHECK(!bpf_validate(insns
, insn_count
));
378 code
= bpfjit_generate_code(NULL
, insns
, insn_count
);
379 ATF_CHECK(code
== NULL
);
382 ATF_TC(libbpfjit_copx_ret_A
);
383 ATF_TC_HEAD(libbpfjit_copx_ret_A
, tc
)
385 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
386 "that returns a content of the A register");
389 ATF_TC_BODY(libbpfjit_copx_ret_A
, tc
)
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)
399 uint8_t pkt
[1] = { 0 };
402 .buflen
= sizeof(pkt
),
403 .wirelen
= sizeof(pkt
),
406 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
408 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
409 ATF_REQUIRE(code
!= NULL
);
411 ATF_CHECK(code(&ctx
, &args
) == 13);
413 bpfjit_free_code(code
);
416 ATF_TC(libbpfjit_copx_ret_buflen
);
417 ATF_TC_HEAD(libbpfjit_copx_ret_buflen
, tc
)
419 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
420 "that returns the buflen argument");
423 ATF_TC_BODY(libbpfjit_copx_ret_buflen
, tc
)
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)
433 uint8_t pkt
[1] = { 0 };
436 .buflen
= sizeof(pkt
),
437 .wirelen
= sizeof(pkt
)
440 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
442 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
443 ATF_REQUIRE(code
!= NULL
);
445 ATF_CHECK(code(&ctx
, &args
) == sizeof(pkt
));
447 bpfjit_free_code(code
);
450 ATF_TC(libbpfjit_copx_ret_wirelen
);
451 ATF_TC_HEAD(libbpfjit_copx_ret_wirelen
, tc
)
453 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
454 "that returns the wirelen argument");
457 ATF_TC_BODY(libbpfjit_copx_ret_wirelen
, tc
)
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)
467 uint8_t pkt
[1] = { 0 };
470 .buflen
= sizeof(pkt
),
471 .wirelen
= sizeof(pkt
)
474 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
476 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
477 ATF_REQUIRE(code
!= NULL
);
479 ATF_CHECK(code(&ctx
, &args
) == sizeof(pkt
));
481 bpfjit_free_code(code
);
484 ATF_TC(libbpfjit_copx_ret_nfuncs
);
485 ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs
, tc
)
487 atf_tc_set_md_var(tc
, "descr", "Test coprocessor function "
488 "that returns nfuncs member of the context argument");
491 ATF_TC_BODY(libbpfjit_copx_ret_nfuncs
, tc
)
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)
501 uint8_t pkt
[1] = { 0 };
504 .buflen
= sizeof(pkt
),
505 .wirelen
= sizeof(pkt
)
508 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
510 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
511 ATF_REQUIRE(code
!= NULL
);
513 ATF_CHECK(code(&ctx
, &args
) == ctx
.nfuncs
);
515 bpfjit_free_code(code
);
518 ATF_TC(libbpfjit_copx_side_effect
);
519 ATF_TC_HEAD(libbpfjit_copx_side_effect
, tc
)
521 atf_tc_set_md_var(tc
, "descr",
522 "Test that ABC optimization doesn't skip BPF_COPX call");
525 ATF_TC_BODY(libbpfjit_copx_side_effect
, tc
)
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)
538 uint8_t pkt
[1] = { 0 };
541 .buflen
= sizeof(pkt
),
542 .wirelen
= sizeof(pkt
),
547 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
549 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
550 ATF_REQUIRE(code
!= NULL
);
552 ATF_CHECK(code(&ctx
, &args
) == 0);
553 ATF_CHECK(arg
== true);
555 bpfjit_free_code(code
);
558 ATF_TC(libbpfjit_copx_cop
);
559 ATF_TC_HEAD(libbpfjit_copx_cop
, tc
)
561 atf_tc_set_md_var(tc
, "descr",
562 "Test BPF_COPX call followed by BPF_COP call");
565 ATF_TC_BODY(libbpfjit_copx_cop
, tc
)
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)
581 uint8_t pkt
[1] = { 2 };
584 .buflen
= sizeof(pkt
),
585 .wirelen
= sizeof(pkt
),
588 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
590 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
591 ATF_REQUIRE(code
!= NULL
);
593 ATF_CHECK(code(&ctx
, &args
) == 5 + ctx
.nfuncs
);
595 bpfjit_free_code(code
);
598 ATF_TC(libbpfjit_copx_invalid_index
);
599 ATF_TC_HEAD(libbpfjit_copx_invalid_index
, tc
)
601 atf_tc_set_md_var(tc
, "descr",
602 "Test that out-of-range BPF_COPX call fails at runtime");
605 ATF_TC_BODY(libbpfjit_copx_invalid_index
, tc
)
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)
614 uint8_t pkt
[1] = { 0 };
617 .buflen
= sizeof(pkt
),
618 .wirelen
= sizeof(pkt
)
621 size_t insn_count
= sizeof(insns
) / sizeof(insns
[0]);
623 code
= bpfjit_generate_code(&ctx
, insns
, insn_count
);
624 ATF_REQUIRE(code
!= NULL
);
626 ATF_CHECK(code(&ctx
, &args
) == 0);
628 bpfjit_free_code(code
);
635 * For every new test please also add a similar test
636 * to ../../net/bpfjit/t_cop.c
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
);
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
);
656 return atf_no_error();