t_cop.c revision 1.3 1 1.3 alnsn /* $NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn Exp $ */
2 1.1 alnsn
3 1.1 alnsn /*-
4 1.1 alnsn * Copyright (c) 2014 Alexander Nasonov.
5 1.1 alnsn * All rights reserved.
6 1.1 alnsn *
7 1.1 alnsn * Redistribution and use in source and binary forms, with or without
8 1.1 alnsn * modification, are permitted provided that the following conditions
9 1.1 alnsn * are met:
10 1.1 alnsn *
11 1.1 alnsn * 1. Redistributions of source code must retain the above copyright
12 1.1 alnsn * notice, this list of conditions and the following disclaimer.
13 1.1 alnsn * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 alnsn * notice, this list of conditions and the following disclaimer in
15 1.1 alnsn * the documentation and/or other materials provided with the
16 1.1 alnsn * distribution.
17 1.1 alnsn *
18 1.1 alnsn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 1.1 alnsn * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 1.1 alnsn * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 1.1 alnsn * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 1.1 alnsn * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 1.1 alnsn * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 1.1 alnsn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 1.1 alnsn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 1.1 alnsn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 1.1 alnsn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 1.1 alnsn * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 alnsn * SUCH DAMAGE.
30 1.1 alnsn */
31 1.1 alnsn
32 1.1 alnsn #include <sys/cdefs.h>
33 1.3 alnsn __RCSID("$NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn Exp $");
34 1.1 alnsn
35 1.1 alnsn #include <stdint.h>
36 1.1 alnsn #include <string.h>
37 1.1 alnsn
38 1.1 alnsn #define __BPF_PRIVATE
39 1.1 alnsn #include <net/bpf.h>
40 1.1 alnsn #include <net/bpfjit.h>
41 1.1 alnsn
42 1.1 alnsn #include "../../net/bpf/h_bpf.h"
43 1.1 alnsn
44 1.1 alnsn /* XXX: atf-c.h has collisions with mbuf */
45 1.1 alnsn #undef m_type
46 1.1 alnsn #undef m_data
47 1.1 alnsn #include <atf-c.h>
48 1.1 alnsn
49 1.1 alnsn #include "../../h_macros.h"
50 1.1 alnsn
51 1.1 alnsn static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
52 1.1 alnsn static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
53 1.1 alnsn static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
54 1.1 alnsn static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
55 1.1 alnsn static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
56 1.1 alnsn
57 1.1 alnsn static const bpf_copfunc_t copfuncs[] = {
58 1.1 alnsn &retA,
59 1.1 alnsn &retBL,
60 1.1 alnsn &retWL,
61 1.1 alnsn &retNF,
62 1.1 alnsn &setARG
63 1.1 alnsn };
64 1.1 alnsn
65 1.1 alnsn static const bpf_ctx_t ctx = {
66 1.1 alnsn .copfuncs = copfuncs,
67 1.1 alnsn .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
68 1.1 alnsn .extwords = 0
69 1.1 alnsn };
70 1.1 alnsn
71 1.1 alnsn static uint32_t
72 1.1 alnsn retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
73 1.1 alnsn {
74 1.1 alnsn
75 1.1 alnsn return A;
76 1.1 alnsn }
77 1.1 alnsn
78 1.1 alnsn static uint32_t
79 1.1 alnsn retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
80 1.1 alnsn {
81 1.1 alnsn
82 1.1 alnsn return args->buflen;
83 1.1 alnsn }
84 1.1 alnsn
85 1.1 alnsn static uint32_t
86 1.1 alnsn retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
87 1.1 alnsn {
88 1.1 alnsn
89 1.1 alnsn return args->wirelen;
90 1.1 alnsn }
91 1.1 alnsn
92 1.1 alnsn static uint32_t
93 1.1 alnsn retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
94 1.1 alnsn {
95 1.1 alnsn
96 1.1 alnsn return bc->nfuncs;
97 1.1 alnsn }
98 1.1 alnsn
99 1.1 alnsn /*
100 1.1 alnsn * COP function with a side effect.
101 1.1 alnsn */
102 1.1 alnsn static uint32_t
103 1.1 alnsn setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
104 1.1 alnsn {
105 1.1 alnsn bool *arg = (bool *)args->arg;
106 1.1 alnsn bool old = *arg;
107 1.1 alnsn
108 1.1 alnsn *arg = true;
109 1.1 alnsn return old;
110 1.1 alnsn }
111 1.1 alnsn
112 1.1 alnsn ATF_TC(bpfjit_cop_no_ctx);
113 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_no_ctx, tc)
114 1.1 alnsn {
115 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
116 1.1 alnsn "instruction isn't valid without a context");
117 1.1 alnsn }
118 1.1 alnsn
119 1.1 alnsn ATF_TC_BODY(bpfjit_cop_no_ctx, tc)
120 1.1 alnsn {
121 1.1 alnsn static struct bpf_insn insns[] = {
122 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0),
123 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 7)
124 1.1 alnsn };
125 1.1 alnsn
126 1.1 alnsn bpfjit_func_t code;
127 1.1 alnsn
128 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
129 1.1 alnsn
130 1.1 alnsn RZ(rump_init());
131 1.1 alnsn
132 1.1 alnsn ATF_CHECK(!prog_validate(insns, insn_count));
133 1.1 alnsn
134 1.1 alnsn rump_schedule();
135 1.1 alnsn code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
136 1.1 alnsn rump_unschedule();
137 1.1 alnsn ATF_CHECK(code == NULL);
138 1.1 alnsn }
139 1.1 alnsn
140 1.1 alnsn ATF_TC(bpfjit_cop_ret_A);
141 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_A, tc)
142 1.1 alnsn {
143 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
144 1.1 alnsn "that returns a content of the A register");
145 1.1 alnsn }
146 1.1 alnsn
147 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_A, tc)
148 1.1 alnsn {
149 1.1 alnsn static struct bpf_insn insns[] = {
150 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
151 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
152 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
153 1.1 alnsn };
154 1.1 alnsn
155 1.1 alnsn bpfjit_func_t code;
156 1.1 alnsn uint8_t pkt[1] = { 0 };
157 1.1 alnsn bpf_args_t args = {
158 1.1 alnsn .pkt = pkt,
159 1.1 alnsn .buflen = sizeof(pkt),
160 1.1 alnsn .wirelen = sizeof(pkt),
161 1.1 alnsn };
162 1.1 alnsn
163 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
164 1.1 alnsn
165 1.1 alnsn RZ(rump_init());
166 1.1 alnsn
167 1.1 alnsn rump_schedule();
168 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
169 1.1 alnsn rump_unschedule();
170 1.1 alnsn ATF_REQUIRE(code != NULL);
171 1.1 alnsn
172 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 13);
173 1.1 alnsn
174 1.1 alnsn rump_schedule();
175 1.1 alnsn rumpns_bpfjit_free_code(code);
176 1.1 alnsn rump_unschedule();
177 1.1 alnsn }
178 1.1 alnsn
179 1.1 alnsn ATF_TC(bpfjit_cop_ret_buflen);
180 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc)
181 1.1 alnsn {
182 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
183 1.1 alnsn "that returns the buflen argument");
184 1.1 alnsn }
185 1.1 alnsn
186 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_buflen, tc)
187 1.1 alnsn {
188 1.1 alnsn static struct bpf_insn insns[] = {
189 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
190 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
191 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
192 1.1 alnsn };
193 1.1 alnsn
194 1.1 alnsn bpfjit_func_t code;
195 1.1 alnsn uint8_t pkt[1] = { 0 };
196 1.1 alnsn bpf_args_t args = {
197 1.1 alnsn .pkt = pkt,
198 1.1 alnsn .buflen = sizeof(pkt),
199 1.1 alnsn .wirelen = sizeof(pkt)
200 1.1 alnsn };
201 1.1 alnsn
202 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
203 1.1 alnsn
204 1.1 alnsn RZ(rump_init());
205 1.1 alnsn
206 1.1 alnsn rump_schedule();
207 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
208 1.1 alnsn rump_unschedule();
209 1.1 alnsn ATF_REQUIRE(code != NULL);
210 1.1 alnsn
211 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
212 1.1 alnsn
213 1.1 alnsn rump_schedule();
214 1.1 alnsn rumpns_bpfjit_free_code(code);
215 1.1 alnsn rump_unschedule();
216 1.1 alnsn }
217 1.1 alnsn
218 1.1 alnsn ATF_TC(bpfjit_cop_ret_wirelen);
219 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc)
220 1.1 alnsn {
221 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
222 1.1 alnsn "that returns the wirelen argument");
223 1.1 alnsn }
224 1.1 alnsn
225 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc)
226 1.1 alnsn {
227 1.1 alnsn static struct bpf_insn insns[] = {
228 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
229 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
230 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
231 1.1 alnsn };
232 1.1 alnsn
233 1.1 alnsn bpfjit_func_t code;
234 1.1 alnsn uint8_t pkt[1] = { 0 };
235 1.1 alnsn bpf_args_t args = {
236 1.1 alnsn .pkt = pkt,
237 1.1 alnsn .buflen = sizeof(pkt),
238 1.1 alnsn .wirelen = sizeof(pkt)
239 1.1 alnsn };
240 1.1 alnsn
241 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
242 1.1 alnsn
243 1.1 alnsn RZ(rump_init());
244 1.1 alnsn
245 1.1 alnsn rump_schedule();
246 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
247 1.1 alnsn rump_unschedule();
248 1.1 alnsn ATF_REQUIRE(code != NULL);
249 1.1 alnsn
250 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
251 1.1 alnsn
252 1.1 alnsn rump_schedule();
253 1.1 alnsn rumpns_bpfjit_free_code(code);
254 1.1 alnsn rump_unschedule();
255 1.1 alnsn }
256 1.1 alnsn
257 1.1 alnsn ATF_TC(bpfjit_cop_ret_nfuncs);
258 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_nfuncs, tc)
259 1.1 alnsn {
260 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
261 1.1 alnsn "that returns nfuncs member of the context argument");
262 1.1 alnsn }
263 1.1 alnsn
264 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc)
265 1.1 alnsn {
266 1.1 alnsn static struct bpf_insn insns[] = {
267 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
268 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
269 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
270 1.1 alnsn };
271 1.1 alnsn
272 1.1 alnsn bpfjit_func_t code;
273 1.1 alnsn uint8_t pkt[1] = { 0 };
274 1.1 alnsn bpf_args_t args = {
275 1.1 alnsn .pkt = pkt,
276 1.1 alnsn .buflen = sizeof(pkt),
277 1.1 alnsn .wirelen = sizeof(pkt)
278 1.1 alnsn };
279 1.1 alnsn
280 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
281 1.1 alnsn
282 1.1 alnsn RZ(rump_init());
283 1.1 alnsn
284 1.1 alnsn rump_schedule();
285 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
286 1.1 alnsn rump_unschedule();
287 1.1 alnsn ATF_REQUIRE(code != NULL);
288 1.1 alnsn
289 1.1 alnsn ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
290 1.1 alnsn
291 1.1 alnsn rump_schedule();
292 1.1 alnsn rumpns_bpfjit_free_code(code);
293 1.1 alnsn rump_unschedule();
294 1.1 alnsn }
295 1.1 alnsn
296 1.1 alnsn ATF_TC(bpfjit_cop_side_effect);
297 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_side_effect, tc)
298 1.1 alnsn {
299 1.1 alnsn atf_tc_set_md_var(tc, "descr",
300 1.1 alnsn "Test that ABC optimization doesn't skip BPF_COP call");
301 1.1 alnsn }
302 1.1 alnsn
303 1.1 alnsn ATF_TC_BODY(bpfjit_cop_side_effect, tc)
304 1.1 alnsn {
305 1.1 alnsn static struct bpf_insn insns[] = {
306 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
307 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
308 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
309 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
310 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
311 1.1 alnsn };
312 1.1 alnsn
313 1.1 alnsn bpfjit_func_t code;
314 1.1 alnsn bool arg = false;
315 1.1 alnsn uint8_t pkt[1] = { 0 };
316 1.1 alnsn bpf_args_t args = {
317 1.1 alnsn .pkt = pkt,
318 1.1 alnsn .buflen = sizeof(pkt),
319 1.1 alnsn .wirelen = sizeof(pkt),
320 1.1 alnsn .mem = NULL,
321 1.1 alnsn .arg = &arg
322 1.1 alnsn };
323 1.1 alnsn
324 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
325 1.1 alnsn
326 1.1 alnsn RZ(rump_init());
327 1.1 alnsn
328 1.1 alnsn rump_schedule();
329 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
330 1.1 alnsn rump_unschedule();
331 1.1 alnsn ATF_REQUIRE(code != NULL);
332 1.1 alnsn
333 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0);
334 1.1 alnsn ATF_CHECK(arg == true);
335 1.1 alnsn
336 1.1 alnsn rump_schedule();
337 1.1 alnsn rumpns_bpfjit_free_code(code);
338 1.1 alnsn rump_unschedule();
339 1.1 alnsn }
340 1.1 alnsn
341 1.3 alnsn ATF_TC(bpfjit_cop_copx);
342 1.3 alnsn ATF_TC_HEAD(bpfjit_cop_copx, tc)
343 1.3 alnsn {
344 1.3 alnsn atf_tc_set_md_var(tc, "descr",
345 1.3 alnsn "Test BPF_COP call followed by BPF_COPX call");
346 1.3 alnsn }
347 1.3 alnsn
348 1.3 alnsn ATF_TC_BODY(bpfjit_cop_copx, tc)
349 1.3 alnsn {
350 1.3 alnsn static struct bpf_insn insns[] = {
351 1.3 alnsn BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */
352 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), /* retA */
353 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
354 1.3 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */
355 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
356 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
357 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retNF */
358 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
359 1.3 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
360 1.3 alnsn };
361 1.3 alnsn
362 1.3 alnsn bpfjit_func_t code;
363 1.3 alnsn uint8_t pkt[1] = { 2 };
364 1.3 alnsn bpf_args_t args = {
365 1.3 alnsn .pkt = pkt,
366 1.3 alnsn .buflen = sizeof(pkt),
367 1.3 alnsn .wirelen = sizeof(pkt),
368 1.3 alnsn };
369 1.3 alnsn
370 1.3 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
371 1.3 alnsn
372 1.3 alnsn RZ(rump_init());
373 1.3 alnsn
374 1.3 alnsn rump_schedule();
375 1.3 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
376 1.3 alnsn rump_unschedule();
377 1.3 alnsn ATF_REQUIRE(code != NULL);
378 1.3 alnsn
379 1.3 alnsn ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
380 1.3 alnsn
381 1.3 alnsn rump_schedule();
382 1.3 alnsn rumpns_bpfjit_free_code(code);
383 1.3 alnsn rump_unschedule();
384 1.3 alnsn }
385 1.3 alnsn
386 1.1 alnsn ATF_TC(bpfjit_cop_invalid_index);
387 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_invalid_index, tc)
388 1.1 alnsn {
389 1.1 alnsn atf_tc_set_md_var(tc, "descr",
390 1.1 alnsn "Test that out-of-range coprocessor function fails validation");
391 1.1 alnsn }
392 1.1 alnsn
393 1.1 alnsn ATF_TC_BODY(bpfjit_cop_invalid_index, tc)
394 1.1 alnsn {
395 1.1 alnsn static struct bpf_insn insns[] = {
396 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
397 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
398 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 27)
399 1.1 alnsn };
400 1.1 alnsn
401 1.1 alnsn bpfjit_func_t code;
402 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
403 1.1 alnsn
404 1.1 alnsn RZ(rump_init());
405 1.1 alnsn
406 1.1 alnsn rump_schedule();
407 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
408 1.1 alnsn rump_unschedule();
409 1.1 alnsn ATF_CHECK(code == NULL);
410 1.1 alnsn }
411 1.1 alnsn
412 1.1 alnsn ATF_TC(bpfjit_copx_no_ctx);
413 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
414 1.1 alnsn {
415 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
416 1.1 alnsn "instruction isn't valid without a context");
417 1.1 alnsn }
418 1.1 alnsn
419 1.1 alnsn ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
420 1.1 alnsn {
421 1.1 alnsn static struct bpf_insn insns[] = {
422 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0),
423 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 7)
424 1.1 alnsn };
425 1.1 alnsn
426 1.1 alnsn bpfjit_func_t code;
427 1.1 alnsn
428 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
429 1.1 alnsn
430 1.1 alnsn RZ(rump_init());
431 1.1 alnsn
432 1.1 alnsn ATF_CHECK(!prog_validate(insns, insn_count));
433 1.1 alnsn
434 1.1 alnsn rump_schedule();
435 1.1 alnsn code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
436 1.1 alnsn rump_unschedule();
437 1.1 alnsn ATF_CHECK(code == NULL);
438 1.1 alnsn }
439 1.1 alnsn
440 1.1 alnsn ATF_TC(bpfjit_copx_ret_A);
441 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_A, tc)
442 1.1 alnsn {
443 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
444 1.1 alnsn "that returns a content of the A register");
445 1.1 alnsn }
446 1.1 alnsn
447 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_A, tc)
448 1.1 alnsn {
449 1.1 alnsn static struct bpf_insn insns[] = {
450 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
451 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
452 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0),
453 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
454 1.1 alnsn };
455 1.1 alnsn
456 1.1 alnsn bpfjit_func_t code;
457 1.1 alnsn uint8_t pkt[1] = { 0 };
458 1.1 alnsn bpf_args_t args = {
459 1.1 alnsn .pkt = pkt,
460 1.1 alnsn .buflen = sizeof(pkt),
461 1.1 alnsn .wirelen = sizeof(pkt),
462 1.1 alnsn };
463 1.1 alnsn
464 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
465 1.1 alnsn
466 1.1 alnsn RZ(rump_init());
467 1.1 alnsn
468 1.1 alnsn rump_schedule();
469 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
470 1.1 alnsn rump_unschedule();
471 1.1 alnsn ATF_REQUIRE(code != NULL);
472 1.1 alnsn
473 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 13);
474 1.1 alnsn
475 1.1 alnsn rump_schedule();
476 1.1 alnsn rumpns_bpfjit_free_code(code);
477 1.1 alnsn rump_unschedule();
478 1.1 alnsn }
479 1.1 alnsn
480 1.1 alnsn ATF_TC(bpfjit_copx_ret_buflen);
481 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc)
482 1.1 alnsn {
483 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
484 1.1 alnsn "that returns the buflen argument");
485 1.1 alnsn }
486 1.1 alnsn
487 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_buflen, tc)
488 1.1 alnsn {
489 1.1 alnsn static struct bpf_insn insns[] = {
490 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
491 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
492 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0),
493 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
494 1.1 alnsn };
495 1.1 alnsn
496 1.1 alnsn bpfjit_func_t code;
497 1.1 alnsn uint8_t pkt[1] = { 0 };
498 1.1 alnsn bpf_args_t args = {
499 1.1 alnsn .pkt = pkt,
500 1.1 alnsn .buflen = sizeof(pkt),
501 1.1 alnsn .wirelen = sizeof(pkt)
502 1.1 alnsn };
503 1.1 alnsn
504 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
505 1.1 alnsn
506 1.1 alnsn RZ(rump_init());
507 1.1 alnsn
508 1.1 alnsn rump_schedule();
509 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
510 1.1 alnsn rump_unschedule();
511 1.1 alnsn ATF_REQUIRE(code != NULL);
512 1.1 alnsn
513 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
514 1.1 alnsn
515 1.2 alnsn rump_schedule();
516 1.1 alnsn rumpns_bpfjit_free_code(code);
517 1.1 alnsn rump_unschedule();
518 1.1 alnsn }
519 1.1 alnsn
520 1.1 alnsn ATF_TC(bpfjit_copx_ret_wirelen);
521 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc)
522 1.1 alnsn {
523 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
524 1.1 alnsn "that returns the wirelen argument");
525 1.1 alnsn }
526 1.1 alnsn
527 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc)
528 1.1 alnsn {
529 1.1 alnsn static struct bpf_insn insns[] = {
530 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
531 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
532 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0),
533 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
534 1.1 alnsn };
535 1.1 alnsn
536 1.1 alnsn bpfjit_func_t code;
537 1.1 alnsn uint8_t pkt[1] = { 0 };
538 1.1 alnsn bpf_args_t args = {
539 1.1 alnsn .pkt = pkt,
540 1.1 alnsn .buflen = sizeof(pkt),
541 1.1 alnsn .wirelen = sizeof(pkt)
542 1.1 alnsn };
543 1.1 alnsn
544 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
545 1.1 alnsn
546 1.1 alnsn RZ(rump_init());
547 1.1 alnsn
548 1.1 alnsn rump_schedule();
549 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
550 1.1 alnsn rump_unschedule();
551 1.1 alnsn ATF_REQUIRE(code != NULL);
552 1.1 alnsn
553 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
554 1.1 alnsn
555 1.1 alnsn rump_schedule();
556 1.1 alnsn rumpns_bpfjit_free_code(code);
557 1.1 alnsn rump_unschedule();
558 1.1 alnsn }
559 1.1 alnsn
560 1.1 alnsn ATF_TC(bpfjit_copx_ret_nfuncs);
561 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc)
562 1.1 alnsn {
563 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
564 1.1 alnsn "that returns nfuncs member of the context argument");
565 1.1 alnsn }
566 1.1 alnsn
567 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc)
568 1.1 alnsn {
569 1.1 alnsn static struct bpf_insn insns[] = {
570 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
571 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
572 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0),
573 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
574 1.1 alnsn };
575 1.1 alnsn
576 1.1 alnsn bpfjit_func_t code;
577 1.1 alnsn uint8_t pkt[1] = { 0 };
578 1.1 alnsn bpf_args_t args = {
579 1.1 alnsn .pkt = pkt,
580 1.1 alnsn .buflen = sizeof(pkt),
581 1.1 alnsn .wirelen = sizeof(pkt)
582 1.1 alnsn };
583 1.1 alnsn
584 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
585 1.1 alnsn
586 1.1 alnsn RZ(rump_init());
587 1.1 alnsn
588 1.1 alnsn rump_schedule();
589 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
590 1.1 alnsn rump_unschedule();
591 1.1 alnsn ATF_REQUIRE(code != NULL);
592 1.1 alnsn
593 1.1 alnsn ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
594 1.1 alnsn
595 1.1 alnsn rump_schedule();
596 1.1 alnsn rumpns_bpfjit_free_code(code);
597 1.1 alnsn rump_unschedule();
598 1.1 alnsn }
599 1.1 alnsn
600 1.1 alnsn ATF_TC(bpfjit_copx_side_effect);
601 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_side_effect, tc)
602 1.1 alnsn {
603 1.1 alnsn atf_tc_set_md_var(tc, "descr",
604 1.1 alnsn "Test that ABC optimization doesn't skip BPF_COPX call");
605 1.1 alnsn }
606 1.1 alnsn
607 1.1 alnsn ATF_TC_BODY(bpfjit_copx_side_effect, tc)
608 1.1 alnsn {
609 1.1 alnsn static struct bpf_insn insns[] = {
610 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13),
611 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
612 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
613 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0),
614 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
615 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
616 1.1 alnsn };
617 1.1 alnsn
618 1.1 alnsn bpfjit_func_t code;
619 1.1 alnsn bool arg = false;
620 1.1 alnsn uint8_t pkt[1] = { 0 };
621 1.1 alnsn bpf_args_t args = {
622 1.1 alnsn .pkt = pkt,
623 1.1 alnsn .buflen = sizeof(pkt),
624 1.1 alnsn .wirelen = sizeof(pkt),
625 1.1 alnsn .mem = NULL,
626 1.1 alnsn .arg = &arg
627 1.1 alnsn };
628 1.1 alnsn
629 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
630 1.1 alnsn
631 1.1 alnsn RZ(rump_init());
632 1.1 alnsn
633 1.1 alnsn rump_schedule();
634 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
635 1.1 alnsn rump_unschedule();
636 1.1 alnsn ATF_REQUIRE(code != NULL);
637 1.1 alnsn
638 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0);
639 1.1 alnsn ATF_CHECK(arg == true);
640 1.1 alnsn
641 1.1 alnsn rump_schedule();
642 1.1 alnsn rumpns_bpfjit_free_code(code);
643 1.1 alnsn rump_unschedule();
644 1.1 alnsn }
645 1.1 alnsn
646 1.3 alnsn ATF_TC(bpfjit_copx_cop);
647 1.3 alnsn ATF_TC_HEAD(bpfjit_copx_cop, tc)
648 1.3 alnsn {
649 1.3 alnsn atf_tc_set_md_var(tc, "descr",
650 1.3 alnsn "Test BPF_COPX call followed by BPF_COP call");
651 1.3 alnsn }
652 1.3 alnsn
653 1.3 alnsn ATF_TC_BODY(bpfjit_copx_cop, tc)
654 1.3 alnsn {
655 1.3 alnsn static struct bpf_insn insns[] = {
656 1.3 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 2), /* X <- 2 */
657 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retWL */
658 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
659 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
660 1.3 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */
661 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
662 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
663 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COP, 3), /* retNF */
664 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
665 1.3 alnsn BPF_STMT(BPF_RET+BPF_A, 0)
666 1.3 alnsn };
667 1.3 alnsn
668 1.3 alnsn bpfjit_func_t code;
669 1.3 alnsn uint8_t pkt[1] = { 2 };
670 1.3 alnsn bpf_args_t args = {
671 1.3 alnsn .pkt = pkt,
672 1.3 alnsn .buflen = sizeof(pkt),
673 1.3 alnsn .wirelen = sizeof(pkt),
674 1.3 alnsn };
675 1.3 alnsn
676 1.3 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
677 1.3 alnsn
678 1.3 alnsn RZ(rump_init());
679 1.3 alnsn
680 1.3 alnsn rump_schedule();
681 1.3 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
682 1.3 alnsn rump_unschedule();
683 1.3 alnsn ATF_REQUIRE(code != NULL);
684 1.3 alnsn
685 1.3 alnsn ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
686 1.3 alnsn
687 1.3 alnsn rump_schedule();
688 1.3 alnsn rumpns_bpfjit_free_code(code);
689 1.3 alnsn rump_unschedule();
690 1.3 alnsn }
691 1.3 alnsn
692 1.1 alnsn ATF_TC(bpfjit_copx_invalid_index);
693 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_invalid_index, tc)
694 1.1 alnsn {
695 1.1 alnsn atf_tc_set_md_var(tc, "descr",
696 1.1 alnsn "Test that out-of-range BPF_COPX call fails at runtime");
697 1.1 alnsn }
698 1.1 alnsn
699 1.1 alnsn ATF_TC_BODY(bpfjit_copx_invalid_index, tc)
700 1.1 alnsn {
701 1.1 alnsn static struct bpf_insn insns[] = {
702 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
703 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0),
704 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 27)
705 1.1 alnsn };
706 1.1 alnsn
707 1.1 alnsn bpfjit_func_t code;
708 1.1 alnsn uint8_t pkt[1] = { 0 };
709 1.1 alnsn bpf_args_t args = {
710 1.1 alnsn .pkt = pkt,
711 1.1 alnsn .buflen = sizeof(pkt),
712 1.1 alnsn .wirelen = sizeof(pkt)
713 1.1 alnsn };
714 1.1 alnsn
715 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]);
716 1.1 alnsn
717 1.1 alnsn RZ(rump_init());
718 1.1 alnsn
719 1.1 alnsn rump_schedule();
720 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
721 1.1 alnsn rump_unschedule();
722 1.1 alnsn ATF_REQUIRE(code != NULL);
723 1.1 alnsn
724 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0);
725 1.1 alnsn
726 1.1 alnsn rump_schedule();
727 1.1 alnsn rumpns_bpfjit_free_code(code);
728 1.1 alnsn rump_unschedule();
729 1.1 alnsn }
730 1.1 alnsn
731 1.1 alnsn ATF_TP_ADD_TCS(tp)
732 1.1 alnsn {
733 1.1 alnsn
734 1.1 alnsn /*
735 1.1 alnsn * For every new test please also add a similar test
736 1.1 alnsn * to ../../lib/libbpfjit/t_cop.c
737 1.1 alnsn */
738 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx);
739 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_A);
740 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_buflen);
741 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_wirelen);
742 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_nfuncs);
743 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_side_effect);
744 1.3 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_copx);
745 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_invalid_index);
746 1.1 alnsn
747 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx);
748 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_A);
749 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_buflen);
750 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_wirelen);
751 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_nfuncs);
752 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_side_effect);
753 1.3 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_cop);
754 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_invalid_index);
755 1.1 alnsn
756 1.1 alnsn return atf_no_error();
757 1.1 alnsn }
758