]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/net/bpfjit/t_cop.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / net / bpfjit / t_cop.c
1 /*      $NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn 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_cop.c,v 1.3 2014/07/13 21:35:33 alnsn 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 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);
56
57 static const bpf_copfunc_t copfuncs[] = {
58         &retA,
59         &retBL,
60         &retWL,
61         &retNF,
62         &setARG
63 };
64
65 static const bpf_ctx_t ctx = {
66         .copfuncs = copfuncs,
67         .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
68         .extwords = 0
69 };
70
71 static uint32_t
72 retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
73 {
74
75         return A;
76 }
77
78 static uint32_t
79 retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
80 {
81
82         return args->buflen;
83 }
84
85 static uint32_t
86 retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
87 {
88
89         return args->wirelen;
90 }
91
92 static uint32_t
93 retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
94 {
95
96         return bc->nfuncs;
97 }
98
99 /*
100  * COP function with a side effect.
101  */
102 static uint32_t
103 setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
104 {
105         bool *arg = (bool *)args->arg;
106         bool old = *arg;
107
108         *arg = true;
109         return old;
110 }
111
112 ATF_TC(bpfjit_cop_no_ctx);
113 ATF_TC_HEAD(bpfjit_cop_no_ctx, tc)
114 {
115         atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
116             "instruction isn't valid without a context");
117 }
118
119 ATF_TC_BODY(bpfjit_cop_no_ctx, tc)
120 {
121         static struct bpf_insn insns[] = {
122                 BPF_STMT(BPF_MISC+BPF_COP, 0),
123                 BPF_STMT(BPF_RET+BPF_K, 7)
124         };
125
126         bpfjit_func_t code;
127
128         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
129
130         RZ(rump_init());
131
132         ATF_CHECK(!prog_validate(insns, insn_count));
133
134         rump_schedule();
135         code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
136         rump_unschedule();
137         ATF_CHECK(code == NULL);
138 }
139
140 ATF_TC(bpfjit_cop_ret_A);
141 ATF_TC_HEAD(bpfjit_cop_ret_A, tc)
142 {
143         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
144             "that returns a content of the A register");
145 }
146
147 ATF_TC_BODY(bpfjit_cop_ret_A, tc)
148 {
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)
153         };
154
155         bpfjit_func_t code;
156         uint8_t pkt[1] = { 0 };
157         bpf_args_t args = {
158                 .pkt = pkt,
159                 .buflen = sizeof(pkt),
160                 .wirelen = sizeof(pkt),
161         };
162
163         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
164
165         RZ(rump_init());
166
167         rump_schedule();
168         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
169         rump_unschedule();
170         ATF_REQUIRE(code != NULL);
171
172         ATF_CHECK(code(&ctx, &args) == 13);
173
174         rump_schedule();
175         rumpns_bpfjit_free_code(code);
176         rump_unschedule();
177 }
178
179 ATF_TC(bpfjit_cop_ret_buflen);
180 ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc)
181 {
182         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
183             "that returns the buflen argument");
184 }
185
186 ATF_TC_BODY(bpfjit_cop_ret_buflen, tc)
187 {
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)
192         };
193
194         bpfjit_func_t code;
195         uint8_t pkt[1] = { 0 };
196         bpf_args_t args = {
197                 .pkt = pkt,
198                 .buflen = sizeof(pkt),
199                 .wirelen = sizeof(pkt)
200         };
201
202         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
203
204         RZ(rump_init());
205
206         rump_schedule();
207         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
208         rump_unschedule();
209         ATF_REQUIRE(code != NULL);
210
211         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
212
213         rump_schedule();
214         rumpns_bpfjit_free_code(code);
215         rump_unschedule();
216 }
217
218 ATF_TC(bpfjit_cop_ret_wirelen);
219 ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc)
220 {
221         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
222             "that returns the wirelen argument");
223 }
224
225 ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc)
226 {
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)
231         };
232
233         bpfjit_func_t code;
234         uint8_t pkt[1] = { 0 };
235         bpf_args_t args = {
236                 .pkt = pkt,
237                 .buflen = sizeof(pkt),
238                 .wirelen = sizeof(pkt)
239         };
240
241         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
242
243         RZ(rump_init());
244
245         rump_schedule();
246         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
247         rump_unschedule();
248         ATF_REQUIRE(code != NULL);
249
250         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
251
252         rump_schedule();
253         rumpns_bpfjit_free_code(code);
254         rump_unschedule();
255 }
256
257 ATF_TC(bpfjit_cop_ret_nfuncs);
258 ATF_TC_HEAD(bpfjit_cop_ret_nfuncs, tc)
259 {
260         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
261             "that returns nfuncs member of the context argument");
262 }
263
264 ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc)
265 {
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)
270         };
271
272         bpfjit_func_t code;
273         uint8_t pkt[1] = { 0 };
274         bpf_args_t args = {
275                 .pkt = pkt,
276                 .buflen = sizeof(pkt),
277                 .wirelen = sizeof(pkt)
278         };
279
280         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
281
282         RZ(rump_init());
283
284         rump_schedule();
285         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
286         rump_unschedule();
287         ATF_REQUIRE(code != NULL);
288
289         ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
290
291         rump_schedule();
292         rumpns_bpfjit_free_code(code);
293         rump_unschedule();
294 }
295
296 ATF_TC(bpfjit_cop_side_effect);
297 ATF_TC_HEAD(bpfjit_cop_side_effect, tc)
298 {
299         atf_tc_set_md_var(tc, "descr",
300             "Test that ABC optimization doesn't skip BPF_COP call");
301 }
302
303 ATF_TC_BODY(bpfjit_cop_side_effect, tc)
304 {
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)
311         };
312
313         bpfjit_func_t code;
314         bool arg = false;
315         uint8_t pkt[1] = { 0 };
316         bpf_args_t args = {
317                 .pkt = pkt,
318                 .buflen = sizeof(pkt),
319                 .wirelen = sizeof(pkt),
320                 .mem = NULL,
321                 .arg = &arg
322         };
323
324         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
325
326         RZ(rump_init());
327
328         rump_schedule();
329         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
330         rump_unschedule();
331         ATF_REQUIRE(code != NULL);
332
333         ATF_CHECK(code(&ctx, &args) == 0);
334         ATF_CHECK(arg == true);
335
336         rump_schedule();
337         rumpns_bpfjit_free_code(code);
338         rump_unschedule();
339 }
340
341 ATF_TC(bpfjit_cop_copx);
342 ATF_TC_HEAD(bpfjit_cop_copx, tc)
343 {
344         atf_tc_set_md_var(tc, "descr",
345             "Test BPF_COP call followed by BPF_COPX call");
346 }
347
348 ATF_TC_BODY(bpfjit_cop_copx, tc)
349 {
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)
360         };
361
362         bpfjit_func_t code;
363         uint8_t pkt[1] = { 2 };
364         bpf_args_t args = {
365                 .pkt = pkt,
366                 .buflen = sizeof(pkt),
367                 .wirelen = sizeof(pkt),
368         };
369
370         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
371
372         RZ(rump_init());
373
374         rump_schedule();
375         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
376         rump_unschedule();
377         ATF_REQUIRE(code != NULL);
378
379         ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
380
381         rump_schedule();
382         rumpns_bpfjit_free_code(code);
383         rump_unschedule();
384 }
385
386 ATF_TC(bpfjit_cop_invalid_index);
387 ATF_TC_HEAD(bpfjit_cop_invalid_index, tc)
388 {
389         atf_tc_set_md_var(tc, "descr",
390             "Test that out-of-range coprocessor function fails validation");
391 }
392
393 ATF_TC_BODY(bpfjit_cop_invalid_index, tc)
394 {
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)
399         };
400
401         bpfjit_func_t code;
402         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
403
404         RZ(rump_init());
405
406         rump_schedule();
407         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
408         rump_unschedule();
409         ATF_CHECK(code == NULL);
410 }
411
412 ATF_TC(bpfjit_copx_no_ctx);
413 ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
414 {
415         atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
416             "instruction isn't valid without a context");
417 }
418
419 ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
420 {
421         static struct bpf_insn insns[] = {
422                 BPF_STMT(BPF_MISC+BPF_COP, 0),
423                 BPF_STMT(BPF_RET+BPF_K, 7)
424         };
425
426         bpfjit_func_t code;
427
428         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
429
430         RZ(rump_init());
431
432         ATF_CHECK(!prog_validate(insns, insn_count));
433
434         rump_schedule();
435         code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
436         rump_unschedule();
437         ATF_CHECK(code == NULL);
438 }
439
440 ATF_TC(bpfjit_copx_ret_A);
441 ATF_TC_HEAD(bpfjit_copx_ret_A, tc)
442 {
443         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
444             "that returns a content of the A register");
445 }
446
447 ATF_TC_BODY(bpfjit_copx_ret_A, tc)
448 {
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)
454         };
455
456         bpfjit_func_t code;
457         uint8_t pkt[1] = { 0 };
458         bpf_args_t args = {
459                 .pkt = pkt,
460                 .buflen = sizeof(pkt),
461                 .wirelen = sizeof(pkt),
462         };
463
464         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
465
466         RZ(rump_init());
467
468         rump_schedule();
469         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
470         rump_unschedule();
471         ATF_REQUIRE(code != NULL);
472
473         ATF_CHECK(code(&ctx, &args) == 13);
474
475         rump_schedule();
476         rumpns_bpfjit_free_code(code);
477         rump_unschedule();
478 }
479
480 ATF_TC(bpfjit_copx_ret_buflen);
481 ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc)
482 {
483         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
484             "that returns the buflen argument");
485 }
486
487 ATF_TC_BODY(bpfjit_copx_ret_buflen, tc)
488 {
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)
494         };
495
496         bpfjit_func_t code;
497         uint8_t pkt[1] = { 0 };
498         bpf_args_t args = {
499                 .pkt = pkt,
500                 .buflen = sizeof(pkt),
501                 .wirelen = sizeof(pkt)
502         };
503
504         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
505
506         RZ(rump_init());
507
508         rump_schedule();
509         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
510         rump_unschedule();
511         ATF_REQUIRE(code != NULL);
512
513         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
514
515         rump_schedule();
516         rumpns_bpfjit_free_code(code);
517         rump_unschedule();
518 }
519
520 ATF_TC(bpfjit_copx_ret_wirelen);
521 ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc)
522 {
523         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
524             "that returns the wirelen argument");
525 }
526
527 ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc)
528 {
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)
534         };
535
536         bpfjit_func_t code;
537         uint8_t pkt[1] = { 0 };
538         bpf_args_t args = {
539                 .pkt = pkt,
540                 .buflen = sizeof(pkt),
541                 .wirelen = sizeof(pkt)
542         };
543
544         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
545
546         RZ(rump_init());
547
548         rump_schedule();
549         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
550         rump_unschedule();
551         ATF_REQUIRE(code != NULL);
552
553         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
554
555         rump_schedule();
556         rumpns_bpfjit_free_code(code);
557         rump_unschedule();
558 }
559
560 ATF_TC(bpfjit_copx_ret_nfuncs);
561 ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc)
562 {
563         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
564             "that returns nfuncs member of the context argument");
565 }
566
567 ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc)
568 {
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)
574         };
575
576         bpfjit_func_t code;
577         uint8_t pkt[1] = { 0 };
578         bpf_args_t args = {
579                 .pkt = pkt,
580                 .buflen = sizeof(pkt),
581                 .wirelen = sizeof(pkt)
582         };
583
584         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
585
586         RZ(rump_init());
587
588         rump_schedule();
589         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
590         rump_unschedule();
591         ATF_REQUIRE(code != NULL);
592
593         ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
594
595         rump_schedule();
596         rumpns_bpfjit_free_code(code);
597         rump_unschedule();
598 }
599
600 ATF_TC(bpfjit_copx_side_effect);
601 ATF_TC_HEAD(bpfjit_copx_side_effect, tc)
602 {
603         atf_tc_set_md_var(tc, "descr",
604             "Test that ABC optimization doesn't skip BPF_COPX call");
605 }
606
607 ATF_TC_BODY(bpfjit_copx_side_effect, tc)
608 {
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)
616         };
617
618         bpfjit_func_t code;
619         bool arg = false;
620         uint8_t pkt[1] = { 0 };
621         bpf_args_t args = {
622                 .pkt = pkt,
623                 .buflen = sizeof(pkt),
624                 .wirelen = sizeof(pkt),
625                 .mem = NULL,
626                 .arg = &arg
627         };
628
629         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
630
631         RZ(rump_init());
632
633         rump_schedule();
634         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
635         rump_unschedule();
636         ATF_REQUIRE(code != NULL);
637
638         ATF_CHECK(code(&ctx, &args) == 0);
639         ATF_CHECK(arg == true);
640
641         rump_schedule();
642         rumpns_bpfjit_free_code(code);
643         rump_unschedule();
644 }
645
646 ATF_TC(bpfjit_copx_cop);
647 ATF_TC_HEAD(bpfjit_copx_cop, tc)
648 {
649         atf_tc_set_md_var(tc, "descr",
650             "Test BPF_COPX call followed by BPF_COP call");
651 }
652
653 ATF_TC_BODY(bpfjit_copx_cop, tc)
654 {
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)
666         };
667
668         bpfjit_func_t code;
669         uint8_t pkt[1] = { 2 };
670         bpf_args_t args = {
671                 .pkt = pkt,
672                 .buflen = sizeof(pkt),
673                 .wirelen = sizeof(pkt),
674         };
675
676         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
677
678         RZ(rump_init());
679
680         rump_schedule();
681         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
682         rump_unschedule();
683         ATF_REQUIRE(code != NULL);
684
685         ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
686
687         rump_schedule();
688         rumpns_bpfjit_free_code(code);
689         rump_unschedule();
690 }
691
692 ATF_TC(bpfjit_copx_invalid_index);
693 ATF_TC_HEAD(bpfjit_copx_invalid_index, tc)
694 {
695         atf_tc_set_md_var(tc, "descr",
696             "Test that out-of-range BPF_COPX call fails at runtime");
697 }
698
699 ATF_TC_BODY(bpfjit_copx_invalid_index, tc)
700 {
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)
705         };
706
707         bpfjit_func_t code;
708         uint8_t pkt[1] = { 0 };
709         bpf_args_t args = {
710                 .pkt = pkt,
711                 .buflen = sizeof(pkt),
712                 .wirelen = sizeof(pkt)
713         };
714
715         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
716
717         RZ(rump_init());
718
719         rump_schedule();
720         code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
721         rump_unschedule();
722         ATF_REQUIRE(code != NULL);
723
724         ATF_CHECK(code(&ctx, &args) == 0);
725
726         rump_schedule();
727         rumpns_bpfjit_free_code(code);
728         rump_unschedule();
729 }
730
731 ATF_TP_ADD_TCS(tp)
732 {
733
734         /*
735          * For every new test please also add a similar test
736          * to ../../lib/libbpfjit/t_cop.c
737          */
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);
746
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);
755
756         return atf_no_error();
757 }