Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : : #include <stdint.h>
8 : : #include <inttypes.h>
9 : : #include <unistd.h>
10 : :
11 : : #include <rte_memory.h>
12 : : #include <rte_debug.h>
13 : : #include <rte_hexdump.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_random.h>
16 : : #include <rte_byteorder.h>
17 : : #include <rte_errno.h>
18 : :
19 : : #include "test.h"
20 : :
21 : : #if !defined(RTE_LIB_BPF)
22 : :
23 : : static int
24 : : test_bpf(void)
25 : : {
26 : : printf("BPF not supported, skipping test\n");
27 : : return TEST_SKIPPED;
28 : : }
29 : :
30 : : #else
31 : :
32 : : #include <rte_bpf.h>
33 : : #include <rte_ether.h>
34 : : #include <rte_ip.h>
35 : :
36 : :
37 : : /* Tests of most simple BPF programs (no instructions, one instruction etc.) */
38 : :
39 : : /*
40 : : * Try to load a simple bpf program from the instructions array.
41 : : *
42 : : * When `expected_errno` is zero, expect it to load successfully.
43 : : * When `expected_errno` is non-zero, expect it to fail with this `rte_errno`.
44 : : *
45 : : * @param nb_ins
46 : : * Number of instructions in the `ins` array.
47 : : * @param ins
48 : : * BPF instructions array.
49 : : * @param expected_errno
50 : : * Expected result.
51 : : * @return
52 : : * TEST_SUCCESS on success, error code on failure.
53 : : */
54 : : static int
55 : 8 : bpf_load_test(uint32_t nb_ins, const struct ebpf_insn *ins, int expected_errno)
56 : : {
57 : 8 : const struct rte_bpf_prm prm = {
58 : : .ins = ins,
59 : : .nb_ins = nb_ins,
60 : : .prog_arg = {
61 : : .type = RTE_BPF_ARG_RAW,
62 : : .size = sizeof(uint64_t),
63 : : },
64 : : };
65 : :
66 : 8 : struct rte_bpf *const bpf = rte_bpf_load(&prm);
67 : 8 : const int actual_errno = rte_errno;
68 : 8 : rte_bpf_destroy(bpf);
69 : :
70 [ + + ]: 8 : if (expected_errno != 0) {
71 [ - + ]: 5 : RTE_TEST_ASSERT_EQUAL(bpf, NULL,
72 : : "expect rte_bpf_load() == NULL");
73 [ - + ]: 5 : RTE_TEST_ASSERT_EQUAL(actual_errno, expected_errno,
74 : : "expect rte_errno == %d, found %d",
75 : : expected_errno, actual_errno);
76 : : } else
77 [ - + ]: 3 : RTE_TEST_ASSERT_NOT_EQUAL(bpf, NULL,
78 : : "expect rte_bpf_load() != NULL");
79 : :
80 : : return TEST_SUCCESS;
81 : : }
82 : :
83 : : /*
84 : : * Try and load completely empty BPF program.
85 : : * Should fail because there is no EXIT (and also return value is undefined).
86 : : */
87 : : static int
88 : 1 : test_no_instructions(void)
89 : : {
90 : : static const struct ebpf_insn ins[] = {};
91 : 1 : return bpf_load_test(RTE_DIM(ins), ins, EINVAL);
92 : : }
93 : :
94 : 303 : REGISTER_FAST_TEST(bpf_no_instructions_autotest, NOHUGE_OK, ASAN_OK, test_no_instructions);
95 : :
96 : : /*
97 : : * Try and load a BPF program comprising single EXIT instruction.
98 : : * Should fail because the return value is undefined.
99 : : */
100 : : static int
101 : 1 : test_exit_only(void)
102 : : {
103 : : static const struct ebpf_insn ins[] = {
104 : : {
105 : : .code = (BPF_JMP | EBPF_EXIT),
106 : : },
107 : : };
108 : 1 : return bpf_load_test(RTE_DIM(ins), ins, EINVAL);
109 : : }
110 : :
111 : 303 : REGISTER_FAST_TEST(bpf_exit_only_autotest, NOHUGE_OK, ASAN_OK, test_exit_only);
112 : :
113 : : /*
114 : : * Try and load a BPF program with no EXIT instruction.
115 : : * Should fail because of this.
116 : : */
117 : : static int
118 : 1 : test_no_exit(void)
119 : : {
120 : : static const struct ebpf_insn ins[] = {
121 : : {
122 : : /* Set return value to the program argument. */
123 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
124 : : .src_reg = EBPF_REG_1,
125 : : .dst_reg = EBPF_REG_0,
126 : : },
127 : : };
128 : 1 : return bpf_load_test(RTE_DIM(ins), ins, EINVAL);
129 : : }
130 : :
131 : 303 : REGISTER_FAST_TEST(bpf_no_exit_autotest, NOHUGE_OK, ASAN_OK, test_no_exit);
132 : :
133 : : /*
134 : : * Try and load smallest possible valid BPF program.
135 : : */
136 : : static int
137 : 1 : test_minimal_working(void)
138 : : {
139 : : static const struct ebpf_insn ins[] = {
140 : : {
141 : : /* Set return value to the program argument. */
142 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
143 : : .src_reg = EBPF_REG_1,
144 : : .dst_reg = EBPF_REG_0,
145 : : },
146 : : {
147 : : .code = (BPF_JMP | EBPF_EXIT),
148 : : },
149 : : };
150 : 1 : return bpf_load_test(RTE_DIM(ins), ins, 0);
151 : : }
152 : :
153 : 303 : REGISTER_FAST_TEST(bpf_minimal_working_autotest, NOHUGE_OK, ASAN_OK, test_minimal_working);
154 : :
155 : : /*
156 : : * Try and load valid BPF program adding one to the argument.
157 : : */
158 : : static int
159 : 1 : test_add_one(void)
160 : : {
161 : : static const struct ebpf_insn ins[] = {
162 : : {
163 : : /* Set return value to one. */
164 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
165 : : .dst_reg = EBPF_REG_0,
166 : : .imm = 1,
167 : : },
168 : : {
169 : : /* Add program argument to the return value. */
170 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
171 : : .src_reg = EBPF_REG_1,
172 : : .dst_reg = EBPF_REG_0,
173 : : },
174 : : {
175 : : .code = (BPF_JMP | EBPF_EXIT),
176 : : },
177 : : };
178 : 1 : return bpf_load_test(RTE_DIM(ins), ins, 0);
179 : : }
180 : :
181 : 303 : REGISTER_FAST_TEST(bpf_add_one_autotest, NOHUGE_OK, ASAN_OK, test_add_one);
182 : :
183 : : /*
184 : : * Try and load valid BPF program subtracting one from the argument.
185 : : */
186 : : static int
187 : 1 : test_subtract_one(void)
188 : : {
189 : : static const struct ebpf_insn ins[] = {
190 : : {
191 : : /* Subtract one from the program argument. */
192 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
193 : : .dst_reg = EBPF_REG_1,
194 : : .imm = 1,
195 : : },
196 : : {
197 : : /* Set return value to the result. */
198 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
199 : : .src_reg = EBPF_REG_1,
200 : : .dst_reg = EBPF_REG_0,
201 : : },
202 : : {
203 : : .code = (BPF_JMP | EBPF_EXIT),
204 : : },
205 : : };
206 : 1 : return bpf_load_test(RTE_DIM(ins), ins, 0);
207 : : }
208 : :
209 : 303 : REGISTER_FAST_TEST(bpf_subtract_one_autotest, NOHUGE_OK, ASAN_OK, test_subtract_one);
210 : :
211 : : /*
212 : : * Conditionally jump over invalid operation as first instruction.
213 : : */
214 : : static int
215 : 1 : test_jump_over_invalid_first(void)
216 : : {
217 : : static const struct ebpf_insn ins[] = {
218 : : {
219 : : /* Jump over the next instruction for some r1. */
220 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
221 : : .dst_reg = EBPF_REG_1,
222 : : .imm = 42,
223 : : .off = 1,
224 : : },
225 : : {
226 : : /* Write 0xDEADBEEF to [r1 + INT16_MIN]. */
227 : : .code = (BPF_ST | BPF_MEM | EBPF_DW),
228 : : .dst_reg = EBPF_REG_1,
229 : : .off = INT16_MIN,
230 : : .imm = 0xDEADBEEF,
231 : : },
232 : : {
233 : : /* Set return value to the program argument. */
234 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
235 : : .src_reg = EBPF_REG_1,
236 : : .dst_reg = EBPF_REG_0,
237 : : },
238 : : {
239 : : .code = (BPF_JMP | EBPF_EXIT),
240 : : },
241 : : };
242 : 1 : return bpf_load_test(RTE_DIM(ins), ins, EINVAL);
243 : : }
244 : :
245 : 303 : REGISTER_FAST_TEST(bpf_jump_over_invalid_first_autotest, NOHUGE_OK, ASAN_OK,
246 : : test_jump_over_invalid_first);
247 : :
248 : : /*
249 : : * Conditionally jump over invalid operation as non-first instruction.
250 : : */
251 : : static int
252 : 1 : test_jump_over_invalid_non_first(void)
253 : : {
254 : : static const struct ebpf_insn ins[] = {
255 : : {
256 : : /* Set return value to the program argument. */
257 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
258 : : .src_reg = EBPF_REG_1,
259 : : .dst_reg = EBPF_REG_0,
260 : : },
261 : : {
262 : : /* Jump over the next instruction for some r1. */
263 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
264 : : .dst_reg = EBPF_REG_1,
265 : : .imm = 42,
266 : : .off = 1,
267 : : },
268 : : {
269 : : /* Write 0xDEADBEEF to [r1 + INT16_MIN]. */
270 : : .code = (BPF_ST | BPF_MEM | EBPF_DW),
271 : : .dst_reg = EBPF_REG_1,
272 : : .off = INT16_MIN,
273 : : .imm = 0xDEADBEEF,
274 : : },
275 : : {
276 : : /* Set return value to the program argument. */
277 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
278 : : .src_reg = EBPF_REG_1,
279 : : .dst_reg = EBPF_REG_0,
280 : : },
281 : : {
282 : : .code = (BPF_JMP | EBPF_EXIT),
283 : : },
284 : : };
285 : 1 : return bpf_load_test(RTE_DIM(ins), ins, EINVAL);
286 : : }
287 : :
288 : 303 : REGISTER_FAST_TEST(bpf_jump_over_invalid_non_first_autotest, NOHUGE_OK, ASAN_OK,
289 : : test_jump_over_invalid_non_first);
290 : :
291 : : /*
292 : : * Basic functional tests for librte_bpf.
293 : : * The main procedure - load eBPF program, execute it and
294 : : * compare results with expected values.
295 : : */
296 : :
297 : : struct dummy_offset {
298 : : RTE_ATOMIC(uint64_t) u64;
299 : : RTE_ATOMIC(uint32_t) u32;
300 : : uint16_t u16;
301 : : uint8_t u8;
302 : : };
303 : :
304 : : struct dummy_vect8 {
305 : : struct dummy_offset in[8];
306 : : struct dummy_offset out[8];
307 : : };
308 : :
309 : : struct dummy_net {
310 : : struct rte_ether_hdr eth_hdr;
311 : : struct rte_vlan_hdr vlan_hdr;
312 : : struct rte_ipv4_hdr ip_hdr;
313 : : };
314 : :
315 : : #define DUMMY_MBUF_NUM 2
316 : :
317 : : /* first mbuf in the packet, should always be at offset 0 */
318 : : struct dummy_mbuf {
319 : : struct rte_mbuf mb[DUMMY_MBUF_NUM];
320 : : uint8_t buf[DUMMY_MBUF_NUM][RTE_MBUF_DEFAULT_BUF_SIZE];
321 : : };
322 : :
323 : : #define TEST_FILL_1 0xDEADBEEF
324 : :
325 : : #define TEST_MUL_1 21
326 : : #define TEST_MUL_2 -100
327 : :
328 : : #define TEST_SHIFT_1 15
329 : : #define TEST_SHIFT_2 33
330 : :
331 : : #define TEST_SHIFT32_MASK (CHAR_BIT * sizeof(uint32_t) - 1)
332 : : #define TEST_SHIFT64_MASK (CHAR_BIT * sizeof(uint64_t) - 1)
333 : :
334 : : #define TEST_JCC_1 0
335 : : #define TEST_JCC_2 -123
336 : : #define TEST_JCC_3 5678
337 : : #define TEST_JCC_4 TEST_FILL_1
338 : :
339 : : #define TEST_IMM_1 UINT64_MAX
340 : : #define TEST_IMM_2 ((uint64_t)INT64_MIN)
341 : : #define TEST_IMM_3 ((uint64_t)INT64_MAX + INT32_MAX)
342 : : #define TEST_IMM_4 ((uint64_t)UINT32_MAX)
343 : : #define TEST_IMM_5 ((uint64_t)UINT32_MAX + 1)
344 : :
345 : : #define TEST_MEMFROB 0x2a2a2a2a
346 : :
347 : : #define STRING_GEEK 0x6B656567
348 : : #define STRING_WEEK 0x6B656577
349 : :
350 : : #define TEST_NETMASK 0xffffff00
351 : : #define TEST_SUBNET 0xaca80200
352 : :
353 : : uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
354 : : uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
355 : :
356 : : uint32_t ip_src_addr = (172U << 24) | (168U << 16) | (2 << 8) | 1;
357 : : uint32_t ip_dst_addr = (172U << 24) | (168U << 16) | (2 << 8) | 2;
358 : :
359 : : struct bpf_test {
360 : : const char *name;
361 : : size_t arg_sz;
362 : : struct rte_bpf_prm prm;
363 : : void (*prepare)(void *);
364 : : int (*check_result)(uint64_t, const void *);
365 : : uint32_t allow_fail;
366 : : };
367 : :
368 : : /*
369 : : * Compare return value and result data with expected ones.
370 : : * Report a failure if they don't match.
371 : : */
372 : : static int
373 : 40 : cmp_res(const char *func, uint64_t exp_rc, uint64_t ret_rc,
374 : : const void *exp_res, const void *ret_res, size_t res_sz)
375 : : {
376 : : int32_t ret;
377 : :
378 : : ret = 0;
379 [ - + ]: 40 : if (exp_rc != ret_rc) {
380 : : printf("%s@%d: invalid return value, expected: 0x%" PRIx64
381 : : ",result: 0x%" PRIx64 "\n",
382 : : func, __LINE__, exp_rc, ret_rc);
383 : : ret |= -1;
384 : : }
385 : :
386 [ - + ]: 40 : if (memcmp(exp_res, ret_res, res_sz) != 0) {
387 : : printf("%s: invalid value\n", func);
388 : 0 : rte_memdump(stdout, "expected", exp_res, res_sz);
389 : 0 : rte_memdump(stdout, "result", ret_res, res_sz);
390 : : ret |= -1;
391 : : }
392 : :
393 : 40 : return ret;
394 : : }
395 : :
396 : : /* Empty prepare function */
397 : : static void
398 : 4 : dummy_prepare(void *arg)
399 : : {
400 : : RTE_SET_USED(arg);
401 : 4 : }
402 : :
403 : : /* store immediate test-cases */
404 : : static const struct ebpf_insn test_store1_prog[] = {
405 : : {
406 : : .code = (BPF_ST | BPF_MEM | BPF_B),
407 : : .dst_reg = EBPF_REG_1,
408 : : .off = offsetof(struct dummy_offset, u8),
409 : : .imm = TEST_FILL_1,
410 : : },
411 : : {
412 : : .code = (BPF_ST | BPF_MEM | BPF_H),
413 : : .dst_reg = EBPF_REG_1,
414 : : .off = offsetof(struct dummy_offset, u16),
415 : : .imm = TEST_FILL_1,
416 : : },
417 : : {
418 : : .code = (BPF_ST | BPF_MEM | BPF_W),
419 : : .dst_reg = EBPF_REG_1,
420 : : .off = offsetof(struct dummy_offset, u32),
421 : : .imm = TEST_FILL_1,
422 : : },
423 : : {
424 : : .code = (BPF_ST | BPF_MEM | EBPF_DW),
425 : : .dst_reg = EBPF_REG_1,
426 : : .off = offsetof(struct dummy_offset, u64),
427 : : .imm = TEST_FILL_1,
428 : : },
429 : : /* return 1 */
430 : : {
431 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
432 : : .dst_reg = EBPF_REG_0,
433 : : .imm = 1,
434 : : },
435 : : {
436 : : .code = (BPF_JMP | EBPF_EXIT),
437 : : },
438 : : };
439 : :
440 : : static void
441 : 14 : test_store1_prepare(void *arg)
442 : : {
443 : : struct dummy_offset *df;
444 : :
445 : : df = arg;
446 : : memset(df, 0, sizeof(*df));
447 : 14 : }
448 : :
449 : : static int
450 : 4 : test_store1_check(uint64_t rc, const void *arg)
451 : : {
452 : : const struct dummy_offset *dft;
453 : : struct dummy_offset dfe;
454 : :
455 : : dft = arg;
456 : :
457 : : memset(&dfe, 0, sizeof(dfe));
458 : 4 : dfe.u64 = (int32_t)TEST_FILL_1;
459 : 4 : dfe.u32 = dfe.u64;
460 : 4 : dfe.u16 = dfe.u64;
461 : 4 : dfe.u8 = dfe.u64;
462 : :
463 : 4 : return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
464 : : }
465 : :
466 : : /* store register test-cases */
467 : : static const struct ebpf_insn test_store2_prog[] = {
468 : :
469 : : {
470 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
471 : : .dst_reg = EBPF_REG_2,
472 : : .imm = TEST_FILL_1,
473 : : },
474 : : {
475 : : .code = (BPF_STX | BPF_MEM | BPF_B),
476 : : .dst_reg = EBPF_REG_1,
477 : : .src_reg = EBPF_REG_2,
478 : : .off = offsetof(struct dummy_offset, u8),
479 : : },
480 : : {
481 : : .code = (BPF_STX | BPF_MEM | BPF_H),
482 : : .dst_reg = EBPF_REG_1,
483 : : .src_reg = EBPF_REG_2,
484 : : .off = offsetof(struct dummy_offset, u16),
485 : : },
486 : : {
487 : : .code = (BPF_STX | BPF_MEM | BPF_W),
488 : : .dst_reg = EBPF_REG_1,
489 : : .src_reg = EBPF_REG_2,
490 : : .off = offsetof(struct dummy_offset, u32),
491 : : },
492 : : {
493 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
494 : : .dst_reg = EBPF_REG_1,
495 : : .src_reg = EBPF_REG_2,
496 : : .off = offsetof(struct dummy_offset, u64),
497 : : },
498 : : /* return 1 */
499 : : {
500 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
501 : : .dst_reg = EBPF_REG_0,
502 : : .imm = 1,
503 : : },
504 : : {
505 : : .code = (BPF_JMP | EBPF_EXIT),
506 : : },
507 : : };
508 : :
509 : : /* load test-cases */
510 : : static const struct ebpf_insn test_load1_prog[] = {
511 : :
512 : : {
513 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
514 : : .dst_reg = EBPF_REG_2,
515 : : .src_reg = EBPF_REG_1,
516 : : .off = offsetof(struct dummy_offset, u8),
517 : : },
518 : : {
519 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
520 : : .dst_reg = EBPF_REG_3,
521 : : .src_reg = EBPF_REG_1,
522 : : .off = offsetof(struct dummy_offset, u16),
523 : : },
524 : : {
525 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
526 : : .dst_reg = EBPF_REG_4,
527 : : .src_reg = EBPF_REG_1,
528 : : .off = offsetof(struct dummy_offset, u32),
529 : : },
530 : : {
531 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
532 : : .dst_reg = EBPF_REG_0,
533 : : .src_reg = EBPF_REG_1,
534 : : .off = offsetof(struct dummy_offset, u64),
535 : : },
536 : : /* return sum */
537 : : {
538 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
539 : : .dst_reg = EBPF_REG_0,
540 : : .src_reg = EBPF_REG_4,
541 : : },
542 : : {
543 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
544 : : .dst_reg = EBPF_REG_0,
545 : : .src_reg = EBPF_REG_3,
546 : : },
547 : : {
548 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
549 : : .dst_reg = EBPF_REG_0,
550 : : .src_reg = EBPF_REG_2,
551 : : },
552 : : {
553 : : .code = (BPF_JMP | EBPF_EXIT),
554 : : },
555 : : };
556 : :
557 : : static void
558 : 4 : test_load1_prepare(void *arg)
559 : : {
560 : : struct dummy_offset *df;
561 : :
562 : : df = arg;
563 : :
564 : : memset(df, 0, sizeof(*df));
565 : 4 : df->u64 = (int32_t)TEST_FILL_1;
566 : 4 : df->u32 = df->u64;
567 : 4 : df->u16 = df->u64;
568 : 4 : df->u8 = df->u64;
569 : 4 : }
570 : :
571 : : static int
572 : 2 : test_load1_check(uint64_t rc, const void *arg)
573 : : {
574 : : uint64_t v;
575 : : const struct dummy_offset *dft;
576 : :
577 : : dft = arg;
578 : 2 : v = dft->u64;
579 : 2 : v += dft->u32;
580 : 2 : v += dft->u16;
581 : 2 : v += dft->u8;
582 : :
583 : 2 : return cmp_res(__func__, v, rc, dft, dft, sizeof(*dft));
584 : : }
585 : :
586 : : /* load immediate test-cases */
587 : : static const struct ebpf_insn test_ldimm1_prog[] = {
588 : :
589 : : {
590 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
591 : : .dst_reg = EBPF_REG_0,
592 : : .imm = (uint32_t)TEST_IMM_1,
593 : : },
594 : : {
595 : : .imm = TEST_IMM_1 >> 32,
596 : : },
597 : : {
598 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
599 : : .dst_reg = EBPF_REG_3,
600 : : .imm = (uint32_t)TEST_IMM_2,
601 : : },
602 : : {
603 : : .imm = TEST_IMM_2 >> 32,
604 : : },
605 : : {
606 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
607 : : .dst_reg = EBPF_REG_5,
608 : : .imm = (uint32_t)TEST_IMM_3,
609 : : },
610 : : {
611 : : .imm = TEST_IMM_3 >> 32,
612 : : },
613 : : {
614 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
615 : : .dst_reg = EBPF_REG_7,
616 : : .imm = (uint32_t)TEST_IMM_4,
617 : : },
618 : : {
619 : : .imm = TEST_IMM_4 >> 32,
620 : : },
621 : : {
622 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
623 : : .dst_reg = EBPF_REG_9,
624 : : .imm = (uint32_t)TEST_IMM_5,
625 : : },
626 : : {
627 : : .imm = TEST_IMM_5 >> 32,
628 : : },
629 : : /* return sum */
630 : : {
631 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
632 : : .dst_reg = EBPF_REG_0,
633 : : .src_reg = EBPF_REG_3,
634 : : },
635 : : {
636 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
637 : : .dst_reg = EBPF_REG_0,
638 : : .src_reg = EBPF_REG_5,
639 : : },
640 : : {
641 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
642 : : .dst_reg = EBPF_REG_0,
643 : : .src_reg = EBPF_REG_7,
644 : : },
645 : : {
646 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
647 : : .dst_reg = EBPF_REG_0,
648 : : .src_reg = EBPF_REG_9,
649 : : },
650 : : {
651 : : .code = (BPF_JMP | EBPF_EXIT),
652 : : },
653 : : };
654 : :
655 : : static int
656 : 2 : test_ldimm1_check(uint64_t rc, const void *arg)
657 : : {
658 : : uint64_t v1, v2;
659 : :
660 : : v1 = TEST_IMM_1;
661 : : v2 = TEST_IMM_2;
662 : : v1 += v2;
663 : : v2 = TEST_IMM_3;
664 : : v1 += v2;
665 : : v2 = TEST_IMM_4;
666 : : v1 += v2;
667 : : v2 = TEST_IMM_5;
668 : : v1 += v2;
669 : :
670 : 2 : return cmp_res(__func__, v1, rc, arg, arg, 0);
671 : : }
672 : :
673 : :
674 : : /* alu mul test-cases */
675 : : static const struct ebpf_insn test_mul1_prog[] = {
676 : :
677 : : {
678 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
679 : : .dst_reg = EBPF_REG_2,
680 : : .src_reg = EBPF_REG_1,
681 : : .off = offsetof(struct dummy_vect8, in[0].u32),
682 : : },
683 : : {
684 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
685 : : .dst_reg = EBPF_REG_3,
686 : : .src_reg = EBPF_REG_1,
687 : : .off = offsetof(struct dummy_vect8, in[1].u64),
688 : : },
689 : : {
690 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
691 : : .dst_reg = EBPF_REG_4,
692 : : .src_reg = EBPF_REG_1,
693 : : .off = offsetof(struct dummy_vect8, in[2].u32),
694 : : },
695 : : {
696 : : .code = (BPF_ALU | BPF_MUL | BPF_K),
697 : : .dst_reg = EBPF_REG_2,
698 : : .imm = TEST_MUL_1,
699 : : },
700 : : {
701 : : .code = (EBPF_ALU64 | BPF_MUL | BPF_K),
702 : : .dst_reg = EBPF_REG_3,
703 : : .imm = TEST_MUL_2,
704 : : },
705 : : {
706 : : .code = (BPF_ALU | BPF_MUL | BPF_X),
707 : : .dst_reg = EBPF_REG_4,
708 : : .src_reg = EBPF_REG_2,
709 : : },
710 : : {
711 : : .code = (EBPF_ALU64 | BPF_MUL | BPF_X),
712 : : .dst_reg = EBPF_REG_4,
713 : : .src_reg = EBPF_REG_3,
714 : : },
715 : : {
716 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
717 : : .dst_reg = EBPF_REG_1,
718 : : .src_reg = EBPF_REG_2,
719 : : .off = offsetof(struct dummy_vect8, out[0].u64),
720 : : },
721 : : {
722 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
723 : : .dst_reg = EBPF_REG_1,
724 : : .src_reg = EBPF_REG_3,
725 : : .off = offsetof(struct dummy_vect8, out[1].u64),
726 : : },
727 : : {
728 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
729 : : .dst_reg = EBPF_REG_1,
730 : : .src_reg = EBPF_REG_4,
731 : : .off = offsetof(struct dummy_vect8, out[2].u64),
732 : : },
733 : : /* return 1 */
734 : : {
735 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
736 : : .dst_reg = EBPF_REG_0,
737 : : .imm = 1,
738 : : },
739 : : {
740 : : .code = (BPF_JMP | EBPF_EXIT),
741 : : },
742 : : };
743 : :
744 : : static void
745 : 4 : test_mul1_prepare(void *arg)
746 : : {
747 : : struct dummy_vect8 *dv;
748 : : uint64_t v;
749 : :
750 : : dv = arg;
751 : :
752 : 4 : v = rte_rand();
753 : :
754 : : memset(dv, 0, sizeof(*dv));
755 : 4 : dv->in[0].u32 = v;
756 : 4 : dv->in[1].u64 = v << 12 | v >> 6;
757 : 4 : dv->in[2].u32 = -v;
758 : 4 : }
759 : :
760 : : static int
761 : 2 : test_mul1_check(uint64_t rc, const void *arg)
762 : : {
763 : : uint64_t r2, r3, r4;
764 : : const struct dummy_vect8 *dvt;
765 : : struct dummy_vect8 dve;
766 : :
767 : : dvt = arg;
768 : : memset(&dve, 0, sizeof(dve));
769 : :
770 : 2 : r2 = dvt->in[0].u32;
771 : 2 : r3 = dvt->in[1].u64;
772 : 2 : r4 = dvt->in[2].u32;
773 : :
774 : 2 : r2 = (uint32_t)r2 * TEST_MUL_1;
775 : 2 : r3 *= TEST_MUL_2;
776 : 2 : r4 = (uint32_t)(r4 * r2);
777 : 2 : r4 *= r3;
778 : :
779 : 2 : dve.out[0].u64 = r2;
780 : 2 : dve.out[1].u64 = r3;
781 : 2 : dve.out[2].u64 = r4;
782 : :
783 : 2 : return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
784 : : }
785 : :
786 : : /* alu shift test-cases */
787 : : static const struct ebpf_insn test_shift1_prog[] = {
788 : :
789 : : {
790 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
791 : : .dst_reg = EBPF_REG_2,
792 : : .src_reg = EBPF_REG_1,
793 : : .off = offsetof(struct dummy_vect8, in[0].u32),
794 : : },
795 : : {
796 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
797 : : .dst_reg = EBPF_REG_3,
798 : : .src_reg = EBPF_REG_1,
799 : : .off = offsetof(struct dummy_vect8, in[1].u64),
800 : : },
801 : : {
802 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
803 : : .dst_reg = EBPF_REG_4,
804 : : .src_reg = EBPF_REG_1,
805 : : .off = offsetof(struct dummy_vect8, in[2].u32),
806 : : },
807 : : {
808 : : .code = (BPF_ALU | BPF_LSH | BPF_K),
809 : : .dst_reg = EBPF_REG_2,
810 : : .imm = TEST_SHIFT_1,
811 : : },
812 : : {
813 : : .code = (EBPF_ALU64 | EBPF_ARSH | BPF_K),
814 : : .dst_reg = EBPF_REG_3,
815 : : .imm = TEST_SHIFT_2,
816 : : },
817 : : {
818 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
819 : : .dst_reg = EBPF_REG_1,
820 : : .src_reg = EBPF_REG_2,
821 : : .off = offsetof(struct dummy_vect8, out[0].u64),
822 : : },
823 : : {
824 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
825 : : .dst_reg = EBPF_REG_1,
826 : : .src_reg = EBPF_REG_3,
827 : : .off = offsetof(struct dummy_vect8, out[1].u64),
828 : : },
829 : : {
830 : : .code = (BPF_ALU | BPF_AND | BPF_K),
831 : : .dst_reg = EBPF_REG_4,
832 : : .imm = TEST_SHIFT64_MASK,
833 : : },
834 : : {
835 : : .code = (EBPF_ALU64 | BPF_LSH | BPF_X),
836 : : .dst_reg = EBPF_REG_3,
837 : : .src_reg = EBPF_REG_4,
838 : : },
839 : : {
840 : : .code = (BPF_ALU | BPF_AND | BPF_K),
841 : : .dst_reg = EBPF_REG_4,
842 : : .imm = TEST_SHIFT32_MASK,
843 : : },
844 : : {
845 : : .code = (BPF_ALU | BPF_RSH | BPF_X),
846 : : .dst_reg = EBPF_REG_2,
847 : : .src_reg = EBPF_REG_4,
848 : : },
849 : : {
850 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
851 : : .dst_reg = EBPF_REG_1,
852 : : .src_reg = EBPF_REG_2,
853 : : .off = offsetof(struct dummy_vect8, out[2].u64),
854 : : },
855 : : {
856 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
857 : : .dst_reg = EBPF_REG_1,
858 : : .src_reg = EBPF_REG_3,
859 : : .off = offsetof(struct dummy_vect8, out[3].u64),
860 : : },
861 : : {
862 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
863 : : .dst_reg = EBPF_REG_2,
864 : : .src_reg = EBPF_REG_1,
865 : : .off = offsetof(struct dummy_vect8, in[0].u32),
866 : : },
867 : : {
868 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
869 : : .dst_reg = EBPF_REG_3,
870 : : .src_reg = EBPF_REG_1,
871 : : .off = offsetof(struct dummy_vect8, in[1].u64),
872 : : },
873 : : {
874 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
875 : : .dst_reg = EBPF_REG_4,
876 : : .src_reg = EBPF_REG_1,
877 : : .off = offsetof(struct dummy_vect8, in[2].u32),
878 : : },
879 : : {
880 : : .code = (BPF_ALU | BPF_AND | BPF_K),
881 : : .dst_reg = EBPF_REG_2,
882 : : .imm = TEST_SHIFT64_MASK,
883 : : },
884 : : {
885 : : .code = (EBPF_ALU64 | EBPF_ARSH | BPF_X),
886 : : .dst_reg = EBPF_REG_3,
887 : : .src_reg = EBPF_REG_2,
888 : : },
889 : : {
890 : : .code = (BPF_ALU | BPF_AND | BPF_K),
891 : : .dst_reg = EBPF_REG_2,
892 : : .imm = TEST_SHIFT32_MASK,
893 : : },
894 : : {
895 : : .code = (BPF_ALU | BPF_LSH | BPF_X),
896 : : .dst_reg = EBPF_REG_4,
897 : : .src_reg = EBPF_REG_2,
898 : : },
899 : : {
900 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
901 : : .dst_reg = EBPF_REG_1,
902 : : .src_reg = EBPF_REG_4,
903 : : .off = offsetof(struct dummy_vect8, out[4].u64),
904 : : },
905 : : {
906 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
907 : : .dst_reg = EBPF_REG_1,
908 : : .src_reg = EBPF_REG_3,
909 : : .off = offsetof(struct dummy_vect8, out[5].u64),
910 : : },
911 : : /* return 1 */
912 : : {
913 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
914 : : .dst_reg = EBPF_REG_0,
915 : : .imm = 1,
916 : : },
917 : : {
918 : : .code = (BPF_JMP | EBPF_EXIT),
919 : : },
920 : : };
921 : :
922 : : static void
923 : 2 : test_shift1_prepare(void *arg)
924 : : {
925 : : struct dummy_vect8 *dv;
926 : : uint64_t v;
927 : :
928 : : dv = arg;
929 : :
930 : 2 : v = rte_rand();
931 : :
932 : : memset(dv, 0, sizeof(*dv));
933 : 2 : dv->in[0].u32 = v;
934 : 2 : dv->in[1].u64 = v << 12 | v >> 6;
935 : 2 : dv->in[2].u32 = (-v ^ 5);
936 : 2 : }
937 : :
938 : : static int
939 : 2 : test_shift1_check(uint64_t rc, const void *arg)
940 : : {
941 : : uint64_t r2, r3, r4;
942 : : const struct dummy_vect8 *dvt;
943 : : struct dummy_vect8 dve;
944 : :
945 : : dvt = arg;
946 : : memset(&dve, 0, sizeof(dve));
947 : :
948 : 2 : r2 = dvt->in[0].u32;
949 : 2 : r3 = dvt->in[1].u64;
950 : 2 : r4 = dvt->in[2].u32;
951 : :
952 : 2 : r2 = (uint32_t)r2 << TEST_SHIFT_1;
953 : 2 : r3 = (int64_t)r3 >> TEST_SHIFT_2;
954 : :
955 : 2 : dve.out[0].u64 = r2;
956 : 2 : dve.out[1].u64 = r3;
957 : :
958 : : r4 &= TEST_SHIFT64_MASK;
959 : 2 : r3 <<= r4;
960 : : r4 &= TEST_SHIFT32_MASK;
961 : 2 : r2 = (uint32_t)r2 >> r4;
962 : :
963 : 2 : dve.out[2].u64 = r2;
964 : 2 : dve.out[3].u64 = r3;
965 : :
966 : : r2 = dvt->in[0].u32;
967 : : r3 = dvt->in[1].u64;
968 : : r4 = dvt->in[2].u32;
969 : :
970 : : r2 &= TEST_SHIFT64_MASK;
971 : 2 : r3 = (int64_t)r3 >> r2;
972 : : r2 &= TEST_SHIFT32_MASK;
973 : 2 : r4 = (uint32_t)r4 << r2;
974 : :
975 : 2 : dve.out[4].u64 = r4;
976 : 2 : dve.out[5].u64 = r3;
977 : :
978 : 2 : return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
979 : : }
980 : :
981 : : /* jmp test-cases */
982 : : static const struct ebpf_insn test_jump1_prog[] = {
983 : :
984 : : [0] = {
985 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
986 : : .dst_reg = EBPF_REG_0,
987 : : .imm = 0,
988 : : },
989 : : [1] = {
990 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
991 : : .dst_reg = EBPF_REG_2,
992 : : .src_reg = EBPF_REG_1,
993 : : .off = offsetof(struct dummy_vect8, in[0].u32),
994 : : },
995 : : [2] = {
996 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
997 : : .dst_reg = EBPF_REG_3,
998 : : .src_reg = EBPF_REG_1,
999 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1000 : : },
1001 : : [3] = {
1002 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1003 : : .dst_reg = EBPF_REG_4,
1004 : : .src_reg = EBPF_REG_1,
1005 : : .off = offsetof(struct dummy_vect8, in[1].u32),
1006 : : },
1007 : : [4] = {
1008 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1009 : : .dst_reg = EBPF_REG_5,
1010 : : .src_reg = EBPF_REG_1,
1011 : : .off = offsetof(struct dummy_vect8, in[1].u64),
1012 : : },
1013 : : [5] = {
1014 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
1015 : : .dst_reg = EBPF_REG_2,
1016 : : .imm = TEST_JCC_1,
1017 : : .off = 8,
1018 : : },
1019 : : [6] = {
1020 : : .code = (BPF_JMP | EBPF_JSLE | BPF_K),
1021 : : .dst_reg = EBPF_REG_3,
1022 : : .imm = TEST_JCC_2,
1023 : : .off = 9,
1024 : : },
1025 : : [7] = {
1026 : : .code = (BPF_JMP | BPF_JGT | BPF_K),
1027 : : .dst_reg = EBPF_REG_4,
1028 : : .imm = TEST_JCC_3,
1029 : : .off = 10,
1030 : : },
1031 : : [8] = {
1032 : : .code = (BPF_JMP | BPF_JSET | BPF_K),
1033 : : .dst_reg = EBPF_REG_5,
1034 : : .imm = TEST_JCC_4,
1035 : : .off = 11,
1036 : : },
1037 : : [9] = {
1038 : : .code = (BPF_JMP | EBPF_JNE | BPF_X),
1039 : : .dst_reg = EBPF_REG_2,
1040 : : .src_reg = EBPF_REG_3,
1041 : : .off = 12,
1042 : : },
1043 : : [10] = {
1044 : : .code = (BPF_JMP | EBPF_JSGT | BPF_X),
1045 : : .dst_reg = EBPF_REG_2,
1046 : : .src_reg = EBPF_REG_4,
1047 : : .off = 13,
1048 : : },
1049 : : [11] = {
1050 : : .code = (BPF_JMP | EBPF_JLE | BPF_X),
1051 : : .dst_reg = EBPF_REG_2,
1052 : : .src_reg = EBPF_REG_5,
1053 : : .off = 14,
1054 : : },
1055 : : [12] = {
1056 : : .code = (BPF_JMP | BPF_JSET | BPF_X),
1057 : : .dst_reg = EBPF_REG_3,
1058 : : .src_reg = EBPF_REG_5,
1059 : : .off = 15,
1060 : : },
1061 : : [13] = {
1062 : : .code = (BPF_JMP | EBPF_EXIT),
1063 : : },
1064 : : [14] = {
1065 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1066 : : .dst_reg = EBPF_REG_0,
1067 : : .imm = 0x1,
1068 : : },
1069 : : [15] = {
1070 : : .code = (BPF_JMP | BPF_JA),
1071 : : .off = -10,
1072 : : },
1073 : : [16] = {
1074 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1075 : : .dst_reg = EBPF_REG_0,
1076 : : .imm = 0x2,
1077 : : },
1078 : : [17] = {
1079 : : .code = (BPF_JMP | BPF_JA),
1080 : : .off = -11,
1081 : : },
1082 : : [18] = {
1083 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1084 : : .dst_reg = EBPF_REG_0,
1085 : : .imm = 0x4,
1086 : : },
1087 : : [19] = {
1088 : : .code = (BPF_JMP | BPF_JA),
1089 : : .off = -12,
1090 : : },
1091 : : [20] = {
1092 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1093 : : .dst_reg = EBPF_REG_0,
1094 : : .imm = 0x8,
1095 : : },
1096 : : [21] = {
1097 : : .code = (BPF_JMP | BPF_JA),
1098 : : .off = -13,
1099 : : },
1100 : : [22] = {
1101 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1102 : : .dst_reg = EBPF_REG_0,
1103 : : .imm = 0x10,
1104 : : },
1105 : : [23] = {
1106 : : .code = (BPF_JMP | BPF_JA),
1107 : : .off = -14,
1108 : : },
1109 : : [24] = {
1110 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1111 : : .dst_reg = EBPF_REG_0,
1112 : : .imm = 0x20,
1113 : : },
1114 : : [25] = {
1115 : : .code = (BPF_JMP | BPF_JA),
1116 : : .off = -15,
1117 : : },
1118 : : [26] = {
1119 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1120 : : .dst_reg = EBPF_REG_0,
1121 : : .imm = 0x40,
1122 : : },
1123 : : [27] = {
1124 : : .code = (BPF_JMP | BPF_JA),
1125 : : .off = -16,
1126 : : },
1127 : : [28] = {
1128 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1129 : : .dst_reg = EBPF_REG_0,
1130 : : .imm = 0x80,
1131 : : },
1132 : : [29] = {
1133 : : .code = (BPF_JMP | BPF_JA),
1134 : : .off = -17,
1135 : : },
1136 : : };
1137 : :
1138 : : static void
1139 : 4 : test_jump1_prepare(void *arg)
1140 : : {
1141 : : struct dummy_vect8 *dv;
1142 : : uint64_t v1, v2;
1143 : :
1144 : : dv = arg;
1145 : :
1146 : 4 : v1 = rte_rand();
1147 : 4 : v2 = rte_rand();
1148 : :
1149 : : memset(dv, 0, sizeof(*dv));
1150 : 4 : dv->in[0].u64 = v1;
1151 : 4 : dv->in[1].u64 = v2;
1152 : 4 : dv->in[0].u32 = (v1 << 12) + (v2 >> 6);
1153 : 4 : dv->in[1].u32 = (v2 << 12) - (v1 >> 6);
1154 : 4 : }
1155 : :
1156 : : static int
1157 : 2 : test_jump1_check(uint64_t rc, const void *arg)
1158 : : {
1159 : : uint64_t r2, r3, r4, r5, rv;
1160 : : const struct dummy_vect8 *dvt;
1161 : :
1162 : : dvt = arg;
1163 : :
1164 : 2 : rv = 0;
1165 : 2 : r2 = dvt->in[0].u32;
1166 : 2 : r3 = dvt->in[0].u64;
1167 : 2 : r4 = dvt->in[1].u32;
1168 : 2 : r5 = dvt->in[1].u64;
1169 : :
1170 [ - + ]: 2 : if (r2 == TEST_JCC_1)
1171 : 0 : rv |= 0x1;
1172 [ - + ]: 2 : if ((int64_t)r3 <= TEST_JCC_2)
1173 : 0 : rv |= 0x2;
1174 [ + - ]: 2 : if (r4 > TEST_JCC_3)
1175 : 2 : rv |= 0x4;
1176 [ + - ]: 2 : if (r5 & TEST_JCC_4)
1177 : 2 : rv |= 0x8;
1178 [ + - ]: 2 : if (r2 != r3)
1179 : 2 : rv |= 0x10;
1180 [ + - ]: 2 : if ((int64_t)r2 > (int64_t)r4)
1181 : 2 : rv |= 0x20;
1182 [ + - ]: 2 : if (r2 <= r5)
1183 : 2 : rv |= 0x40;
1184 [ + - ]: 2 : if (r3 & r5)
1185 : 2 : rv |= 0x80;
1186 : :
1187 : 2 : return cmp_res(__func__, rv, rc, &rv, &rc, sizeof(rv));
1188 : : }
1189 : :
1190 : : /* Jump test case - check ip4_dest in particular subnet */
1191 : : static const struct ebpf_insn test_jump2_prog[] = {
1192 : :
1193 : : [0] = {
1194 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1195 : : .dst_reg = EBPF_REG_2,
1196 : : .imm = 0xe,
1197 : : },
1198 : : [1] = {
1199 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1200 : : .dst_reg = EBPF_REG_3,
1201 : : .src_reg = EBPF_REG_1,
1202 : : .off = 12,
1203 : : },
1204 : : [2] = {
1205 : : .code = (BPF_JMP | EBPF_JNE | BPF_K),
1206 : : .dst_reg = EBPF_REG_3,
1207 : : .off = 2,
1208 : : .imm = 0x81,
1209 : : },
1210 : : [3] = {
1211 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1212 : : .dst_reg = EBPF_REG_2,
1213 : : .imm = 0x12,
1214 : : },
1215 : : [4] = {
1216 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1217 : : .dst_reg = EBPF_REG_3,
1218 : : .src_reg = EBPF_REG_1,
1219 : : .off = 16,
1220 : : },
1221 : : [5] = {
1222 : : .code = (EBPF_ALU64 | BPF_AND | BPF_K),
1223 : : .dst_reg = EBPF_REG_3,
1224 : : .imm = 0xffff,
1225 : : },
1226 : : [6] = {
1227 : : .code = (BPF_JMP | EBPF_JNE | BPF_K),
1228 : : .dst_reg = EBPF_REG_3,
1229 : : .off = 9,
1230 : : .imm = 0x8,
1231 : : },
1232 : : [7] = {
1233 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1234 : : .dst_reg = EBPF_REG_1,
1235 : : .src_reg = EBPF_REG_2,
1236 : : },
1237 : : [8] = {
1238 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1239 : : .dst_reg = EBPF_REG_0,
1240 : : .imm = 0,
1241 : : },
1242 : : [9] = {
1243 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1244 : : .dst_reg = EBPF_REG_1,
1245 : : .src_reg = EBPF_REG_1,
1246 : : .off = 16,
1247 : : },
1248 : : [10] = {
1249 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1250 : : .dst_reg = EBPF_REG_3,
1251 : : .imm = TEST_NETMASK,
1252 : : },
1253 : : [11] = {
1254 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1255 : : .dst_reg = EBPF_REG_3,
1256 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1257 : : },
1258 : : [12] = {
1259 : : .code = (BPF_ALU | BPF_AND | BPF_X),
1260 : : .dst_reg = EBPF_REG_1,
1261 : : .src_reg = EBPF_REG_3,
1262 : : },
1263 : : [13] = {
1264 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1265 : : .dst_reg = EBPF_REG_3,
1266 : : .imm = TEST_SUBNET,
1267 : : },
1268 : : [14] = {
1269 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1270 : : .dst_reg = EBPF_REG_3,
1271 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1272 : : },
1273 : : [15] = {
1274 : : .code = (BPF_JMP | BPF_JEQ | BPF_X),
1275 : : .dst_reg = EBPF_REG_1,
1276 : : .src_reg = EBPF_REG_3,
1277 : : .off = 1,
1278 : : },
1279 : : [16] = {
1280 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1281 : : .dst_reg = EBPF_REG_0,
1282 : : .imm = -1,
1283 : : },
1284 : : [17] = {
1285 : : .code = (BPF_JMP | EBPF_EXIT),
1286 : : },
1287 : : };
1288 : :
1289 : : /* Preparing a vlan packet */
1290 : : static void
1291 [ - + ]: 2 : test_jump2_prepare(void *arg)
1292 : : {
1293 : : struct dummy_net *dn;
1294 : :
1295 : : dn = arg;
1296 : : memset(dn, 0, sizeof(*dn));
1297 : :
1298 : : /*
1299 : : * Initialize ether header.
1300 : : */
1301 : : rte_ether_addr_copy((struct rte_ether_addr *)dst_mac,
1302 : : &dn->eth_hdr.dst_addr);
1303 : : rte_ether_addr_copy((struct rte_ether_addr *)src_mac,
1304 : : &dn->eth_hdr.src_addr);
1305 : 2 : dn->eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
1306 : :
1307 : : /*
1308 : : * Initialize vlan header.
1309 : : */
1310 : 2 : dn->vlan_hdr.eth_proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
1311 : 2 : dn->vlan_hdr.vlan_tci = 32;
1312 : :
1313 : : /*
1314 : : * Initialize IP header.
1315 : : */
1316 : 2 : dn->ip_hdr.version_ihl = 0x45; /*IP_VERSION | IP_HDRLEN*/
1317 : 2 : dn->ip_hdr.time_to_live = 64; /* IP_DEFTTL */
1318 : 2 : dn->ip_hdr.next_proto_id = IPPROTO_TCP;
1319 : 2 : dn->ip_hdr.packet_id = rte_cpu_to_be_16(0x463c);
1320 : 2 : dn->ip_hdr.total_length = rte_cpu_to_be_16(60);
1321 [ - + ]: 2 : dn->ip_hdr.src_addr = rte_cpu_to_be_32(ip_src_addr);
1322 [ - + ]: 2 : dn->ip_hdr.dst_addr = rte_cpu_to_be_32(ip_dst_addr);
1323 : 2 : }
1324 : :
1325 : : static int
1326 : 2 : test_jump2_check(uint64_t rc, const void *arg)
1327 : : {
1328 : : const struct rte_ether_hdr *eth_hdr = arg;
1329 : : const struct rte_ipv4_hdr *ipv4_hdr;
1330 : : const void *next = eth_hdr;
1331 : : uint16_t eth_type;
1332 : : uint64_t v = -1;
1333 : :
1334 [ + - ]: 2 : if (eth_hdr->ether_type == htons(0x8100)) {
1335 : : const struct rte_vlan_hdr *vlan_hdr =
1336 : : (const void *)(eth_hdr + 1);
1337 : 2 : eth_type = vlan_hdr->eth_proto;
1338 : 2 : next = vlan_hdr + 1;
1339 : : } else {
1340 : : eth_type = eth_hdr->ether_type;
1341 : 0 : next = eth_hdr + 1;
1342 : : }
1343 : :
1344 [ + - ]: 2 : if (eth_type == htons(0x0800)) {
1345 : : ipv4_hdr = next;
1346 [ + - ]: 2 : if ((ipv4_hdr->dst_addr & rte_cpu_to_be_32(TEST_NETMASK)) ==
1347 : : rte_cpu_to_be_32(TEST_SUBNET)) {
1348 : : v = 0;
1349 : : }
1350 : : }
1351 : :
1352 : 2 : return cmp_res(__func__, v, rc, arg, arg, sizeof(arg));
1353 : : }
1354 : :
1355 : : /* alu (add, sub, and, or, xor, neg) test-cases */
1356 : : static const struct ebpf_insn test_alu1_prog[] = {
1357 : :
1358 : : {
1359 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1360 : : .dst_reg = EBPF_REG_2,
1361 : : .src_reg = EBPF_REG_1,
1362 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1363 : : },
1364 : : {
1365 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1366 : : .dst_reg = EBPF_REG_3,
1367 : : .src_reg = EBPF_REG_1,
1368 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1369 : : },
1370 : : {
1371 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1372 : : .dst_reg = EBPF_REG_4,
1373 : : .src_reg = EBPF_REG_1,
1374 : : .off = offsetof(struct dummy_vect8, in[1].u32),
1375 : : },
1376 : : {
1377 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1378 : : .dst_reg = EBPF_REG_5,
1379 : : .src_reg = EBPF_REG_1,
1380 : : .off = offsetof(struct dummy_vect8, in[1].u64),
1381 : : },
1382 : : {
1383 : : .code = (BPF_ALU | BPF_AND | BPF_K),
1384 : : .dst_reg = EBPF_REG_2,
1385 : : .imm = TEST_FILL_1,
1386 : : },
1387 : : {
1388 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1389 : : .dst_reg = EBPF_REG_3,
1390 : : .imm = TEST_FILL_1,
1391 : : },
1392 : : {
1393 : : .code = (BPF_ALU | BPF_XOR | BPF_K),
1394 : : .dst_reg = EBPF_REG_4,
1395 : : .imm = TEST_FILL_1,
1396 : : },
1397 : : {
1398 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1399 : : .dst_reg = EBPF_REG_5,
1400 : : .imm = TEST_FILL_1,
1401 : : },
1402 : : {
1403 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1404 : : .dst_reg = EBPF_REG_1,
1405 : : .src_reg = EBPF_REG_2,
1406 : : .off = offsetof(struct dummy_vect8, out[0].u64),
1407 : : },
1408 : : {
1409 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1410 : : .dst_reg = EBPF_REG_1,
1411 : : .src_reg = EBPF_REG_3,
1412 : : .off = offsetof(struct dummy_vect8, out[1].u64),
1413 : : },
1414 : : {
1415 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1416 : : .dst_reg = EBPF_REG_1,
1417 : : .src_reg = EBPF_REG_4,
1418 : : .off = offsetof(struct dummy_vect8, out[2].u64),
1419 : : },
1420 : : {
1421 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1422 : : .dst_reg = EBPF_REG_1,
1423 : : .src_reg = EBPF_REG_5,
1424 : : .off = offsetof(struct dummy_vect8, out[3].u64),
1425 : : },
1426 : : {
1427 : : .code = (BPF_ALU | BPF_OR | BPF_X),
1428 : : .dst_reg = EBPF_REG_2,
1429 : : .src_reg = EBPF_REG_3,
1430 : : },
1431 : : {
1432 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
1433 : : .dst_reg = EBPF_REG_3,
1434 : : .src_reg = EBPF_REG_4,
1435 : : },
1436 : : {
1437 : : .code = (BPF_ALU | BPF_SUB | BPF_X),
1438 : : .dst_reg = EBPF_REG_4,
1439 : : .src_reg = EBPF_REG_5,
1440 : : },
1441 : : {
1442 : : .code = (EBPF_ALU64 | BPF_AND | BPF_X),
1443 : : .dst_reg = EBPF_REG_5,
1444 : : .src_reg = EBPF_REG_2,
1445 : : },
1446 : : {
1447 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1448 : : .dst_reg = EBPF_REG_1,
1449 : : .src_reg = EBPF_REG_2,
1450 : : .off = offsetof(struct dummy_vect8, out[4].u64),
1451 : : },
1452 : : {
1453 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1454 : : .dst_reg = EBPF_REG_1,
1455 : : .src_reg = EBPF_REG_3,
1456 : : .off = offsetof(struct dummy_vect8, out[5].u64),
1457 : : },
1458 : : {
1459 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1460 : : .dst_reg = EBPF_REG_1,
1461 : : .src_reg = EBPF_REG_4,
1462 : : .off = offsetof(struct dummy_vect8, out[6].u64),
1463 : : },
1464 : : {
1465 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1466 : : .dst_reg = EBPF_REG_1,
1467 : : .src_reg = EBPF_REG_5,
1468 : : .off = offsetof(struct dummy_vect8, out[7].u64),
1469 : : },
1470 : : /* return (-r2 + (-r3)) */
1471 : : {
1472 : : .code = (BPF_ALU | BPF_NEG),
1473 : : .dst_reg = EBPF_REG_2,
1474 : : },
1475 : : {
1476 : : .code = (EBPF_ALU64 | BPF_NEG),
1477 : : .dst_reg = EBPF_REG_3,
1478 : : },
1479 : : {
1480 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1481 : : .dst_reg = EBPF_REG_2,
1482 : : .src_reg = EBPF_REG_3,
1483 : : },
1484 : : {
1485 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1486 : : .dst_reg = EBPF_REG_0,
1487 : : .src_reg = EBPF_REG_2,
1488 : : },
1489 : : {
1490 : : .code = (BPF_JMP | EBPF_EXIT),
1491 : : },
1492 : : };
1493 : :
1494 : : static int
1495 : 2 : test_alu1_check(uint64_t rc, const void *arg)
1496 : : {
1497 : : uint64_t r2, r3, r4, r5, rv;
1498 : : const struct dummy_vect8 *dvt;
1499 : : struct dummy_vect8 dve;
1500 : :
1501 : : dvt = arg;
1502 : : memset(&dve, 0, sizeof(dve));
1503 : :
1504 : 2 : r2 = dvt->in[0].u32;
1505 : 2 : r3 = dvt->in[0].u64;
1506 : 2 : r4 = dvt->in[1].u32;
1507 : 2 : r5 = dvt->in[1].u64;
1508 : :
1509 : 2 : r2 = (uint32_t)r2 & TEST_FILL_1;
1510 : 2 : r3 |= (int32_t) TEST_FILL_1;
1511 : 2 : r4 = (uint32_t)r4 ^ TEST_FILL_1;
1512 : 2 : r5 += (int32_t)TEST_FILL_1;
1513 : :
1514 : 2 : dve.out[0].u64 = r2;
1515 : 2 : dve.out[1].u64 = r3;
1516 : 2 : dve.out[2].u64 = r4;
1517 : 2 : dve.out[3].u64 = r5;
1518 : :
1519 : 2 : r2 = (uint32_t)r2 | (uint32_t)r3;
1520 : 2 : r3 ^= r4;
1521 : 2 : r4 = (uint32_t)r4 - (uint32_t)r5;
1522 : 2 : r5 &= r2;
1523 : :
1524 : 2 : dve.out[4].u64 = r2;
1525 : 2 : dve.out[5].u64 = r3;
1526 : 2 : dve.out[6].u64 = r4;
1527 : 2 : dve.out[7].u64 = r5;
1528 : :
1529 : 2 : r2 = -(int32_t)r2;
1530 : : rv = (uint32_t)r2;
1531 : : r3 = -r3;
1532 : : rv += r3;
1533 : :
1534 : 2 : return cmp_res(__func__, rv, rc, dve.out, dvt->out, sizeof(dve.out));
1535 : : }
1536 : :
1537 : : /* endianness conversions (BE->LE/LE->BE) test-cases */
1538 : : static const struct ebpf_insn test_bele1_prog[] = {
1539 : :
1540 : : {
1541 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1542 : : .dst_reg = EBPF_REG_2,
1543 : : .src_reg = EBPF_REG_1,
1544 : : .off = offsetof(struct dummy_vect8, in[0].u16),
1545 : : },
1546 : : {
1547 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1548 : : .dst_reg = EBPF_REG_3,
1549 : : .src_reg = EBPF_REG_1,
1550 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1551 : : },
1552 : : {
1553 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1554 : : .dst_reg = EBPF_REG_4,
1555 : : .src_reg = EBPF_REG_1,
1556 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1557 : : },
1558 : : {
1559 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1560 : : .dst_reg = EBPF_REG_2,
1561 : : .imm = sizeof(uint16_t) * CHAR_BIT,
1562 : : },
1563 : : {
1564 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1565 : : .dst_reg = EBPF_REG_3,
1566 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1567 : : },
1568 : : {
1569 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1570 : : .dst_reg = EBPF_REG_4,
1571 : : .imm = sizeof(uint64_t) * CHAR_BIT,
1572 : : },
1573 : : {
1574 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1575 : : .dst_reg = EBPF_REG_1,
1576 : : .src_reg = EBPF_REG_2,
1577 : : .off = offsetof(struct dummy_vect8, out[0].u64),
1578 : : },
1579 : : {
1580 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1581 : : .dst_reg = EBPF_REG_1,
1582 : : .src_reg = EBPF_REG_3,
1583 : : .off = offsetof(struct dummy_vect8, out[1].u64),
1584 : : },
1585 : : {
1586 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1587 : : .dst_reg = EBPF_REG_1,
1588 : : .src_reg = EBPF_REG_4,
1589 : : .off = offsetof(struct dummy_vect8, out[2].u64),
1590 : : },
1591 : : {
1592 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1593 : : .dst_reg = EBPF_REG_2,
1594 : : .src_reg = EBPF_REG_1,
1595 : : .off = offsetof(struct dummy_vect8, in[0].u16),
1596 : : },
1597 : : {
1598 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1599 : : .dst_reg = EBPF_REG_3,
1600 : : .src_reg = EBPF_REG_1,
1601 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1602 : : },
1603 : : {
1604 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1605 : : .dst_reg = EBPF_REG_4,
1606 : : .src_reg = EBPF_REG_1,
1607 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1608 : : },
1609 : : {
1610 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1611 : : .dst_reg = EBPF_REG_2,
1612 : : .imm = sizeof(uint16_t) * CHAR_BIT,
1613 : : },
1614 : : {
1615 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1616 : : .dst_reg = EBPF_REG_3,
1617 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1618 : : },
1619 : : {
1620 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1621 : : .dst_reg = EBPF_REG_4,
1622 : : .imm = sizeof(uint64_t) * CHAR_BIT,
1623 : : },
1624 : : {
1625 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1626 : : .dst_reg = EBPF_REG_1,
1627 : : .src_reg = EBPF_REG_2,
1628 : : .off = offsetof(struct dummy_vect8, out[3].u64),
1629 : : },
1630 : : {
1631 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1632 : : .dst_reg = EBPF_REG_1,
1633 : : .src_reg = EBPF_REG_3,
1634 : : .off = offsetof(struct dummy_vect8, out[4].u64),
1635 : : },
1636 : : {
1637 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1638 : : .dst_reg = EBPF_REG_1,
1639 : : .src_reg = EBPF_REG_4,
1640 : : .off = offsetof(struct dummy_vect8, out[5].u64),
1641 : : },
1642 : : /* return 1 */
1643 : : {
1644 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1645 : : .dst_reg = EBPF_REG_0,
1646 : : .imm = 1,
1647 : : },
1648 : : {
1649 : : .code = (BPF_JMP | EBPF_EXIT),
1650 : : },
1651 : : };
1652 : :
1653 : : static void
1654 : 2 : test_bele1_prepare(void *arg)
1655 : : {
1656 : : struct dummy_vect8 *dv;
1657 : :
1658 : : dv = arg;
1659 : :
1660 : : memset(dv, 0, sizeof(*dv));
1661 : 2 : dv->in[0].u64 = rte_rand();
1662 : 2 : dv->in[0].u32 = dv->in[0].u64;
1663 : 2 : dv->in[0].u16 = dv->in[0].u64;
1664 : 2 : }
1665 : :
1666 : : static int
1667 [ - + ]: 2 : test_bele1_check(uint64_t rc, const void *arg)
1668 : : {
1669 : : uint64_t r2, r3, r4;
1670 : : const struct dummy_vect8 *dvt;
1671 : : struct dummy_vect8 dve;
1672 : :
1673 : : dvt = arg;
1674 : : memset(&dve, 0, sizeof(dve));
1675 : :
1676 : 2 : r2 = dvt->in[0].u16;
1677 : 2 : r3 = dvt->in[0].u32;
1678 : 2 : r4 = dvt->in[0].u64;
1679 : :
1680 [ - + ]: 4 : r2 = rte_cpu_to_be_16(r2);
1681 [ - + ]: 4 : r3 = rte_cpu_to_be_32(r3);
1682 [ - + ]: 2 : r4 = rte_cpu_to_be_64(r4);
1683 : :
1684 : 2 : dve.out[0].u64 = r2;
1685 : 2 : dve.out[1].u64 = r3;
1686 : 2 : dve.out[2].u64 = r4;
1687 : :
1688 : : r2 = dvt->in[0].u16;
1689 : : r3 = dvt->in[0].u32;
1690 : : r4 = dvt->in[0].u64;
1691 : :
1692 : : r2 = rte_cpu_to_le_16(r2);
1693 : : r3 = rte_cpu_to_le_32(r3);
1694 : : r4 = rte_cpu_to_le_64(r4);
1695 : :
1696 : 2 : dve.out[3].u64 = r2;
1697 : 2 : dve.out[4].u64 = r3;
1698 : 2 : dve.out[5].u64 = r4;
1699 : :
1700 : 2 : return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
1701 : : }
1702 : :
1703 : : /* atomic add test-cases */
1704 : : static const struct ebpf_insn test_xadd1_prog[] = {
1705 : :
1706 : : {
1707 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1708 : : .dst_reg = EBPF_REG_2,
1709 : : .imm = 1,
1710 : : },
1711 : : {
1712 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1713 : : .dst_reg = EBPF_REG_1,
1714 : : .src_reg = EBPF_REG_2,
1715 : : .off = offsetof(struct dummy_offset, u32),
1716 : : },
1717 : : {
1718 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1719 : : .dst_reg = EBPF_REG_1,
1720 : : .src_reg = EBPF_REG_2,
1721 : : .off = offsetof(struct dummy_offset, u64),
1722 : : },
1723 : : {
1724 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1725 : : .dst_reg = EBPF_REG_3,
1726 : : .imm = -1,
1727 : : },
1728 : : {
1729 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1730 : : .dst_reg = EBPF_REG_1,
1731 : : .src_reg = EBPF_REG_3,
1732 : : .off = offsetof(struct dummy_offset, u32),
1733 : : },
1734 : : {
1735 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1736 : : .dst_reg = EBPF_REG_1,
1737 : : .src_reg = EBPF_REG_3,
1738 : : .off = offsetof(struct dummy_offset, u64),
1739 : : },
1740 : : {
1741 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1742 : : .dst_reg = EBPF_REG_4,
1743 : : .imm = TEST_FILL_1,
1744 : : },
1745 : : {
1746 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1747 : : .dst_reg = EBPF_REG_1,
1748 : : .src_reg = EBPF_REG_4,
1749 : : .off = offsetof(struct dummy_offset, u32),
1750 : : },
1751 : : {
1752 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1753 : : .dst_reg = EBPF_REG_1,
1754 : : .src_reg = EBPF_REG_4,
1755 : : .off = offsetof(struct dummy_offset, u64),
1756 : : },
1757 : : {
1758 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1759 : : .dst_reg = EBPF_REG_5,
1760 : : .imm = TEST_MUL_1,
1761 : : },
1762 : : {
1763 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1764 : : .dst_reg = EBPF_REG_1,
1765 : : .src_reg = EBPF_REG_5,
1766 : : .off = offsetof(struct dummy_offset, u32),
1767 : : },
1768 : : {
1769 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1770 : : .dst_reg = EBPF_REG_1,
1771 : : .src_reg = EBPF_REG_5,
1772 : : .off = offsetof(struct dummy_offset, u64),
1773 : : },
1774 : : {
1775 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1776 : : .dst_reg = EBPF_REG_6,
1777 : : .imm = TEST_MUL_2,
1778 : : },
1779 : : {
1780 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1781 : : .dst_reg = EBPF_REG_1,
1782 : : .src_reg = EBPF_REG_6,
1783 : : .off = offsetof(struct dummy_offset, u32),
1784 : : },
1785 : : {
1786 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1787 : : .dst_reg = EBPF_REG_1,
1788 : : .src_reg = EBPF_REG_6,
1789 : : .off = offsetof(struct dummy_offset, u64),
1790 : : },
1791 : : {
1792 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1793 : : .dst_reg = EBPF_REG_7,
1794 : : .imm = TEST_JCC_2,
1795 : : },
1796 : : {
1797 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1798 : : .dst_reg = EBPF_REG_1,
1799 : : .src_reg = EBPF_REG_7,
1800 : : .off = offsetof(struct dummy_offset, u32),
1801 : : },
1802 : : {
1803 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1804 : : .dst_reg = EBPF_REG_1,
1805 : : .src_reg = EBPF_REG_7,
1806 : : .off = offsetof(struct dummy_offset, u64),
1807 : : },
1808 : : {
1809 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1810 : : .dst_reg = EBPF_REG_8,
1811 : : .imm = TEST_JCC_3,
1812 : : },
1813 : : {
1814 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1815 : : .dst_reg = EBPF_REG_1,
1816 : : .src_reg = EBPF_REG_8,
1817 : : .off = offsetof(struct dummy_offset, u32),
1818 : : },
1819 : : {
1820 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1821 : : .dst_reg = EBPF_REG_1,
1822 : : .src_reg = EBPF_REG_8,
1823 : : .off = offsetof(struct dummy_offset, u64),
1824 : : },
1825 : : /* return 1 */
1826 : : {
1827 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1828 : : .dst_reg = EBPF_REG_0,
1829 : : .imm = 1,
1830 : : },
1831 : : {
1832 : : .code = (BPF_JMP | EBPF_EXIT),
1833 : : },
1834 : : };
1835 : :
1836 : : static int
1837 : 2 : test_xadd1_check(uint64_t rc, const void *arg)
1838 : : {
1839 : : uint64_t rv;
1840 : : const struct dummy_offset *dft;
1841 : : struct dummy_offset dfe;
1842 : :
1843 : : dft = arg;
1844 : : memset(&dfe, 0, sizeof(dfe));
1845 : :
1846 : : rv = 1;
1847 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1848 : : rte_memory_order_relaxed);
1849 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1850 : : rte_memory_order_relaxed);
1851 : :
1852 : : rv = -1;
1853 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1854 : : rte_memory_order_relaxed);
1855 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1856 : : rte_memory_order_relaxed);
1857 : :
1858 : : rv = (int32_t)TEST_FILL_1;
1859 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1860 : : rte_memory_order_relaxed);
1861 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1862 : : rte_memory_order_relaxed);
1863 : :
1864 : : rv = TEST_MUL_1;
1865 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1866 : : rte_memory_order_relaxed);
1867 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1868 : : rte_memory_order_relaxed);
1869 : :
1870 : : rv = TEST_MUL_2;
1871 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1872 : : rte_memory_order_relaxed);
1873 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1874 : : rte_memory_order_relaxed);
1875 : :
1876 : : rv = TEST_JCC_2;
1877 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1878 : : rte_memory_order_relaxed);
1879 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1880 : : rte_memory_order_relaxed);
1881 : :
1882 : : rv = TEST_JCC_3;
1883 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1884 : : rte_memory_order_relaxed);
1885 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1886 : : rte_memory_order_relaxed);
1887 : :
1888 : 2 : return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
1889 : : }
1890 : :
1891 : : /* alu div test-cases */
1892 : : static const struct ebpf_insn test_div1_prog[] = {
1893 : :
1894 : : {
1895 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1896 : : .dst_reg = EBPF_REG_2,
1897 : : .src_reg = EBPF_REG_1,
1898 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1899 : : },
1900 : : {
1901 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1902 : : .dst_reg = EBPF_REG_3,
1903 : : .src_reg = EBPF_REG_1,
1904 : : .off = offsetof(struct dummy_vect8, in[1].u64),
1905 : : },
1906 : : {
1907 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1908 : : .dst_reg = EBPF_REG_4,
1909 : : .src_reg = EBPF_REG_1,
1910 : : .off = offsetof(struct dummy_vect8, in[2].u32),
1911 : : },
1912 : : {
1913 : : .code = (BPF_ALU | BPF_DIV | BPF_K),
1914 : : .dst_reg = EBPF_REG_2,
1915 : : .imm = TEST_MUL_1,
1916 : : },
1917 : : {
1918 : : .code = (EBPF_ALU64 | BPF_MOD | BPF_K),
1919 : : .dst_reg = EBPF_REG_3,
1920 : : .imm = TEST_MUL_2,
1921 : : },
1922 : : {
1923 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1924 : : .dst_reg = EBPF_REG_2,
1925 : : .imm = 1,
1926 : : },
1927 : : {
1928 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1929 : : .dst_reg = EBPF_REG_3,
1930 : : .imm = 1,
1931 : : },
1932 : : {
1933 : : .code = (BPF_ALU | BPF_MOD | BPF_X),
1934 : : .dst_reg = EBPF_REG_4,
1935 : : .src_reg = EBPF_REG_2,
1936 : : },
1937 : : {
1938 : : .code = (EBPF_ALU64 | BPF_DIV | BPF_X),
1939 : : .dst_reg = EBPF_REG_4,
1940 : : .src_reg = EBPF_REG_3,
1941 : : },
1942 : : {
1943 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1944 : : .dst_reg = EBPF_REG_1,
1945 : : .src_reg = EBPF_REG_2,
1946 : : .off = offsetof(struct dummy_vect8, out[0].u64),
1947 : : },
1948 : : {
1949 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1950 : : .dst_reg = EBPF_REG_1,
1951 : : .src_reg = EBPF_REG_3,
1952 : : .off = offsetof(struct dummy_vect8, out[1].u64),
1953 : : },
1954 : : {
1955 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1956 : : .dst_reg = EBPF_REG_1,
1957 : : .src_reg = EBPF_REG_4,
1958 : : .off = offsetof(struct dummy_vect8, out[2].u64),
1959 : : },
1960 : : /* check that we can handle division by zero gracefully. */
1961 : : {
1962 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1963 : : .dst_reg = EBPF_REG_2,
1964 : : .src_reg = EBPF_REG_1,
1965 : : .off = offsetof(struct dummy_vect8, in[3].u32),
1966 : : },
1967 : : {
1968 : : .code = (BPF_ALU | BPF_DIV | BPF_X),
1969 : : .dst_reg = EBPF_REG_4,
1970 : : .src_reg = EBPF_REG_2,
1971 : : },
1972 : : /* return 1 */
1973 : : {
1974 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1975 : : .dst_reg = EBPF_REG_0,
1976 : : .imm = 1,
1977 : : },
1978 : : {
1979 : : .code = (BPF_JMP | EBPF_EXIT),
1980 : : },
1981 : : };
1982 : :
1983 : : static int
1984 : 2 : test_div1_check(uint64_t rc, const void *arg)
1985 : : {
1986 : : uint64_t r2, r3, r4;
1987 : : const struct dummy_vect8 *dvt;
1988 : : struct dummy_vect8 dve;
1989 : :
1990 : : dvt = arg;
1991 : : memset(&dve, 0, sizeof(dve));
1992 : :
1993 : 2 : r2 = dvt->in[0].u32;
1994 : 2 : r3 = dvt->in[1].u64;
1995 : 2 : r4 = dvt->in[2].u32;
1996 : :
1997 : 2 : r2 = (uint32_t)r2 / TEST_MUL_1;
1998 : 2 : r3 %= TEST_MUL_2;
1999 : 2 : r2 |= 1;
2000 : 2 : r3 |= 1;
2001 : 2 : r4 = (uint32_t)(r4 % r2);
2002 : 2 : r4 /= r3;
2003 : :
2004 : 2 : dve.out[0].u64 = r2;
2005 : 2 : dve.out[1].u64 = r3;
2006 : 2 : dve.out[2].u64 = r4;
2007 : :
2008 : : /*
2009 : : * in the test prog we attempted to divide by zero.
2010 : : * so return value should return 0.
2011 : : */
2012 : 2 : return cmp_res(__func__, 0, rc, dve.out, dvt->out, sizeof(dve.out));
2013 : : }
2014 : :
2015 : : /* call test-cases */
2016 : : static const struct ebpf_insn test_call1_prog[] = {
2017 : :
2018 : : {
2019 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
2020 : : .dst_reg = EBPF_REG_2,
2021 : : .src_reg = EBPF_REG_1,
2022 : : .off = offsetof(struct dummy_offset, u32),
2023 : : },
2024 : : {
2025 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2026 : : .dst_reg = EBPF_REG_3,
2027 : : .src_reg = EBPF_REG_1,
2028 : : .off = offsetof(struct dummy_offset, u64),
2029 : : },
2030 : : {
2031 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2032 : : .dst_reg = EBPF_REG_10,
2033 : : .src_reg = EBPF_REG_2,
2034 : : .off = -4,
2035 : : },
2036 : : {
2037 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
2038 : : .dst_reg = EBPF_REG_10,
2039 : : .src_reg = EBPF_REG_3,
2040 : : .off = -16,
2041 : : },
2042 : : {
2043 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2044 : : .dst_reg = EBPF_REG_2,
2045 : : .src_reg = EBPF_REG_10,
2046 : : },
2047 : : {
2048 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
2049 : : .dst_reg = EBPF_REG_2,
2050 : : .imm = 4,
2051 : : },
2052 : : {
2053 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2054 : : .dst_reg = EBPF_REG_3,
2055 : : .src_reg = EBPF_REG_10,
2056 : : },
2057 : : {
2058 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
2059 : : .dst_reg = EBPF_REG_3,
2060 : : .imm = 16,
2061 : : },
2062 : : {
2063 : : .code = (BPF_JMP | EBPF_CALL),
2064 : : .imm = 0,
2065 : : },
2066 : : {
2067 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
2068 : : .dst_reg = EBPF_REG_2,
2069 : : .src_reg = EBPF_REG_10,
2070 : : .off = -4,
2071 : : },
2072 : : {
2073 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2074 : : .dst_reg = EBPF_REG_0,
2075 : : .src_reg = EBPF_REG_10,
2076 : : .off = -16
2077 : : },
2078 : : {
2079 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2080 : : .dst_reg = EBPF_REG_0,
2081 : : .src_reg = EBPF_REG_2,
2082 : : },
2083 : : {
2084 : : .code = (BPF_JMP | EBPF_EXIT),
2085 : : },
2086 : : };
2087 : :
2088 : : static void
2089 : 2 : dummy_func1(const void *p, uint32_t *v32, uint64_t *v64)
2090 : : {
2091 : : const struct dummy_offset *dv;
2092 : :
2093 : : dv = p;
2094 : :
2095 : 4 : v32[0] += dv->u16;
2096 : 4 : v64[0] += dv->u8;
2097 : 2 : }
2098 : :
2099 : : static int
2100 : 2 : test_call1_check(uint64_t rc, const void *arg)
2101 : : {
2102 : : uint32_t v32;
2103 : : uint64_t v64;
2104 : : const struct dummy_offset *dv;
2105 : :
2106 : : dv = arg;
2107 : :
2108 : 2 : v32 = dv->u32;
2109 : 2 : v64 = dv->u64;
2110 : : dummy_func1(arg, &v32, &v64);
2111 : 2 : v64 += v32;
2112 : :
2113 : 2 : return cmp_res(__func__, v64, rc, dv, dv, sizeof(*dv));
2114 : : }
2115 : :
2116 : : static const struct rte_bpf_xsym test_call1_xsym[] = {
2117 : : {
2118 : : .name = RTE_STR(dummy_func1),
2119 : : .type = RTE_BPF_XTYPE_FUNC,
2120 : : .func = {
2121 : : .val = (void *)dummy_func1,
2122 : : .nb_args = 3,
2123 : : .args = {
2124 : : [0] = {
2125 : : .type = RTE_BPF_ARG_PTR,
2126 : : .size = sizeof(struct dummy_offset),
2127 : : },
2128 : : [1] = {
2129 : : .type = RTE_BPF_ARG_PTR,
2130 : : .size = sizeof(uint32_t),
2131 : : },
2132 : : [2] = {
2133 : : .type = RTE_BPF_ARG_PTR,
2134 : : .size = sizeof(uint64_t),
2135 : : },
2136 : : },
2137 : : },
2138 : : },
2139 : : };
2140 : :
2141 : : static const struct ebpf_insn test_call2_prog[] = {
2142 : :
2143 : : {
2144 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2145 : : .dst_reg = EBPF_REG_1,
2146 : : .src_reg = EBPF_REG_10,
2147 : : },
2148 : : {
2149 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2150 : : .dst_reg = EBPF_REG_1,
2151 : : .imm = -(int32_t)sizeof(struct dummy_offset),
2152 : : },
2153 : : {
2154 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2155 : : .dst_reg = EBPF_REG_2,
2156 : : .src_reg = EBPF_REG_10,
2157 : : },
2158 : : {
2159 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2160 : : .dst_reg = EBPF_REG_2,
2161 : : .imm = -2 * (int32_t)sizeof(struct dummy_offset),
2162 : : },
2163 : : {
2164 : : .code = (BPF_JMP | EBPF_CALL),
2165 : : .imm = 0,
2166 : : },
2167 : : {
2168 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2169 : : .dst_reg = EBPF_REG_1,
2170 : : .src_reg = EBPF_REG_10,
2171 : : .off = -(int32_t)(sizeof(struct dummy_offset) -
2172 : : offsetof(struct dummy_offset, u64)),
2173 : : },
2174 : : {
2175 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
2176 : : .dst_reg = EBPF_REG_0,
2177 : : .src_reg = EBPF_REG_10,
2178 : : .off = -(int32_t)(sizeof(struct dummy_offset) -
2179 : : offsetof(struct dummy_offset, u32)),
2180 : : },
2181 : : {
2182 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2183 : : .dst_reg = EBPF_REG_0,
2184 : : .src_reg = EBPF_REG_1,
2185 : : },
2186 : : {
2187 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
2188 : : .dst_reg = EBPF_REG_1,
2189 : : .src_reg = EBPF_REG_10,
2190 : : .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
2191 : : offsetof(struct dummy_offset, u16)),
2192 : : },
2193 : : {
2194 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2195 : : .dst_reg = EBPF_REG_0,
2196 : : .src_reg = EBPF_REG_1,
2197 : : },
2198 : : {
2199 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2200 : : .dst_reg = EBPF_REG_1,
2201 : : .src_reg = EBPF_REG_10,
2202 : : .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
2203 : : offsetof(struct dummy_offset, u8)),
2204 : : },
2205 : : {
2206 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2207 : : .dst_reg = EBPF_REG_0,
2208 : : .src_reg = EBPF_REG_1,
2209 : : },
2210 : : {
2211 : : .code = (BPF_JMP | EBPF_EXIT),
2212 : : },
2213 : :
2214 : : };
2215 : :
2216 : : static void
2217 : 2 : dummy_func2(struct dummy_offset *a, struct dummy_offset *b)
2218 : : {
2219 : : uint64_t v;
2220 : :
2221 : : v = 0;
2222 : 2 : a->u64 = v++;
2223 : 2 : a->u32 = v++;
2224 : 2 : a->u16 = v++;
2225 : 2 : a->u8 = v++;
2226 : 2 : b->u64 = v++;
2227 : 2 : b->u32 = v++;
2228 : 2 : b->u16 = v++;
2229 : 2 : b->u8 = v++;
2230 : 2 : }
2231 : :
2232 : : static int
2233 : 2 : test_call2_check(uint64_t rc, const void *arg)
2234 : : {
2235 : : uint64_t v;
2236 : : struct dummy_offset a, b;
2237 : :
2238 : : RTE_SET_USED(arg);
2239 : :
2240 : : dummy_func2(&a, &b);
2241 : : v = a.u64 + a.u32 + b.u16 + b.u8;
2242 : :
2243 : 2 : return cmp_res(__func__, v, rc, arg, arg, 0);
2244 : : }
2245 : :
2246 : : static const struct rte_bpf_xsym test_call2_xsym[] = {
2247 : : {
2248 : : .name = RTE_STR(dummy_func2),
2249 : : .type = RTE_BPF_XTYPE_FUNC,
2250 : : .func = {
2251 : : .val = (void *)dummy_func2,
2252 : : .nb_args = 2,
2253 : : .args = {
2254 : : [0] = {
2255 : : .type = RTE_BPF_ARG_PTR,
2256 : : .size = sizeof(struct dummy_offset),
2257 : : },
2258 : : [1] = {
2259 : : .type = RTE_BPF_ARG_PTR,
2260 : : .size = sizeof(struct dummy_offset),
2261 : : },
2262 : : },
2263 : : },
2264 : : },
2265 : : };
2266 : :
2267 : : static const struct ebpf_insn test_call3_prog[] = {
2268 : :
2269 : : {
2270 : : .code = (BPF_JMP | EBPF_CALL),
2271 : : .imm = 0,
2272 : : },
2273 : : {
2274 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2275 : : .dst_reg = EBPF_REG_2,
2276 : : .src_reg = EBPF_REG_0,
2277 : : .off = offsetof(struct dummy_offset, u8),
2278 : : },
2279 : : {
2280 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
2281 : : .dst_reg = EBPF_REG_3,
2282 : : .src_reg = EBPF_REG_0,
2283 : : .off = offsetof(struct dummy_offset, u16),
2284 : : },
2285 : : {
2286 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
2287 : : .dst_reg = EBPF_REG_4,
2288 : : .src_reg = EBPF_REG_0,
2289 : : .off = offsetof(struct dummy_offset, u32),
2290 : : },
2291 : : {
2292 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2293 : : .dst_reg = EBPF_REG_0,
2294 : : .src_reg = EBPF_REG_0,
2295 : : .off = offsetof(struct dummy_offset, u64),
2296 : : },
2297 : : /* return sum */
2298 : : {
2299 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2300 : : .dst_reg = EBPF_REG_0,
2301 : : .src_reg = EBPF_REG_4,
2302 : : },
2303 : : {
2304 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2305 : : .dst_reg = EBPF_REG_0,
2306 : : .src_reg = EBPF_REG_3,
2307 : : },
2308 : : {
2309 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2310 : : .dst_reg = EBPF_REG_0,
2311 : : .src_reg = EBPF_REG_2,
2312 : : },
2313 : : {
2314 : : .code = (BPF_JMP | EBPF_EXIT),
2315 : : },
2316 : : };
2317 : :
2318 : : static const struct dummy_offset *
2319 : 2 : dummy_func3(const struct dummy_vect8 *p)
2320 : : {
2321 : 2 : return &p->in[RTE_DIM(p->in) - 1];
2322 : : }
2323 : :
2324 : : static void
2325 : 2 : test_call3_prepare(void *arg)
2326 : : {
2327 : : struct dummy_vect8 *pv;
2328 : : struct dummy_offset *df;
2329 : :
2330 : : pv = arg;
2331 : : df = (struct dummy_offset *)(uintptr_t)dummy_func3(pv);
2332 : :
2333 : : memset(pv, 0, sizeof(*pv));
2334 : 2 : df->u64 = (int32_t)TEST_FILL_1;
2335 : 2 : df->u32 = df->u64;
2336 : 2 : df->u16 = df->u64;
2337 : 2 : df->u8 = df->u64;
2338 : 2 : }
2339 : :
2340 : : static int
2341 : 2 : test_call3_check(uint64_t rc, const void *arg)
2342 : : {
2343 : : uint64_t v;
2344 : : const struct dummy_vect8 *pv;
2345 : : const struct dummy_offset *dft;
2346 : :
2347 : : pv = arg;
2348 : : dft = dummy_func3(pv);
2349 : :
2350 : 2 : v = dft->u64;
2351 : 2 : v += dft->u32;
2352 : 2 : v += dft->u16;
2353 : 2 : v += dft->u8;
2354 : :
2355 : 2 : return cmp_res(__func__, v, rc, pv, pv, sizeof(*pv));
2356 : : }
2357 : :
2358 : : static const struct rte_bpf_xsym test_call3_xsym[] = {
2359 : : {
2360 : : .name = RTE_STR(dummy_func3),
2361 : : .type = RTE_BPF_XTYPE_FUNC,
2362 : : .func = {
2363 : : .val = (void *)dummy_func3,
2364 : : .nb_args = 1,
2365 : : .args = {
2366 : : [0] = {
2367 : : .type = RTE_BPF_ARG_PTR,
2368 : : .size = sizeof(struct dummy_vect8),
2369 : : },
2370 : : },
2371 : : .ret = {
2372 : : .type = RTE_BPF_ARG_PTR,
2373 : : .size = sizeof(struct dummy_offset),
2374 : : },
2375 : : },
2376 : : },
2377 : : };
2378 : :
2379 : : /* Test for stack corruption in multiple function calls */
2380 : : static const struct ebpf_insn test_call4_prog[] = {
2381 : : {
2382 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2383 : : .dst_reg = EBPF_REG_10,
2384 : : .off = -4,
2385 : : .imm = 1,
2386 : : },
2387 : : {
2388 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2389 : : .dst_reg = EBPF_REG_10,
2390 : : .off = -3,
2391 : : .imm = 2,
2392 : : },
2393 : : {
2394 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2395 : : .dst_reg = EBPF_REG_10,
2396 : : .off = -2,
2397 : : .imm = 3,
2398 : : },
2399 : : {
2400 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2401 : : .dst_reg = EBPF_REG_10,
2402 : : .off = -1,
2403 : : .imm = 4,
2404 : : },
2405 : : {
2406 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2407 : : .dst_reg = EBPF_REG_1,
2408 : : .src_reg = EBPF_REG_10,
2409 : : },
2410 : : {
2411 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2412 : : .dst_reg = EBPF_REG_2,
2413 : : .imm = 4,
2414 : : },
2415 : : {
2416 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_X),
2417 : : .dst_reg = EBPF_REG_1,
2418 : : .src_reg = EBPF_REG_2,
2419 : : },
2420 : : {
2421 : : .code = (BPF_JMP | EBPF_CALL),
2422 : : .imm = 0,
2423 : : },
2424 : : {
2425 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2426 : : .dst_reg = EBPF_REG_1,
2427 : : .src_reg = EBPF_REG_10,
2428 : : .off = -4,
2429 : : },
2430 : : {
2431 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2432 : : .dst_reg = EBPF_REG_2,
2433 : : .src_reg = EBPF_REG_10,
2434 : : .off = -3,
2435 : : },
2436 : : {
2437 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2438 : : .dst_reg = EBPF_REG_3,
2439 : : .src_reg = EBPF_REG_10,
2440 : : .off = -2,
2441 : : },
2442 : : {
2443 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2444 : : .dst_reg = EBPF_REG_4,
2445 : : .src_reg = EBPF_REG_10,
2446 : : .off = -1,
2447 : : },
2448 : : {
2449 : : .code = (BPF_JMP | EBPF_CALL),
2450 : : .imm = 1,
2451 : : },
2452 : : {
2453 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_K),
2454 : : .dst_reg = EBPF_REG_0,
2455 : : .imm = TEST_MEMFROB,
2456 : : },
2457 : : {
2458 : : .code = (BPF_JMP | EBPF_EXIT),
2459 : : },
2460 : : };
2461 : :
2462 : : /* Gathering the bytes together */
2463 : : static uint32_t
2464 : 2 : dummy_func4_1(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
2465 : : {
2466 : 4 : return (a << 24) | (b << 16) | (c << 8) | (d << 0);
2467 : : }
2468 : :
2469 : : /* Implementation of memfrob */
2470 : : static uint32_t
2471 : 2 : dummy_func4_0(uint32_t *s, uint8_t n)
2472 : : {
2473 : : char *p = (char *) s;
2474 [ + + + + ]: 20 : while (n-- > 0)
2475 : 16 : *p++ ^= 42;
2476 : 2 : return *s;
2477 : : }
2478 : :
2479 : :
2480 : : static int
2481 : 2 : test_call4_check(uint64_t rc, const void *arg)
2482 : : {
2483 : 2 : uint8_t a[4] = {1, 2, 3, 4};
2484 : : uint32_t s, v = 0;
2485 : :
2486 : : RTE_SET_USED(arg);
2487 : :
2488 : : s = dummy_func4_0((uint32_t *)a, 4);
2489 : :
2490 : 2 : s = dummy_func4_1(a[0], a[1], a[2], a[3]);
2491 : :
2492 : 2 : v = s ^ TEST_MEMFROB;
2493 : :
2494 : 2 : return cmp_res(__func__, v, rc, &v, &rc, sizeof(v));
2495 : : }
2496 : :
2497 : : static const struct rte_bpf_xsym test_call4_xsym[] = {
2498 : : [0] = {
2499 : : .name = RTE_STR(dummy_func4_0),
2500 : : .type = RTE_BPF_XTYPE_FUNC,
2501 : : .func = {
2502 : : .val = (void *)dummy_func4_0,
2503 : : .nb_args = 2,
2504 : : .args = {
2505 : : [0] = {
2506 : : .type = RTE_BPF_ARG_PTR,
2507 : : .size = 4 * sizeof(uint8_t),
2508 : : },
2509 : : [1] = {
2510 : : .type = RTE_BPF_ARG_RAW,
2511 : : .size = sizeof(uint8_t),
2512 : : },
2513 : : },
2514 : : .ret = {
2515 : : .type = RTE_BPF_ARG_RAW,
2516 : : .size = sizeof(uint32_t),
2517 : : },
2518 : : },
2519 : : },
2520 : : [1] = {
2521 : : .name = RTE_STR(dummy_func4_1),
2522 : : .type = RTE_BPF_XTYPE_FUNC,
2523 : : .func = {
2524 : : .val = (void *)dummy_func4_1,
2525 : : .nb_args = 4,
2526 : : .args = {
2527 : : [0] = {
2528 : : .type = RTE_BPF_ARG_RAW,
2529 : : .size = sizeof(uint8_t),
2530 : : },
2531 : : [1] = {
2532 : : .type = RTE_BPF_ARG_RAW,
2533 : : .size = sizeof(uint8_t),
2534 : : },
2535 : : [2] = {
2536 : : .type = RTE_BPF_ARG_RAW,
2537 : : .size = sizeof(uint8_t),
2538 : : },
2539 : : [3] = {
2540 : : .type = RTE_BPF_ARG_RAW,
2541 : : .size = sizeof(uint8_t),
2542 : : },
2543 : : },
2544 : : .ret = {
2545 : : .type = RTE_BPF_ARG_RAW,
2546 : : .size = sizeof(uint32_t),
2547 : : },
2548 : : },
2549 : : },
2550 : : };
2551 : :
2552 : : /* string compare test case */
2553 : : static const struct ebpf_insn test_call5_prog[] = {
2554 : :
2555 : : [0] = {
2556 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2557 : : .dst_reg = EBPF_REG_1,
2558 : : .imm = STRING_GEEK,
2559 : : },
2560 : : [1] = {
2561 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2562 : : .dst_reg = EBPF_REG_10,
2563 : : .src_reg = EBPF_REG_1,
2564 : : .off = -8,
2565 : : },
2566 : : [2] = {
2567 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2568 : : .dst_reg = EBPF_REG_6,
2569 : : .imm = 0,
2570 : : },
2571 : : [3] = {
2572 : : .code = (BPF_STX | BPF_MEM | BPF_B),
2573 : : .dst_reg = EBPF_REG_10,
2574 : : .src_reg = EBPF_REG_6,
2575 : : .off = -4,
2576 : : },
2577 : : [4] = {
2578 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2579 : : .dst_reg = EBPF_REG_10,
2580 : : .src_reg = EBPF_REG_6,
2581 : : .off = -12,
2582 : : },
2583 : : [5] = {
2584 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2585 : : .dst_reg = EBPF_REG_1,
2586 : : .imm = STRING_WEEK,
2587 : : },
2588 : : [6] = {
2589 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2590 : : .dst_reg = EBPF_REG_10,
2591 : : .src_reg = EBPF_REG_1,
2592 : : .off = -16,
2593 : : },
2594 : : [7] = {
2595 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2596 : : .dst_reg = EBPF_REG_1,
2597 : : .src_reg = EBPF_REG_10,
2598 : : },
2599 : : [8] = {
2600 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2601 : : .dst_reg = EBPF_REG_1,
2602 : : .imm = -8,
2603 : : },
2604 : : [9] = {
2605 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2606 : : .dst_reg = EBPF_REG_2,
2607 : : .src_reg = EBPF_REG_1,
2608 : : },
2609 : : [10] = {
2610 : : .code = (BPF_JMP | EBPF_CALL),
2611 : : .imm = 0,
2612 : : },
2613 : : [11] = {
2614 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2615 : : .dst_reg = EBPF_REG_1,
2616 : : .src_reg = EBPF_REG_0,
2617 : : },
2618 : : [12] = {
2619 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
2620 : : .dst_reg = EBPF_REG_0,
2621 : : .imm = -1,
2622 : : },
2623 : : [13] = {
2624 : : .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
2625 : : .dst_reg = EBPF_REG_1,
2626 : : .imm = 0x20,
2627 : : },
2628 : : [14] = {
2629 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2630 : : .dst_reg = EBPF_REG_1,
2631 : : .imm = 0x20,
2632 : : },
2633 : : [15] = {
2634 : : .code = (BPF_JMP | EBPF_JNE | BPF_K),
2635 : : .dst_reg = EBPF_REG_1,
2636 : : .off = 11,
2637 : : .imm = 0,
2638 : : },
2639 : : [16] = {
2640 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2641 : : .dst_reg = EBPF_REG_1,
2642 : : .src_reg = EBPF_REG_10,
2643 : : },
2644 : : [17] = {
2645 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2646 : : .dst_reg = EBPF_REG_1,
2647 : : .imm = -8,
2648 : : },
2649 : : [18] = {
2650 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2651 : : .dst_reg = EBPF_REG_2,
2652 : : .src_reg = EBPF_REG_10,
2653 : : },
2654 : : [19] = {
2655 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2656 : : .dst_reg = EBPF_REG_2,
2657 : : .imm = -16,
2658 : : },
2659 : : [20] = {
2660 : : .code = (BPF_JMP | EBPF_CALL),
2661 : : .imm = 0,
2662 : : },
2663 : : [21] = {
2664 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2665 : : .dst_reg = EBPF_REG_1,
2666 : : .src_reg = EBPF_REG_0,
2667 : : },
2668 : : [22] = {
2669 : : .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
2670 : : .dst_reg = EBPF_REG_1,
2671 : : .imm = 0x20,
2672 : : },
2673 : : [23] = {
2674 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2675 : : .dst_reg = EBPF_REG_1,
2676 : : .imm = 0x20,
2677 : : },
2678 : : [24] = {
2679 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2680 : : .dst_reg = EBPF_REG_0,
2681 : : .src_reg = EBPF_REG_1,
2682 : : },
2683 : : [25] = {
2684 : : .code = (BPF_JMP | BPF_JEQ | BPF_X),
2685 : : .dst_reg = EBPF_REG_1,
2686 : : .src_reg = EBPF_REG_6,
2687 : : .off = 1,
2688 : : },
2689 : : [26] = {
2690 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2691 : : .dst_reg = EBPF_REG_0,
2692 : : .imm = 0,
2693 : : },
2694 : : [27] = {
2695 : : .code = (BPF_JMP | EBPF_EXIT),
2696 : : },
2697 : : };
2698 : :
2699 : : /* String comparison implementation, return 0 if equal else difference */
2700 : : static uint32_t
2701 : 4 : dummy_func5(const char *s1, const char *s2)
2702 : : {
2703 [ + + + + : 22 : while (*s1 && (*s1 == *s2)) {
+ + ]
2704 : 8 : s1++;
2705 : 8 : s2++;
2706 : : }
2707 : 4 : return *(const unsigned char *)s1 - *(const unsigned char *)s2;
2708 : : }
2709 : :
2710 : : static int
2711 : 2 : test_call5_check(uint64_t rc, const void *arg)
2712 : : {
2713 : 2 : char a[] = "geek";
2714 : : char b[] = "week";
2715 : : uint32_t v;
2716 : :
2717 : : RTE_SET_USED(arg);
2718 : :
2719 : 2 : v = dummy_func5(a, a);
2720 : : if (v != 0) {
2721 : : v = -1;
2722 : : goto fail;
2723 : : }
2724 : :
2725 : : v = dummy_func5(a, b);
2726 : : if (v == 0)
2727 : : goto fail;
2728 : :
2729 : : v = 0;
2730 : :
2731 : : fail:
2732 : 2 : return cmp_res(__func__, v, rc, &v, &rc, sizeof(v));
2733 : : }
2734 : :
2735 : : static const struct rte_bpf_xsym test_call5_xsym[] = {
2736 : : [0] = {
2737 : : .name = RTE_STR(dummy_func5),
2738 : : .type = RTE_BPF_XTYPE_FUNC,
2739 : : .func = {
2740 : : .val = (void *)dummy_func5,
2741 : : .nb_args = 2,
2742 : : .args = {
2743 : : [0] = {
2744 : : .type = RTE_BPF_ARG_PTR,
2745 : : .size = sizeof(char),
2746 : : },
2747 : : [1] = {
2748 : : .type = RTE_BPF_ARG_PTR,
2749 : : .size = sizeof(char),
2750 : : },
2751 : : },
2752 : : .ret = {
2753 : : .type = RTE_BPF_ARG_RAW,
2754 : : .size = sizeof(uint32_t),
2755 : : },
2756 : : },
2757 : : },
2758 : : };
2759 : :
2760 : : /* load mbuf (BPF_ABS/BPF_IND) test-cases */
2761 : : static const struct ebpf_insn test_ld_mbuf1_prog[] = {
2762 : :
2763 : : /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
2764 : : {
2765 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2766 : : .dst_reg = EBPF_REG_6,
2767 : : .src_reg = EBPF_REG_1,
2768 : : },
2769 : : /* load IPv4 version and IHL */
2770 : : {
2771 : : .code = (BPF_LD | BPF_ABS | BPF_B),
2772 : : .imm = offsetof(struct rte_ipv4_hdr, version_ihl),
2773 : : },
2774 : : /* check IP version */
2775 : : {
2776 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2777 : : .dst_reg = EBPF_REG_2,
2778 : : .src_reg = EBPF_REG_0,
2779 : : },
2780 : : {
2781 : : .code = (BPF_ALU | BPF_AND | BPF_K),
2782 : : .dst_reg = EBPF_REG_2,
2783 : : .imm = 0xf0,
2784 : : },
2785 : : {
2786 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
2787 : : .dst_reg = EBPF_REG_2,
2788 : : .imm = IPVERSION << 4,
2789 : : .off = 2,
2790 : : },
2791 : : /* invalid IP version, return 0 */
2792 : : {
2793 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
2794 : : .dst_reg = EBPF_REG_0,
2795 : : .src_reg = EBPF_REG_0,
2796 : : },
2797 : : {
2798 : : .code = (BPF_JMP | EBPF_EXIT),
2799 : : },
2800 : : /* load 3-rd byte of IP data */
2801 : : {
2802 : : .code = (BPF_ALU | BPF_AND | BPF_K),
2803 : : .dst_reg = EBPF_REG_0,
2804 : : .imm = RTE_IPV4_HDR_IHL_MASK,
2805 : : },
2806 : : {
2807 : : .code = (BPF_ALU | BPF_LSH | BPF_K),
2808 : : .dst_reg = EBPF_REG_0,
2809 : : .imm = 2,
2810 : : },
2811 : : {
2812 : : .code = (BPF_LD | BPF_IND | BPF_B),
2813 : : .src_reg = EBPF_REG_0,
2814 : : .imm = 3,
2815 : : },
2816 : : {
2817 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2818 : : .dst_reg = EBPF_REG_7,
2819 : : .src_reg = EBPF_REG_0,
2820 : : },
2821 : : /* load IPv4 src addr */
2822 : : {
2823 : : .code = (BPF_LD | BPF_ABS | BPF_W),
2824 : : .imm = offsetof(struct rte_ipv4_hdr, src_addr),
2825 : : },
2826 : : {
2827 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2828 : : .dst_reg = EBPF_REG_7,
2829 : : .src_reg = EBPF_REG_0,
2830 : : },
2831 : : /* load IPv4 total length */
2832 : : {
2833 : : .code = (BPF_LD | BPF_ABS | BPF_H),
2834 : : .imm = offsetof(struct rte_ipv4_hdr, total_length),
2835 : : },
2836 : : {
2837 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2838 : : .dst_reg = EBPF_REG_8,
2839 : : .src_reg = EBPF_REG_0,
2840 : : },
2841 : : /* load last 4 bytes of IP data */
2842 : : {
2843 : : .code = (BPF_LD | BPF_IND | BPF_W),
2844 : : .src_reg = EBPF_REG_8,
2845 : : .imm = -(int32_t)sizeof(uint32_t),
2846 : : },
2847 : : {
2848 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2849 : : .dst_reg = EBPF_REG_7,
2850 : : .src_reg = EBPF_REG_0,
2851 : : },
2852 : : /* load 2 bytes from the middle of IP data */
2853 : : {
2854 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2855 : : .dst_reg = EBPF_REG_8,
2856 : : .imm = 1,
2857 : : },
2858 : : {
2859 : : .code = (BPF_LD | BPF_IND | BPF_H),
2860 : : .src_reg = EBPF_REG_8,
2861 : : },
2862 : : {
2863 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2864 : : .dst_reg = EBPF_REG_0,
2865 : : .src_reg = EBPF_REG_7,
2866 : : },
2867 : : {
2868 : : .code = (BPF_JMP | EBPF_EXIT),
2869 : : },
2870 : : };
2871 : :
2872 : : static void
2873 : 13 : dummy_mbuf_prep(struct rte_mbuf *mb, uint8_t buf[], uint32_t buf_len,
2874 : : uint32_t data_len)
2875 : : {
2876 : : uint32_t i;
2877 : : uint8_t *db;
2878 : :
2879 : 13 : mb->buf_addr = buf;
2880 [ + - ]: 13 : rte_mbuf_iova_set(mb, (uintptr_t)buf);
2881 [ + - ]: 13 : mb->buf_len = buf_len;
2882 : : rte_mbuf_refcnt_set(mb, 1);
2883 : :
2884 : : /* set pool pointer to dummy value, test doesn't use it */
2885 [ + - ]: 13 : mb->pool = (void *)buf;
2886 : :
2887 : : rte_pktmbuf_reset(mb);
2888 [ + - ]: 13 : db = (uint8_t *)rte_pktmbuf_append(mb, data_len);
2889 : :
2890 [ + + ]: 2513 : for (i = 0; i != data_len; i++)
2891 : 2500 : db[i] = i;
2892 : 13 : }
2893 : :
2894 : : static void
2895 : 6 : test_ld_mbuf1_prepare(void *arg)
2896 : : {
2897 : : struct dummy_mbuf *dm;
2898 : : struct rte_ipv4_hdr *ph;
2899 : :
2900 : : const uint32_t plen = 400;
2901 : 6 : const struct rte_ipv4_hdr iph = {
2902 : : .version_ihl = RTE_IPV4_VHL_DEF,
2903 : : .total_length = rte_cpu_to_be_16(plen),
2904 : : .time_to_live = IPDEFTTL,
2905 : : .next_proto_id = IPPROTO_RAW,
2906 : : .src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK),
2907 : : .dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST),
2908 : : };
2909 : :
2910 : : dm = arg;
2911 : : memset(dm, 0, sizeof(*dm));
2912 : :
2913 : 6 : dummy_mbuf_prep(&dm->mb[0], dm->buf[0], sizeof(dm->buf[0]),
2914 : : plen / 2 + 1);
2915 : 6 : dummy_mbuf_prep(&dm->mb[1], dm->buf[1], sizeof(dm->buf[0]),
2916 : : plen / 2 - 1);
2917 : :
2918 : : rte_pktmbuf_chain(&dm->mb[0], &dm->mb[1]);
2919 : :
2920 : 6 : ph = rte_pktmbuf_mtod(dm->mb, typeof(ph));
2921 : : memcpy(ph, &iph, sizeof(iph));
2922 : 6 : }
2923 : :
2924 : : static uint64_t
2925 [ + - ]: 4 : test_ld_mbuf1(const struct rte_mbuf *pkt)
2926 : : {
2927 : : uint64_t n, v;
2928 : : const uint8_t *p8;
2929 : : const uint16_t *p16;
2930 : : const uint32_t *p32;
2931 : : struct dummy_offset dof;
2932 : :
2933 : : /* load IPv4 version and IHL */
2934 : : p8 = rte_pktmbuf_read(pkt,
2935 : : offsetof(struct rte_ipv4_hdr, version_ihl), sizeof(*p8),
2936 : : &dof);
2937 [ + - ]: 4 : if (p8 == NULL)
2938 : : return 0;
2939 : :
2940 : : /* check IP version */
2941 [ + - ]: 4 : if ((p8[0] & 0xf0) != IPVERSION << 4)
2942 : : return 0;
2943 : :
2944 : 4 : n = (p8[0] & RTE_IPV4_HDR_IHL_MASK) * RTE_IPV4_IHL_MULTIPLIER;
2945 : :
2946 : : /* load 3-rd byte of IP data */
2947 [ + - ]: 4 : p8 = rte_pktmbuf_read(pkt, n + 3, sizeof(*p8), &dof);
2948 [ + - ]: 4 : if (p8 == NULL)
2949 : : return 0;
2950 : :
2951 [ + - ]: 4 : v = p8[0];
2952 : :
2953 : : /* load IPv4 src addr */
2954 : : p32 = rte_pktmbuf_read(pkt,
2955 : : offsetof(struct rte_ipv4_hdr, src_addr), sizeof(*p32),
2956 : : &dof);
2957 [ + - ]: 4 : if (p32 == NULL)
2958 : : return 0;
2959 : :
2960 [ - + + - ]: 8 : v += rte_be_to_cpu_32(p32[0]);
2961 : :
2962 : : /* load IPv4 total length */
2963 : : p16 = rte_pktmbuf_read(pkt,
2964 : : offsetof(struct rte_ipv4_hdr, total_length), sizeof(*p16),
2965 : : &dof);
2966 [ + - ]: 4 : if (p16 == NULL)
2967 : : return 0;
2968 : :
2969 [ - + ]: 8 : n = rte_be_to_cpu_16(p16[0]);
2970 : :
2971 : : /* load last 4 bytes of IP data */
2972 [ - + ]: 4 : p32 = rte_pktmbuf_read(pkt, n - sizeof(*p32), sizeof(*p32), &dof);
2973 [ + - ]: 4 : if (p32 == NULL)
2974 : : return 0;
2975 : :
2976 [ - + ]: 4 : v += rte_be_to_cpu_32(p32[0]);
2977 : :
2978 : : /* load 2 bytes from the middle of IP data */
2979 [ - + ]: 4 : p16 = rte_pktmbuf_read(pkt, n / 2, sizeof(*p16), &dof);
2980 [ + - ]: 4 : if (p16 == NULL)
2981 : : return 0;
2982 : :
2983 [ - + ]: 4 : v += rte_be_to_cpu_16(p16[0]);
2984 : 4 : return v;
2985 : : }
2986 : :
2987 : : static int
2988 : 4 : test_ld_mbuf1_check(uint64_t rc, const void *arg)
2989 : : {
2990 : : const struct dummy_mbuf *dm;
2991 : : uint64_t v;
2992 : :
2993 : : dm = arg;
2994 : 4 : v = test_ld_mbuf1(dm->mb);
2995 : 4 : return cmp_res(__func__, v, rc, arg, arg, 0);
2996 : : }
2997 : :
2998 : : /*
2999 : : * same as ld_mbuf1, but then truncate the mbuf by 1B,
3000 : : * so load of last 4B fail.
3001 : : */
3002 : : static void
3003 : 2 : test_ld_mbuf2_prepare(void *arg)
3004 : : {
3005 : : struct dummy_mbuf *dm;
3006 : :
3007 : 2 : test_ld_mbuf1_prepare(arg);
3008 : : dm = arg;
3009 : 2 : rte_pktmbuf_trim(dm->mb, 1);
3010 : 2 : }
3011 : :
3012 : : static int
3013 : 2 : test_ld_mbuf2_check(uint64_t rc, const void *arg)
3014 : : {
3015 : 2 : return cmp_res(__func__, 0, rc, arg, arg, 0);
3016 : : }
3017 : :
3018 : : /* same as test_ld_mbuf1, but now store intermediate results on the stack */
3019 : : static const struct ebpf_insn test_ld_mbuf3_prog[] = {
3020 : :
3021 : : /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
3022 : : {
3023 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
3024 : : .dst_reg = EBPF_REG_6,
3025 : : .src_reg = EBPF_REG_1,
3026 : : },
3027 : : /* load IPv4 version and IHL */
3028 : : {
3029 : : .code = (BPF_LD | BPF_ABS | BPF_B),
3030 : : .imm = offsetof(struct rte_ipv4_hdr, version_ihl),
3031 : : },
3032 : : /* check IP version */
3033 : : {
3034 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
3035 : : .dst_reg = EBPF_REG_2,
3036 : : .src_reg = EBPF_REG_0,
3037 : : },
3038 : : {
3039 : : .code = (BPF_ALU | BPF_AND | BPF_K),
3040 : : .dst_reg = EBPF_REG_2,
3041 : : .imm = 0xf0,
3042 : : },
3043 : : {
3044 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
3045 : : .dst_reg = EBPF_REG_2,
3046 : : .imm = IPVERSION << 4,
3047 : : .off = 2,
3048 : : },
3049 : : /* invalid IP version, return 0 */
3050 : : {
3051 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
3052 : : .dst_reg = EBPF_REG_0,
3053 : : .src_reg = EBPF_REG_0,
3054 : : },
3055 : : {
3056 : : .code = (BPF_JMP | EBPF_EXIT),
3057 : : },
3058 : : /* load 3-rd byte of IP data */
3059 : : {
3060 : : .code = (BPF_ALU | BPF_AND | BPF_K),
3061 : : .dst_reg = EBPF_REG_0,
3062 : : .imm = RTE_IPV4_HDR_IHL_MASK,
3063 : : },
3064 : : {
3065 : : .code = (BPF_ALU | BPF_LSH | BPF_K),
3066 : : .dst_reg = EBPF_REG_0,
3067 : : .imm = 2,
3068 : : },
3069 : : {
3070 : : .code = (BPF_LD | BPF_IND | BPF_B),
3071 : : .src_reg = EBPF_REG_0,
3072 : : .imm = 3,
3073 : : },
3074 : : {
3075 : : .code = (BPF_STX | BPF_MEM | BPF_B),
3076 : : .dst_reg = EBPF_REG_10,
3077 : : .src_reg = EBPF_REG_0,
3078 : : .off = (int16_t)(offsetof(struct dummy_offset, u8) -
3079 : : sizeof(struct dummy_offset)),
3080 : : },
3081 : : /* load IPv4 src addr */
3082 : : {
3083 : : .code = (BPF_LD | BPF_ABS | BPF_W),
3084 : : .imm = offsetof(struct rte_ipv4_hdr, src_addr),
3085 : : },
3086 : : {
3087 : : .code = (BPF_STX | BPF_MEM | BPF_W),
3088 : : .dst_reg = EBPF_REG_10,
3089 : : .src_reg = EBPF_REG_0,
3090 : : .off = (int16_t)(offsetof(struct dummy_offset, u32) -
3091 : : sizeof(struct dummy_offset)),
3092 : : },
3093 : : /* load IPv4 total length */
3094 : : {
3095 : : .code = (BPF_LD | BPF_ABS | BPF_H),
3096 : : .imm = offsetof(struct rte_ipv4_hdr, total_length),
3097 : : },
3098 : : {
3099 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
3100 : : .dst_reg = EBPF_REG_8,
3101 : : .src_reg = EBPF_REG_0,
3102 : : },
3103 : : /* load last 4 bytes of IP data */
3104 : : {
3105 : : .code = (BPF_LD | BPF_IND | BPF_W),
3106 : : .src_reg = EBPF_REG_8,
3107 : : .imm = -(int32_t)sizeof(uint32_t),
3108 : : },
3109 : : {
3110 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
3111 : : .dst_reg = EBPF_REG_10,
3112 : : .src_reg = EBPF_REG_0,
3113 : : .off = (int16_t)(offsetof(struct dummy_offset, u64) -
3114 : : sizeof(struct dummy_offset)),
3115 : : },
3116 : : /* load 2 bytes from the middle of IP data */
3117 : : {
3118 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
3119 : : .dst_reg = EBPF_REG_8,
3120 : : .imm = 1,
3121 : : },
3122 : : {
3123 : : .code = (BPF_LD | BPF_IND | BPF_H),
3124 : : .src_reg = EBPF_REG_8,
3125 : : },
3126 : : {
3127 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
3128 : : .dst_reg = EBPF_REG_1,
3129 : : .src_reg = EBPF_REG_10,
3130 : : .off = (int16_t)(offsetof(struct dummy_offset, u64) -
3131 : : sizeof(struct dummy_offset)),
3132 : : },
3133 : : {
3134 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
3135 : : .dst_reg = EBPF_REG_0,
3136 : : .src_reg = EBPF_REG_1,
3137 : : },
3138 : : {
3139 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
3140 : : .dst_reg = EBPF_REG_1,
3141 : : .src_reg = EBPF_REG_10,
3142 : : .off = (int16_t)(offsetof(struct dummy_offset, u32) -
3143 : : sizeof(struct dummy_offset)),
3144 : : },
3145 : : {
3146 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
3147 : : .dst_reg = EBPF_REG_0,
3148 : : .src_reg = EBPF_REG_1,
3149 : : },
3150 : : {
3151 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
3152 : : .dst_reg = EBPF_REG_1,
3153 : : .src_reg = EBPF_REG_10,
3154 : : .off = (int16_t)(offsetof(struct dummy_offset, u8) -
3155 : : sizeof(struct dummy_offset)),
3156 : : },
3157 : : {
3158 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
3159 : : .dst_reg = EBPF_REG_0,
3160 : : .src_reg = EBPF_REG_1,
3161 : : },
3162 : : {
3163 : : .code = (BPF_JMP | EBPF_EXIT),
3164 : : },
3165 : : };
3166 : :
3167 : : /* divide INT64_MIN by -1 */
3168 : : static const struct ebpf_insn test_int64min_udiv_uint64max_prog[] = {
3169 : : /* Load INT64_MIN into r0 */
3170 : : {
3171 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
3172 : : .dst_reg = EBPF_REG_0,
3173 : : .imm = (int32_t)INT64_MIN,
3174 : : },
3175 : : {
3176 : : .imm = (int32_t)(INT64_MIN >> 32),
3177 : : },
3178 : : /* Divide r0 by immediate -1 */
3179 : : {
3180 : : .code = (EBPF_ALU64 | BPF_DIV | BPF_K),
3181 : : .dst_reg = EBPF_REG_0,
3182 : : .imm = -1,
3183 : : },
3184 : : /* Exit for correctness otherwise */
3185 : : {
3186 : : .code = (BPF_JMP | EBPF_EXIT),
3187 : : },
3188 : : };
3189 : :
3190 : : static int
3191 : 2 : test_int64min_udiv_uint64max_check(uint64_t rc, const void *arg)
3192 : : {
3193 : : RTE_SET_USED(arg);
3194 : : /* 0x8000000000000000ull / 0xFFFFFFFFFFFFFFFFull == 0 */
3195 [ - + ]: 2 : TEST_ASSERT_EQUAL(rc, 0, "expected 0, found %#" PRIx64, rc);
3196 : : return TEST_SUCCESS;
3197 : : }
3198 : :
3199 : : /* modulo INT64_MIN by -1 */
3200 : : static const struct ebpf_insn test_int64min_umod_uint64max_prog[] = {
3201 : : /* Load INT64_MIN into r0 */
3202 : : {
3203 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
3204 : : .dst_reg = EBPF_REG_0,
3205 : : .imm = (int32_t)INT64_MIN,
3206 : : },
3207 : : {
3208 : : .imm = (int32_t)(INT64_MIN >> 32),
3209 : : },
3210 : : /* Modulo r0 by immediate -1 */
3211 : : {
3212 : : .code = (EBPF_ALU64 | BPF_MOD | BPF_K),
3213 : : .dst_reg = EBPF_REG_0,
3214 : : .imm = -1,
3215 : : },
3216 : : /* Exit for correctness otherwise */
3217 : : {
3218 : : .code = (BPF_JMP | EBPF_EXIT),
3219 : : },
3220 : : };
3221 : :
3222 : : static int
3223 : 2 : test_int64min_umod_uint64max_check(uint64_t rc, const void *arg)
3224 : : {
3225 : : RTE_SET_USED(arg);
3226 : : /* 0x8000000000000000ull % 0xFFFFFFFFFFFFFFFFull == 0x8000000000000000ull */
3227 [ - + ]: 2 : TEST_ASSERT_EQUAL(rc, (uint64_t)INT64_MIN, "expected INT64_MIN, found %#" PRIx64, rc);
3228 : : return TEST_SUCCESS;
3229 : : }
3230 : :
3231 : : /* all bpf test cases */
3232 : : static const struct bpf_test tests[] = {
3233 : : {
3234 : : .name = "test_store1",
3235 : : .arg_sz = sizeof(struct dummy_offset),
3236 : : .prm = {
3237 : : .ins = test_store1_prog,
3238 : : .nb_ins = RTE_DIM(test_store1_prog),
3239 : : .prog_arg = {
3240 : : .type = RTE_BPF_ARG_PTR,
3241 : : .size = sizeof(struct dummy_offset),
3242 : : },
3243 : : },
3244 : : .prepare = test_store1_prepare,
3245 : : .check_result = test_store1_check,
3246 : : },
3247 : : {
3248 : : .name = "test_store2",
3249 : : .arg_sz = sizeof(struct dummy_offset),
3250 : : .prm = {
3251 : : .ins = test_store2_prog,
3252 : : .nb_ins = RTE_DIM(test_store2_prog),
3253 : : .prog_arg = {
3254 : : .type = RTE_BPF_ARG_PTR,
3255 : : .size = sizeof(struct dummy_offset),
3256 : : },
3257 : : },
3258 : : .prepare = test_store1_prepare,
3259 : : .check_result = test_store1_check,
3260 : : },
3261 : : {
3262 : : .name = "test_load1",
3263 : : .arg_sz = sizeof(struct dummy_offset),
3264 : : .prm = {
3265 : : .ins = test_load1_prog,
3266 : : .nb_ins = RTE_DIM(test_load1_prog),
3267 : : .prog_arg = {
3268 : : .type = RTE_BPF_ARG_PTR,
3269 : : .size = sizeof(struct dummy_offset),
3270 : : },
3271 : : },
3272 : : .prepare = test_load1_prepare,
3273 : : .check_result = test_load1_check,
3274 : : },
3275 : : {
3276 : : .name = "test_ldimm1",
3277 : : .arg_sz = sizeof(struct dummy_offset),
3278 : : .prm = {
3279 : : .ins = test_ldimm1_prog,
3280 : : .nb_ins = RTE_DIM(test_ldimm1_prog),
3281 : : .prog_arg = {
3282 : : .type = RTE_BPF_ARG_PTR,
3283 : : .size = sizeof(struct dummy_offset),
3284 : : },
3285 : : },
3286 : : .prepare = test_store1_prepare,
3287 : : .check_result = test_ldimm1_check,
3288 : : },
3289 : : {
3290 : : .name = "test_mul1",
3291 : : .arg_sz = sizeof(struct dummy_vect8),
3292 : : .prm = {
3293 : : .ins = test_mul1_prog,
3294 : : .nb_ins = RTE_DIM(test_mul1_prog),
3295 : : .prog_arg = {
3296 : : .type = RTE_BPF_ARG_PTR,
3297 : : .size = sizeof(struct dummy_vect8),
3298 : : },
3299 : : },
3300 : : .prepare = test_mul1_prepare,
3301 : : .check_result = test_mul1_check,
3302 : : },
3303 : : {
3304 : : .name = "test_shift1",
3305 : : .arg_sz = sizeof(struct dummy_vect8),
3306 : : .prm = {
3307 : : .ins = test_shift1_prog,
3308 : : .nb_ins = RTE_DIM(test_shift1_prog),
3309 : : .prog_arg = {
3310 : : .type = RTE_BPF_ARG_PTR,
3311 : : .size = sizeof(struct dummy_vect8),
3312 : : },
3313 : : },
3314 : : .prepare = test_shift1_prepare,
3315 : : .check_result = test_shift1_check,
3316 : : },
3317 : : {
3318 : : .name = "test_jump1",
3319 : : .arg_sz = sizeof(struct dummy_vect8),
3320 : : .prm = {
3321 : : .ins = test_jump1_prog,
3322 : : .nb_ins = RTE_DIM(test_jump1_prog),
3323 : : .prog_arg = {
3324 : : .type = RTE_BPF_ARG_PTR,
3325 : : .size = sizeof(struct dummy_vect8),
3326 : : },
3327 : : },
3328 : : .prepare = test_jump1_prepare,
3329 : : .check_result = test_jump1_check,
3330 : : },
3331 : : {
3332 : : .name = "test_jump2",
3333 : : .arg_sz = sizeof(struct dummy_net),
3334 : : .prm = {
3335 : : .ins = test_jump2_prog,
3336 : : .nb_ins = RTE_DIM(test_jump2_prog),
3337 : : .prog_arg = {
3338 : : .type = RTE_BPF_ARG_PTR,
3339 : : .size = sizeof(struct dummy_net),
3340 : : },
3341 : : },
3342 : : .prepare = test_jump2_prepare,
3343 : : .check_result = test_jump2_check,
3344 : : },
3345 : : {
3346 : : .name = "test_alu1",
3347 : : .arg_sz = sizeof(struct dummy_vect8),
3348 : : .prm = {
3349 : : .ins = test_alu1_prog,
3350 : : .nb_ins = RTE_DIM(test_alu1_prog),
3351 : : .prog_arg = {
3352 : : .type = RTE_BPF_ARG_PTR,
3353 : : .size = sizeof(struct dummy_vect8),
3354 : : },
3355 : : },
3356 : : .prepare = test_jump1_prepare,
3357 : : .check_result = test_alu1_check,
3358 : : },
3359 : : {
3360 : : .name = "test_bele1",
3361 : : .arg_sz = sizeof(struct dummy_vect8),
3362 : : .prm = {
3363 : : .ins = test_bele1_prog,
3364 : : .nb_ins = RTE_DIM(test_bele1_prog),
3365 : : .prog_arg = {
3366 : : .type = RTE_BPF_ARG_PTR,
3367 : : .size = sizeof(struct dummy_vect8),
3368 : : },
3369 : : },
3370 : : .prepare = test_bele1_prepare,
3371 : : .check_result = test_bele1_check,
3372 : : },
3373 : : {
3374 : : .name = "test_xadd1",
3375 : : .arg_sz = sizeof(struct dummy_offset),
3376 : : .prm = {
3377 : : .ins = test_xadd1_prog,
3378 : : .nb_ins = RTE_DIM(test_xadd1_prog),
3379 : : .prog_arg = {
3380 : : .type = RTE_BPF_ARG_PTR,
3381 : : .size = sizeof(struct dummy_offset),
3382 : : },
3383 : : },
3384 : : .prepare = test_store1_prepare,
3385 : : .check_result = test_xadd1_check,
3386 : : },
3387 : : {
3388 : : .name = "test_div1",
3389 : : .arg_sz = sizeof(struct dummy_vect8),
3390 : : .prm = {
3391 : : .ins = test_div1_prog,
3392 : : .nb_ins = RTE_DIM(test_div1_prog),
3393 : : .prog_arg = {
3394 : : .type = RTE_BPF_ARG_PTR,
3395 : : .size = sizeof(struct dummy_vect8),
3396 : : },
3397 : : },
3398 : : .prepare = test_mul1_prepare,
3399 : : .check_result = test_div1_check,
3400 : : },
3401 : : {
3402 : : .name = "test_call1",
3403 : : .arg_sz = sizeof(struct dummy_offset),
3404 : : .prm = {
3405 : : .ins = test_call1_prog,
3406 : : .nb_ins = RTE_DIM(test_call1_prog),
3407 : : .prog_arg = {
3408 : : .type = RTE_BPF_ARG_PTR,
3409 : : .size = sizeof(struct dummy_offset),
3410 : : },
3411 : : .xsym = test_call1_xsym,
3412 : : .nb_xsym = RTE_DIM(test_call1_xsym),
3413 : : },
3414 : : .prepare = test_load1_prepare,
3415 : : .check_result = test_call1_check,
3416 : : /* for now don't support function calls on 32 bit platform */
3417 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3418 : : },
3419 : : {
3420 : : .name = "test_call2",
3421 : : .arg_sz = sizeof(struct dummy_offset),
3422 : : .prm = {
3423 : : .ins = test_call2_prog,
3424 : : .nb_ins = RTE_DIM(test_call2_prog),
3425 : : .prog_arg = {
3426 : : .type = RTE_BPF_ARG_PTR,
3427 : : .size = sizeof(struct dummy_offset),
3428 : : },
3429 : : .xsym = test_call2_xsym,
3430 : : .nb_xsym = RTE_DIM(test_call2_xsym),
3431 : : },
3432 : : .prepare = test_store1_prepare,
3433 : : .check_result = test_call2_check,
3434 : : /* for now don't support function calls on 32 bit platform */
3435 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3436 : : },
3437 : : {
3438 : : .name = "test_call3",
3439 : : .arg_sz = sizeof(struct dummy_vect8),
3440 : : .prm = {
3441 : : .ins = test_call3_prog,
3442 : : .nb_ins = RTE_DIM(test_call3_prog),
3443 : : .prog_arg = {
3444 : : .type = RTE_BPF_ARG_PTR,
3445 : : .size = sizeof(struct dummy_vect8),
3446 : : },
3447 : : .xsym = test_call3_xsym,
3448 : : .nb_xsym = RTE_DIM(test_call3_xsym),
3449 : : },
3450 : : .prepare = test_call3_prepare,
3451 : : .check_result = test_call3_check,
3452 : : /* for now don't support function calls on 32 bit platform */
3453 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3454 : : },
3455 : : {
3456 : : .name = "test_call4",
3457 : : .arg_sz = sizeof(struct dummy_offset),
3458 : : .prm = {
3459 : : .ins = test_call4_prog,
3460 : : .nb_ins = RTE_DIM(test_call4_prog),
3461 : : .prog_arg = {
3462 : : .type = RTE_BPF_ARG_PTR,
3463 : : .size = 2 * sizeof(struct dummy_offset),
3464 : : },
3465 : : .xsym = test_call4_xsym,
3466 : : .nb_xsym = RTE_DIM(test_call4_xsym),
3467 : : },
3468 : : .prepare = test_store1_prepare,
3469 : : .check_result = test_call4_check,
3470 : : /* for now don't support function calls on 32 bit platform */
3471 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3472 : : },
3473 : : {
3474 : : .name = "test_call5",
3475 : : .arg_sz = sizeof(struct dummy_offset),
3476 : : .prm = {
3477 : : .ins = test_call5_prog,
3478 : : .nb_ins = RTE_DIM(test_call5_prog),
3479 : : .prog_arg = {
3480 : : .type = RTE_BPF_ARG_PTR,
3481 : : .size = sizeof(struct dummy_offset),
3482 : : },
3483 : : .xsym = test_call5_xsym,
3484 : : .nb_xsym = RTE_DIM(test_call5_xsym),
3485 : : },
3486 : : .prepare = test_store1_prepare,
3487 : : .check_result = test_call5_check,
3488 : : /* for now don't support function calls on 32 bit platform */
3489 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3490 : : },
3491 : : {
3492 : : .name = "test_ld_mbuf1",
3493 : : .arg_sz = sizeof(struct dummy_mbuf),
3494 : : .prm = {
3495 : : .ins = test_ld_mbuf1_prog,
3496 : : .nb_ins = RTE_DIM(test_ld_mbuf1_prog),
3497 : : .prog_arg = {
3498 : : .type = RTE_BPF_ARG_PTR_MBUF,
3499 : : .buf_size = sizeof(struct dummy_mbuf),
3500 : : },
3501 : : },
3502 : : .prepare = test_ld_mbuf1_prepare,
3503 : : .check_result = test_ld_mbuf1_check,
3504 : : /* mbuf as input argument is not supported on 32 bit platform */
3505 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3506 : : },
3507 : : {
3508 : : .name = "test_ld_mbuf2",
3509 : : .arg_sz = sizeof(struct dummy_mbuf),
3510 : : .prm = {
3511 : : .ins = test_ld_mbuf1_prog,
3512 : : .nb_ins = RTE_DIM(test_ld_mbuf1_prog),
3513 : : .prog_arg = {
3514 : : .type = RTE_BPF_ARG_PTR_MBUF,
3515 : : .buf_size = sizeof(struct dummy_mbuf),
3516 : : },
3517 : : },
3518 : : .prepare = test_ld_mbuf2_prepare,
3519 : : .check_result = test_ld_mbuf2_check,
3520 : : /* mbuf as input argument is not supported on 32 bit platform */
3521 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3522 : : },
3523 : : {
3524 : : .name = "test_ld_mbuf3",
3525 : : .arg_sz = sizeof(struct dummy_mbuf),
3526 : : .prm = {
3527 : : .ins = test_ld_mbuf3_prog,
3528 : : .nb_ins = RTE_DIM(test_ld_mbuf3_prog),
3529 : : .prog_arg = {
3530 : : .type = RTE_BPF_ARG_PTR_MBUF,
3531 : : .buf_size = sizeof(struct dummy_mbuf),
3532 : : },
3533 : : },
3534 : : .prepare = test_ld_mbuf1_prepare,
3535 : : .check_result = test_ld_mbuf1_check,
3536 : : /* mbuf as input argument is not supported on 32 bit platform */
3537 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3538 : : },
3539 : : {
3540 : : .name = "test_int64min_udiv_uint64max",
3541 : : .arg_sz = sizeof(struct dummy_vect8),
3542 : : .prm = {
3543 : : .ins = test_int64min_udiv_uint64max_prog,
3544 : : .nb_ins = RTE_DIM(test_int64min_udiv_uint64max_prog),
3545 : : .prog_arg = {
3546 : : .type = RTE_BPF_ARG_PTR,
3547 : : .size = sizeof(struct dummy_vect8),
3548 : : },
3549 : : },
3550 : : .prepare = dummy_prepare,
3551 : : .check_result = test_int64min_udiv_uint64max_check,
3552 : : },
3553 : : {
3554 : : .name = "test_int64min_umod_uint64max",
3555 : : .arg_sz = 1,
3556 : : .prm = {
3557 : : .ins = test_int64min_umod_uint64max_prog,
3558 : : .nb_ins = RTE_DIM(test_int64min_umod_uint64max_prog),
3559 : : .prog_arg = {
3560 : : .type = RTE_BPF_ARG_PTR,
3561 : : .size = 1,
3562 : : },
3563 : : },
3564 : : .prepare = dummy_prepare,
3565 : : .check_result = test_int64min_umod_uint64max_check,
3566 : : },
3567 : : };
3568 : :
3569 : : static int
3570 : 22 : run_test(const struct bpf_test *tst)
3571 : 22 : {
3572 : : int32_t ret, rv;
3573 : : int64_t rc;
3574 : : struct rte_bpf *bpf;
3575 : : struct rte_bpf_jit jit;
3576 : 22 : uint8_t tbuf[tst->arg_sz];
3577 : :
3578 : 22 : printf("%s(%s) start\n", __func__, tst->name);
3579 : :
3580 : 22 : bpf = rte_bpf_load(&tst->prm);
3581 [ - + ]: 22 : if (bpf == NULL) {
3582 : 0 : printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
3583 : : __func__, __LINE__, rte_errno, strerror(rte_errno));
3584 : 0 : return -1;
3585 : : }
3586 : :
3587 : 22 : tst->prepare(tbuf);
3588 : 22 : rc = rte_bpf_exec(bpf, tbuf);
3589 : 22 : ret = tst->check_result(rc, tbuf);
3590 [ - + ]: 22 : if (ret != 0) {
3591 : 0 : printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
3592 : 0 : __func__, __LINE__, tst->name, ret, strerror(ret));
3593 : : }
3594 : :
3595 : : /* repeat the same test with jit, when possible */
3596 : 22 : rte_bpf_get_jit(bpf, &jit);
3597 [ + - ]: 22 : if (jit.func != NULL) {
3598 : :
3599 : 22 : tst->prepare(tbuf);
3600 : 22 : rc = jit.func(tbuf);
3601 : 22 : rv = tst->check_result(rc, tbuf);
3602 : 22 : ret |= rv;
3603 [ - + ]: 22 : if (rv != 0) {
3604 : 0 : printf("%s@%d: check_result(%s) failed, "
3605 : : "error: %d(%s);\n",
3606 : 0 : __func__, __LINE__, tst->name,
3607 : : rv, strerror(rv));
3608 : : }
3609 : : }
3610 : :
3611 : 22 : rte_bpf_destroy(bpf);
3612 : 22 : return ret;
3613 : :
3614 : : }
3615 : :
3616 : : /* Test all eBPF load APIs with prm set to NULL. */
3617 : : static int
3618 : 1 : test_bpf_load_null(void)
3619 : : {
3620 : : struct rte_bpf *bpf;
3621 : : int saved_errno;
3622 : :
3623 : 1 : rte_errno = 0;
3624 : 1 : bpf = rte_bpf_load(NULL);
3625 : 1 : saved_errno = rte_errno;
3626 : 1 : rte_bpf_destroy(bpf);
3627 [ - + ]: 1 : RTE_TEST_ASSERT_NULL(bpf, "rte_bpf_load(NULL) did not return NULL\n");
3628 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(saved_errno, EINVAL,
3629 : : "rte_bpf_load(NULL) did not set rte_errno to EINVAL\n");
3630 : :
3631 : 1 : rte_errno = 0;
3632 : 1 : bpf = rte_bpf_elf_load(NULL, "a", "b");
3633 : 1 : saved_errno = rte_errno;
3634 : 1 : rte_bpf_destroy(bpf);
3635 [ - + ]: 1 : RTE_TEST_ASSERT_NULL(bpf, "rte_bpf_elf_load(NULL, \"a\", \"b\") did not return NULL\n");
3636 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(saved_errno, EINVAL,
3637 : : "rte_bpf_elf_load(NULL, \"a\", \"b\") did not set rte_errno to EINVAL\n");
3638 : :
3639 : 1 : rte_errno = 0;
3640 : 1 : bpf = rte_bpf_load_ex(NULL);
3641 : 1 : saved_errno = rte_errno;
3642 : 1 : rte_bpf_destroy(bpf);
3643 [ - + ]: 1 : RTE_TEST_ASSERT_NULL(bpf, "rte_bpf_load_ex(NULL) did not return NULL\n");
3644 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(saved_errno, EINVAL,
3645 : : "rte_bpf_load_ex(NULL) did not set rte_errno to EINVAL\n");
3646 : :
3647 : : return 0;
3648 : : }
3649 : 303 : REGISTER_FAST_TEST(bpf_load_null_autotest, NOHUGE_OK, ASAN_OK, test_bpf_load_null);
3650 : :
3651 : : /* Test calling wrong API for execution of a multi-argument eBPF program. */
3652 : : static int
3653 : 1 : test_bpf_exec_wrong_nb_prog_arg(void)
3654 : : {
3655 : : static const struct ebpf_insn ins[] = {
3656 : : { .code = (EBPF_ALU64 | EBPF_MOV | BPF_K), .dst_reg = EBPF_REG_0, .imm = 0 },
3657 : : { .code = (BPF_JMP | EBPF_EXIT), }
3658 : : };
3659 : : static const struct rte_bpf_prm_ex prm = {
3660 : : .sz = sizeof(struct rte_bpf_prm_ex),
3661 : : .origin = RTE_BPF_ORIGIN_RAW,
3662 : : .raw.ins = ins,
3663 : : .raw.nb_ins = RTE_DIM(ins),
3664 : : .prog_arg = {
3665 : : { .type = RTE_BPF_ARG_RAW, .size = sizeof(uint64_t) },
3666 : : { .type = RTE_BPF_ARG_RAW, .size = sizeof(uint64_t) },
3667 : : },
3668 : : .nb_prog_arg = 2, /* Intentionally mismatched: expects 2, burst gives 1 */
3669 : : };
3670 : :
3671 : : struct rte_bpf *bpf;
3672 : : uint64_t rc[1];
3673 : 1 : void *ctx[1] = {NULL};
3674 : : uint32_t result;
3675 : : int saved_errno;
3676 : :
3677 : 1 : bpf = rte_bpf_load_ex(&prm);
3678 [ - + ]: 1 : RTE_TEST_ASSERT_NOT_NULL(bpf, "rte_bpf_load_ex failed\n");
3679 : :
3680 : 1 : rte_errno = 0;
3681 : 1 : result = rte_bpf_exec_burst(bpf, ctx, rc, 1);
3682 : 1 : saved_errno = rte_errno;
3683 : 1 : rte_bpf_destroy(bpf);
3684 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(result, 0, "rte_bpf_exec_burst did not return 0\n");
3685 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(saved_errno, EINVAL,
3686 : : "rte_bpf_exec_burst did not set rte_errno to EINVAL\n");
3687 : :
3688 : : return 0;
3689 : : }
3690 : 303 : REGISTER_FAST_TEST(bpf_exec_wrong_nb_prog_arg_autotest, NOHUGE_OK, ASAN_OK,
3691 : : test_bpf_exec_wrong_nb_prog_arg);
3692 : :
3693 : : /* Test passing unsupported flags when executing an eBPF program. */
3694 : : static int
3695 : 1 : test_bpf_exec_wrong_flags(void)
3696 : : {
3697 : : static const struct ebpf_insn ins[] = {
3698 : : { .code = (EBPF_ALU64 | EBPF_MOV | BPF_K), .dst_reg = EBPF_REG_0, .imm = 0 },
3699 : : { .code = (BPF_JMP | EBPF_EXIT), }
3700 : : };
3701 : : static const struct rte_bpf_prm_ex prm = {
3702 : : .sz = sizeof(struct rte_bpf_prm_ex),
3703 : : .origin = RTE_BPF_ORIGIN_RAW,
3704 : : .raw.ins = ins,
3705 : : .raw.nb_ins = RTE_DIM(ins),
3706 : : .prog_arg = { { .type = RTE_BPF_ARG_RAW, .size = sizeof(uint64_t) } },
3707 : : .nb_prog_arg = 1,
3708 : : };
3709 : :
3710 : : struct rte_bpf *bpf;
3711 : : uint64_t rc[1];
3712 : 1 : struct rte_bpf_prog_ctx ctx_ex[1] = {};
3713 : : uint32_t result;
3714 : : int saved_errno;
3715 : :
3716 : 1 : bpf = rte_bpf_load_ex(&prm);
3717 [ - + ]: 1 : RTE_TEST_ASSERT_NOT_NULL(bpf, "rte_bpf_load_ex failed\n");
3718 : :
3719 : 1 : rte_errno = 0;
3720 : 1 : result = rte_bpf_exec_burst_ex(bpf, ctx_ex, rc, 1, UINT64_MAX);
3721 : 1 : saved_errno = rte_errno;
3722 : 1 : rte_bpf_destroy(bpf);
3723 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(result, 0, "rte_bpf_exec_burst_ex did not return 0\n");
3724 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(saved_errno, EINVAL,
3725 : : "rte_bpf_exec_burst_ex did not set rte_errno to EINVAL\n");
3726 : :
3727 : : return 0;
3728 : : }
3729 : 303 : REGISTER_FAST_TEST(bpf_exec_wrong_flags_autotest, NOHUGE_OK, ASAN_OK, test_bpf_exec_wrong_flags);
3730 : :
3731 : : static int
3732 : 1 : test_bpf(void)
3733 : : {
3734 : : int32_t rc, rv;
3735 : : uint32_t i;
3736 : :
3737 : : rc = 0;
3738 [ + + ]: 23 : for (i = 0; i != RTE_DIM(tests); i++) {
3739 : 22 : rv = run_test(tests + i);
3740 [ + - ]: 22 : if (tests[i].allow_fail == 0)
3741 : 22 : rc |= rv;
3742 : : }
3743 : :
3744 : 1 : return rc;
3745 : : }
3746 : :
3747 : : #endif /* !RTE_LIB_BPF */
3748 : :
3749 : 303 : REGISTER_FAST_TEST(bpf_autotest, NOHUGE_OK, ASAN_OK, test_bpf);
3750 : :
3751 : : /* Tests of BPF JIT stack alignment when calling external functions (xfuncs). */
3752 : :
3753 : : /* Function called from the BPF program in a test. */
3754 : : typedef uint64_t (*text_xfunc_t)(uint64_t argument);
3755 : :
3756 : : /* Call function from BPF program, verify that it incremented its argument. */
3757 : : static int
3758 : 100 : call_from_bpf_test(text_xfunc_t xfunc)
3759 : : {
3760 : : static const struct ebpf_insn ins[] = {
3761 : : {
3762 : : .code = (BPF_JMP | EBPF_CALL),
3763 : : .imm = 0, /* xsym #0 */
3764 : : },
3765 : : {
3766 : : .code = (BPF_JMP | EBPF_EXIT),
3767 : : },
3768 : : };
3769 : 100 : const struct rte_bpf_xsym xsym[] = {
3770 : : {
3771 : : .name = "xfunc",
3772 : : .type = RTE_BPF_XTYPE_FUNC,
3773 : : .func = {
3774 : : .val = (void *)xfunc,
3775 : : .nb_args = 1,
3776 : : .args = {
3777 : : {
3778 : : .type = RTE_BPF_ARG_RAW,
3779 : : .size = sizeof(uint64_t),
3780 : : },
3781 : : },
3782 : : .ret = {
3783 : : .type = RTE_BPF_ARG_RAW,
3784 : : .size = sizeof(uint64_t),
3785 : : },
3786 : : },
3787 : : },
3788 : : };
3789 : 100 : const struct rte_bpf_prm prm = {
3790 : : .ins = ins,
3791 : : .nb_ins = RTE_DIM(ins),
3792 : : .xsym = xsym,
3793 : : .nb_xsym = RTE_DIM(xsym),
3794 : : .prog_arg = {
3795 : : .type = RTE_BPF_ARG_RAW,
3796 : : .size = sizeof(uint64_t),
3797 : : },
3798 : : };
3799 : :
3800 : : struct rte_bpf_jit jit;
3801 : :
3802 : 100 : struct rte_bpf *const bpf = rte_bpf_load(&prm);
3803 [ - + ]: 100 : RTE_TEST_ASSERT_NOT_EQUAL(bpf, NULL,
3804 : : "expect rte_bpf_load() != NULL");
3805 : :
3806 [ - + ]: 100 : RTE_TEST_ASSERT_SUCCESS(rte_bpf_get_jit(bpf, &jit),
3807 : : "expect rte_bpf_get_jit() to succeed");
3808 : :
3809 : 100 : const text_xfunc_t jit_function = (void *)jit.func;
3810 [ - + ]: 100 : if (jit_function == NULL) {
3811 : 0 : rte_bpf_destroy(bpf);
3812 : 0 : return TEST_SKIPPED;
3813 : : }
3814 : :
3815 : : const uint64_t argument = 42;
3816 : 100 : const uint64_t result = jit_function(argument);
3817 : 100 : rte_bpf_destroy(bpf);
3818 : :
3819 [ - + ]: 100 : RTE_TEST_ASSERT_EQUAL(result, argument + 1,
3820 : : "expect result == %ju, found %ju",
3821 : : (uintmax_t)(argument + 1), (uintmax_t)result);
3822 : :
3823 : : return TEST_SUCCESS;
3824 : : }
3825 : :
3826 : : /*
3827 : : * Test alignment of a local variable.
3828 : : *
3829 : : * NOTE: May produce false negatives with sanitizers if they replace the stack.
3830 : : */
3831 : :
3832 : : /* Copy of the pointer to max_align stack variable, volatile to thwart optimization. */
3833 : : static volatile uintptr_t stack_alignment_test_pointer;
3834 : :
3835 : : static uint64_t
3836 : 1 : stack_alignment_xfunc(uint64_t argument)
3837 : : {
3838 : : max_align_t max_align;
3839 : 1 : stack_alignment_test_pointer = (uintptr_t)&max_align;
3840 : 1 : return argument + 1;
3841 : : }
3842 : :
3843 : : static int
3844 : 1 : test_stack_alignment(void)
3845 : : {
3846 : 1 : const int test_rc = call_from_bpf_test(stack_alignment_xfunc);
3847 [ + - ]: 1 : if (test_rc == TEST_SKIPPED)
3848 : : return TEST_SKIPPED;
3849 : :
3850 [ - + ]: 1 : RTE_TEST_ASSERT_SUCCESS(test_rc,
3851 : : "expect call_from_bpf_test(stack_alignment_xfunc) to succeed");
3852 : :
3853 : 1 : const uintptr_t test_offset = stack_alignment_test_pointer;
3854 [ - + ]: 1 : RTE_TEST_ASSERT_NOT_EQUAL(test_offset, 0, "expect test_pointer != 0");
3855 : :
3856 : 1 : const size_t test_alignment = test_offset % alignof(max_align_t);
3857 [ - + ]: 1 : RTE_TEST_ASSERT_EQUAL(test_alignment, 0,
3858 : : "expect test_alignment == 0, found %zu", test_alignment);
3859 : :
3860 : : return TEST_SUCCESS;
3861 : : }
3862 : :
3863 : 303 : REGISTER_FAST_TEST(bpf_stack_alignment_autotest, NOHUGE_OK, ASAN_OK, test_stack_alignment);
3864 : :
3865 : : /*
3866 : : * Test copying `__uint128_t`.
3867 : : *
3868 : : * This operation is used by some variations of `rte_memcpy`;
3869 : : * it can also be produced by vectorizer in the compiler.
3870 : : */
3871 : :
3872 : : #if defined(__SIZEOF_INT128__)
3873 : :
3874 : : static uint64_t
3875 : 1 : stack_copy_uint128_xfunc(uint64_t argument)
3876 : : {
3877 : : /* Pass addresses through volatiles to prevent compiler from optimizing it all out. */
3878 : : char alignas(16) src_buffer[16];
3879 : : char alignas(16) dst_buffer[16];
3880 : : void *const src = (char *volatile)src_buffer;
3881 : : void *const dst = (char *volatile)dst_buffer;
3882 : : const size_t size = 16;
3883 : :
3884 : : memset(src, 0x2a, size);
3885 : : memset(dst, 0x55, size);
3886 : 1 : const int initial_memcmp_rc = memcmp(dst, src, size);
3887 : :
3888 : : const __uint128_t *const src128 = (const __uint128_t *)src;
3889 : : __uint128_t *const dst128 = (__uint128_t *)dst;
3890 : 1 : *dst128 = *src128;
3891 : 1 : const int memcmp_rc = memcmp(dst, src, size);
3892 : :
3893 : 1 : return argument + 1 + !initial_memcmp_rc + memcmp_rc;
3894 : : }
3895 : :
3896 : : static int
3897 : 1 : test_stack_copy_uint128(void)
3898 : : {
3899 : 1 : const int test_rc = call_from_bpf_test(stack_copy_uint128_xfunc);
3900 [ + - ]: 1 : if (test_rc == TEST_SKIPPED)
3901 : : return TEST_SKIPPED;
3902 : :
3903 [ - + ]: 1 : RTE_TEST_ASSERT_SUCCESS(test_rc,
3904 : : "expect call_from_bpf_test(stack_copy_uint128_xfunc) to succeed");
3905 : :
3906 : : return TEST_SUCCESS;
3907 : : }
3908 : :
3909 : : #else
3910 : :
3911 : : static int
3912 : : test_stack_copy_uint128(void)
3913 : : {
3914 : : return TEST_SKIPPED;
3915 : : }
3916 : :
3917 : : #endif
3918 : :
3919 : 303 : REGISTER_FAST_TEST(bpf_stack_copy_uint128_autotest, NOHUGE_OK, ASAN_OK, test_stack_copy_uint128);
3920 : :
3921 : : /*
3922 : : * Test SSE2 load and store intrinsics.
3923 : : *
3924 : : * These intrinsics are used by e.g. lib/hash.
3925 : : *
3926 : : * Test both aligned and unaligned versions. Unaligned intrinsics may still fail
3927 : : * when the stack is misaligned, since they only treat memory address as
3928 : : * unaligned, not stack.
3929 : : */
3930 : :
3931 : : #if defined(__SSE2__)
3932 : :
3933 : : static uint64_t
3934 : 1 : stack_sse2_aligned_xfunc(uint64_t argument)
3935 : : {
3936 : : /* Pass addresses through volatiles to prevent compiler from optimizing it all out. */
3937 : : char alignas(16) src_buffer[16];
3938 : : char alignas(16) dst_buffer[16];
3939 : : void *const src = (char *volatile)src_buffer;
3940 : : void *const dst = (char *volatile)dst_buffer;
3941 : : const size_t size = 16;
3942 : :
3943 : : memset(src, 0x2a, size);
3944 : : memset(dst, 0x55, size);
3945 : 1 : const int initial_memcmp_rc = memcmp(dst, src, size);
3946 : :
3947 : : const __m128i tmp = _mm_load_si128((const __m128i *)src);
3948 : : _mm_store_si128((__m128i *)dst, tmp);
3949 : 1 : const int memcmp_rc = memcmp(dst, src, size);
3950 : :
3951 : 1 : return argument + 1 + !initial_memcmp_rc + memcmp_rc;
3952 : : }
3953 : :
3954 : : static uint64_t
3955 : 1 : stack_sse2_unaligned_xfunc(uint64_t argument)
3956 : : {
3957 : : /* Pass addresses through volatiles to prevent compiler from optimizing it all out. */
3958 : : char alignas(16) src_buffer[17];
3959 : : char alignas(16) dst_buffer[17];
3960 : : void *const src = (char *volatile)src_buffer + 1;
3961 : : void *const dst = (char *volatile)dst_buffer + 1;
3962 : : const size_t size = 16;
3963 : :
3964 : : memset(src, 0x2a, size);
3965 : : memset(dst, 0x55, size);
3966 : 1 : const int initial_memcmp_rc = memcmp(dst, src, size);
3967 : :
3968 : : const __m128i tmp = _mm_loadu_si128((const __m128i *)src);
3969 : : _mm_storeu_si128((__m128i *)dst, tmp);
3970 : 1 : const int memcmp_rc = memcmp(dst, src, size);
3971 : :
3972 : 1 : return argument + 1 + !initial_memcmp_rc + memcmp_rc;
3973 : : }
3974 : :
3975 : : static int
3976 : 1 : test_stack_sse2(void)
3977 : : {
3978 : : int test_rc;
3979 : :
3980 : 1 : test_rc = call_from_bpf_test(stack_sse2_aligned_xfunc);
3981 [ + - ]: 1 : if (test_rc == TEST_SKIPPED)
3982 : : return test_rc;
3983 [ - + ]: 1 : RTE_TEST_ASSERT_SUCCESS(test_rc,
3984 : : "expect call_from_bpf_test(stack_sse2_aligned_xfunc) to succeed");
3985 : :
3986 : 1 : test_rc = call_from_bpf_test(stack_sse2_unaligned_xfunc);
3987 [ + - ]: 1 : if (test_rc == TEST_SKIPPED)
3988 : : return test_rc;
3989 [ - + ]: 1 : RTE_TEST_ASSERT_SUCCESS(test_rc,
3990 : : "expect call_from_bpf_test(stack_sse2_unaligned_xfunc) to succeed");
3991 : :
3992 : : return TEST_SUCCESS;
3993 : : }
3994 : :
3995 : : #else
3996 : :
3997 : : static int
3998 : : test_stack_sse2(void)
3999 : : {
4000 : : return TEST_SKIPPED;
4001 : : }
4002 : :
4003 : : #endif
4004 : :
4005 : 303 : REGISTER_FAST_TEST(bpf_stack_sse2_autotest, NOHUGE_OK, ASAN_OK, test_stack_sse2);
4006 : :
4007 : : /*
4008 : : * Run memcpy and rte_memcpy with various data sizes and offsets (unaligned and aligned).
4009 : : *
4010 : : * May produce false negatives even if BPF breaks stack alignment since
4011 : : * compilers may realign the stack in the beginning of the function to use
4012 : : * vector instructions with width larger than the default stack alignment.
4013 : : * However, represents very important use case that was broken in practice.
4014 : : *
4015 : : * For the reason specified above test 16-byte fixed-width memcpy explicitly.
4016 : : */
4017 : :
4018 : : static void *volatile stack_memcpy_dst;
4019 : : static const void *volatile stack_memcpy_src;
4020 : : static size_t volatile stack_memcpy_size;
4021 : :
4022 : : static uint64_t
4023 : 4 : stack_memcpy16_xfunc(uint64_t argument)
4024 : : {
4025 : : RTE_ASSERT(stack_memcpy_size == 16);
4026 : 4 : memcpy(stack_memcpy_dst, stack_memcpy_src, 16);
4027 : 4 : return argument + 1;
4028 : : }
4029 : :
4030 : : static uint64_t
4031 : 4 : stack_rte_memcpy16_xfunc(uint64_t argument)
4032 : : {
4033 : : RTE_ASSERT(stack_memcpy_size == 16);
4034 : 4 : rte_memcpy(stack_memcpy_dst, stack_memcpy_src, 16);
4035 : 4 : return argument + 1;
4036 : : }
4037 : :
4038 : : static uint64_t
4039 : 44 : stack_memcpy_xfunc(uint64_t argument)
4040 : : {
4041 : 44 : memcpy(stack_memcpy_dst, stack_memcpy_src, stack_memcpy_size);
4042 : 44 : return argument + 1;
4043 : : }
4044 : :
4045 : : static uint64_t
4046 : 44 : stack_rte_memcpy_xfunc(uint64_t argument)
4047 : : {
4048 [ + + ]: 44 : rte_memcpy(stack_memcpy_dst, stack_memcpy_src, stack_memcpy_size);
4049 : 44 : return argument + 1;
4050 : : }
4051 : :
4052 : : static int
4053 : 96 : stack_memcpy_subtest(text_xfunc_t xfunc, size_t size, size_t src_offset, size_t dst_offset)
4054 : : {
4055 : 96 : stack_memcpy_size = size;
4056 : :
4057 : 96 : char *const src_buffer = malloc(size + src_offset);
4058 : 96 : char *const dst_buffer = malloc(size + dst_offset);
4059 : :
4060 [ - + ]: 96 : if (src_buffer == NULL || dst_buffer == NULL) {
4061 : 0 : free(dst_buffer);
4062 : 0 : free(src_buffer);
4063 : 0 : return TEST_FAILED;
4064 : : }
4065 : :
4066 : 96 : memset(src_buffer + src_offset, 0x2a, size);
4067 : 96 : stack_memcpy_src = src_buffer + src_offset;
4068 : :
4069 : 96 : memset(dst_buffer + dst_offset, 0x55, size);
4070 : 96 : stack_memcpy_dst = dst_buffer + dst_offset;
4071 : :
4072 : 96 : const int initial_memcmp_rc = memcmp(stack_memcpy_dst, stack_memcpy_src, size);
4073 : 96 : const int test_rc = call_from_bpf_test(xfunc);
4074 : 96 : const int memcmp_rc = memcmp(stack_memcpy_dst, stack_memcpy_src, size);
4075 : :
4076 : 96 : free(dst_buffer);
4077 : 96 : free(src_buffer);
4078 : :
4079 [ + - ]: 96 : if (test_rc == TEST_SKIPPED)
4080 : : return TEST_SKIPPED;
4081 : :
4082 [ - + ]: 96 : RTE_TEST_ASSERT_FAIL(initial_memcmp_rc, "expect memcmp() to fail initially");
4083 [ - + ]: 96 : RTE_TEST_ASSERT_SUCCESS(test_rc, "expect call_from_bpf_test(xfunc) to succeed");
4084 [ - + ]: 96 : RTE_TEST_ASSERT_SUCCESS(memcmp_rc, "expect memcmp() to succeed");
4085 : :
4086 : : return TEST_SUCCESS;
4087 : : }
4088 : :
4089 : : static int
4090 : 1 : test_stack_memcpy(void)
4091 : : {
4092 [ + + ]: 5 : for (int offsets = 0; offsets < 4; ++offsets) {
4093 : 4 : const bool src_offset = offsets & 1;
4094 : 4 : const bool dst_offset = offsets & 2;
4095 : : int test_rc;
4096 : :
4097 : 4 : test_rc = stack_memcpy_subtest(stack_memcpy16_xfunc,
4098 : : 16, src_offset, dst_offset);
4099 [ + - ]: 4 : if (test_rc == TEST_SKIPPED)
4100 : : return test_rc;
4101 [ - + ]: 4 : RTE_TEST_ASSERT_SUCCESS(test_rc,
4102 : : "expect stack_memcpy_subtest(stack_memcpy16_xfunc, "
4103 : : "16, %i, %i) to succeed",
4104 : : src_offset, dst_offset);
4105 : :
4106 : 4 : test_rc = stack_memcpy_subtest(stack_rte_memcpy16_xfunc,
4107 : : 16, src_offset, dst_offset);
4108 [ + - ]: 4 : if (test_rc == TEST_SKIPPED)
4109 : : return test_rc;
4110 [ - + ]: 4 : RTE_TEST_ASSERT_SUCCESS(test_rc,
4111 : : "expect stack_memcpy_subtest(stack_rte_memcpy16_xfunc, "
4112 : : "16, %i, %i) to succeed",
4113 : : src_offset, dst_offset);
4114 : :
4115 [ + + ]: 48 : for (size_t size = 1; size <= 1024; size <<= 1) {
4116 : 44 : test_rc = stack_memcpy_subtest(stack_memcpy_xfunc,
4117 : : size, src_offset, dst_offset);
4118 [ + - ]: 44 : if (test_rc == TEST_SKIPPED)
4119 : : return test_rc;
4120 [ - + ]: 44 : RTE_TEST_ASSERT_SUCCESS(test_rc,
4121 : : "expect stack_memcpy_subtest(stack_memcpy_xfunc, "
4122 : : "%zu, %i, %i) to succeed",
4123 : : size, src_offset, dst_offset);
4124 : :
4125 : 44 : test_rc = stack_memcpy_subtest(stack_rte_memcpy_xfunc,
4126 : : size, src_offset, dst_offset);
4127 [ + - ]: 44 : if (test_rc == TEST_SKIPPED)
4128 : : return test_rc;
4129 [ - + ]: 44 : RTE_TEST_ASSERT_SUCCESS(test_rc,
4130 : : "expect stack_memcpy_subtest(stack_rte_memcpy_xfunc, "
4131 : : "%zu, %i, %i) to succeed",
4132 : : size, src_offset, dst_offset);
4133 : : }
4134 : : }
4135 : : return TEST_SUCCESS;
4136 : : }
4137 : :
4138 : 303 : REGISTER_FAST_TEST(bpf_stack_memcpy_autotest, NOHUGE_OK, ASAN_OK, test_stack_memcpy);
4139 : :
4140 : : /*
4141 : : * The BPF elf load test needs the BPF programs to be successfully
4142 : : * compiled into generated file bpf_test.h. This means having
4143 : : * clang with BPF target and xxd command to encode object.
4144 : : *
4145 : : * Test also needs the NULL PMD to be able to have something
4146 : : * to insert filter onto.
4147 : : */
4148 : : #if defined(TEST_BPF_ELF_LOAD) && defined(RTE_NET_NULL)
4149 : :
4150 : : /*
4151 : : * Helper function to write BPF object data to temporary file.
4152 : : * Returns temp file path on success, NULL on failure.
4153 : : * Caller must free the returned path and unlink the file.
4154 : : */
4155 : : static char *
4156 : : create_temp_bpf_file(const uint8_t *data, size_t size, const char *name)
4157 : : {
4158 : : char *tmpfile = NULL;
4159 : : int fd;
4160 : : ssize_t written;
4161 : :
4162 : : if (asprintf(&tmpfile, "/tmp/dpdk_bpf_%s_XXXXXX.o", name) < 0) {
4163 : : printf("%s@%d: asprintf failed: %s\n",
4164 : : __func__, __LINE__, strerror(errno));
4165 : : return NULL;
4166 : : }
4167 : :
4168 : : /* Create and open temp file */
4169 : : fd = mkstemps(tmpfile, strlen(".o"));
4170 : : if (fd < 0) {
4171 : : printf("%s@%d: mkstemps(%s) failed: %s\n",
4172 : : __func__, __LINE__, tmpfile, strerror(errno));
4173 : : free(tmpfile);
4174 : : return NULL;
4175 : : }
4176 : :
4177 : : /* Write BPF object data */
4178 : : written = write(fd, data, size);
4179 : : close(fd);
4180 : :
4181 : : if (written != (ssize_t)size) {
4182 : : printf("%s@%d: write failed: %s\n",
4183 : : __func__, __LINE__, strerror(errno));
4184 : : unlink(tmpfile);
4185 : : free(tmpfile);
4186 : : return NULL;
4187 : : }
4188 : :
4189 : : return tmpfile;
4190 : : }
4191 : :
4192 : : #include "test_bpf_load.h"
4193 : :
4194 : : /* Function loading BPF program from ELF image in memory. */
4195 : : typedef struct rte_bpf *
4196 : : (*load_elf_image_t)(const void *data, size_t size, const char *section,
4197 : : const struct rte_bpf_xsym *xsym, uint32_t nb_xsym, const struct rte_bpf_arg *prog_arg);
4198 : :
4199 : : /* Load BPF program by writing ELF image to temporary file and opening this file. */
4200 : : static struct rte_bpf *
4201 : : load_elf_image_temp_file(const void *data, size_t size, const char *section,
4202 : : const struct rte_bpf_xsym *xsym, uint32_t nb_xsym, const struct rte_bpf_arg *prog_arg)
4203 : : {
4204 : : /* Create temp file from embedded BPF object */
4205 : : char *tmpfile = create_temp_bpf_file(data, size, "test");
4206 : : if (tmpfile == NULL) {
4207 : : rte_errno = EIO;
4208 : : return NULL;
4209 : : }
4210 : :
4211 : : /* Try to load BPF program from temp file */
4212 : : const struct rte_bpf_prm prm = {
4213 : : .xsym = xsym,
4214 : : .nb_xsym = nb_xsym,
4215 : : .prog_arg = *prog_arg,
4216 : : };
4217 : :
4218 : : struct rte_bpf *bpf = rte_bpf_elf_load(&prm, tmpfile, section);
4219 : : unlink(tmpfile);
4220 : : free(tmpfile);
4221 : :
4222 : : return bpf;
4223 : : }
4224 : :
4225 : : /* Load BPF program by calling rte_bpf_load_ex and specifying image as the origin. */
4226 : : static struct rte_bpf *
4227 : : load_elf_image_direct(const void *data, size_t size, const char *section,
4228 : : const struct rte_bpf_xsym *xsym, uint32_t nb_xsym, const struct rte_bpf_arg *prog_arg)
4229 : : {
4230 : : return rte_bpf_load_ex(&(struct rte_bpf_prm_ex){
4231 : : .sz = sizeof(struct rte_bpf_prm_ex),
4232 : : .origin = RTE_BPF_ORIGIN_ELF_MEMORY,
4233 : : .elf_memory.data = data,
4234 : : .elf_memory.size = size,
4235 : : .elf_memory.section = section,
4236 : : .xsym = xsym,
4237 : : .nb_xsym = nb_xsym,
4238 : : .prog_arg[0] = *prog_arg,
4239 : : .nb_prog_arg = 1,
4240 : : });
4241 : : }
4242 : :
4243 : : /*
4244 : : * Test loading BPF program from an object file.
4245 : : * This test uses same arguments as previous test_call1 example.
4246 : : */
4247 : : static int
4248 : : test_bpf_elf_load(load_elf_image_t load_elf_image)
4249 : : {
4250 : : static const char test_section[] = "call1";
4251 : : uint8_t tbuf[sizeof(struct dummy_vect8)];
4252 : : const struct rte_bpf_xsym xsym[] = {
4253 : : {
4254 : : .name = RTE_STR(dummy_func1),
4255 : : .type = RTE_BPF_XTYPE_FUNC,
4256 : : .func = {
4257 : : .val = (void *)dummy_func1,
4258 : : .nb_args = 3,
4259 : : .args = {
4260 : : [0] = {
4261 : : .type = RTE_BPF_ARG_PTR,
4262 : : .size = sizeof(struct dummy_offset),
4263 : : },
4264 : : [1] = {
4265 : : .type = RTE_BPF_ARG_PTR,
4266 : : .size = sizeof(uint32_t),
4267 : : },
4268 : : [2] = {
4269 : : .type = RTE_BPF_ARG_PTR,
4270 : : .size = sizeof(uint64_t),
4271 : : },
4272 : : },
4273 : : },
4274 : : },
4275 : : };
4276 : : static const struct rte_bpf_arg prog_arg = {
4277 : : .type = RTE_BPF_ARG_PTR,
4278 : : .size = sizeof(tbuf),
4279 : : };
4280 : : struct rte_bpf *bpf;
4281 : : int ret;
4282 : :
4283 : : bpf = load_elf_image(app_test_bpf_load_o, app_test_bpf_load_o_len, test_section,
4284 : : xsym, RTE_DIM(xsym), &prog_arg);
4285 : :
4286 : : /* If libelf support is not available */
4287 : : if (bpf == NULL && rte_errno == ENOTSUP)
4288 : : return TEST_SKIPPED;
4289 : :
4290 : : TEST_ASSERT(bpf != NULL, "failed to load BPF %d:%s", rte_errno, strerror(rte_errno));
4291 : :
4292 : : /* Prepare test data */
4293 : : struct dummy_vect8 *dv = (struct dummy_vect8 *)tbuf;
4294 : :
4295 : : memset(dv, 0, sizeof(*dv));
4296 : : dv->in[0].u64 = (int32_t)TEST_FILL_1;
4297 : : dv->in[0].u32 = dv->in[0].u64;
4298 : : dv->in[0].u16 = dv->in[0].u64;
4299 : : dv->in[0].u8 = dv->in[0].u64;
4300 : :
4301 : : /* Execute loaded BPF program */
4302 : : uint64_t rc = rte_bpf_exec(bpf, tbuf);
4303 : : ret = test_call1_check(rc, tbuf);
4304 : : TEST_ASSERT(ret == 0, "test_call1_check failed: %d", ret);
4305 : :
4306 : : /* Test JIT if available */
4307 : : struct rte_bpf_jit jit;
4308 : : ret = rte_bpf_get_jit(bpf, &jit);
4309 : : TEST_ASSERT(ret == 0, "rte_bpf_get_jit failed: %d", ret);
4310 : :
4311 : : if (jit.func != NULL) {
4312 : : memset(dv, 0, sizeof(*dv));
4313 : : dv->in[0].u64 = (int32_t)TEST_FILL_1;
4314 : : dv->in[0].u32 = dv->in[0].u64;
4315 : : dv->in[0].u16 = dv->in[0].u64;
4316 : : dv->in[0].u8 = dv->in[0].u64;
4317 : :
4318 : : rc = jit.func(tbuf);
4319 : : ret = test_call1_check(rc, tbuf);
4320 : : TEST_ASSERT(ret == 0, "jit test_call1_check failed: %d", ret);
4321 : : }
4322 : :
4323 : : rte_bpf_destroy(bpf);
4324 : :
4325 : : printf("%s: ELF load test passed\n", __func__);
4326 : : return TEST_SUCCESS;
4327 : : }
4328 : :
4329 : : #include <rte_ethdev.h>
4330 : : #include <rte_bpf_ethdev.h>
4331 : : #include <rte_bus_vdev.h>
4332 : :
4333 : : #include "test_bpf_filter.h"
4334 : :
4335 : : #define BPF_TEST_BURST 128
4336 : : #define BPF_TEST_POOLSIZE 256 /* at least 2x burst */
4337 : : #define BPF_TEST_PKT_LEN 64 /* Ether + IP + TCP */
4338 : :
4339 : : static int null_vdev_setup(const char *name, uint16_t *port, struct rte_mempool *pool)
4340 : : {
4341 : : int ret;
4342 : :
4343 : : /* Make a null device */
4344 : : ret = rte_vdev_init(name, NULL);
4345 : : TEST_ASSERT(ret == 0, "rte_vdev_init(%s) failed: %d", name, ret);
4346 : :
4347 : : ret = rte_eth_dev_get_port_by_name(name, port);
4348 : : TEST_ASSERT(ret == 0, "failed to get port id for %s: %d", name, ret);
4349 : :
4350 : : struct rte_eth_conf conf = { };
4351 : : ret = rte_eth_dev_configure(*port, 1, 1, &conf);
4352 : : TEST_ASSERT(ret == 0, "failed to configure port %u: %d", *port, ret);
4353 : :
4354 : : struct rte_eth_txconf txconf = { };
4355 : : ret = rte_eth_tx_queue_setup(*port, 0, BPF_TEST_BURST, SOCKET_ID_ANY, &txconf);
4356 : : TEST_ASSERT(ret == 0, "failed to setup tx queue port %u: %d", *port, ret);
4357 : :
4358 : : struct rte_eth_rxconf rxconf = { };
4359 : : ret = rte_eth_rx_queue_setup(*port, 0, BPF_TEST_BURST, SOCKET_ID_ANY,
4360 : : &rxconf, pool);
4361 : : TEST_ASSERT(ret == 0, "failed to setup rx queue port %u: %d", *port, ret);
4362 : :
4363 : : ret = rte_eth_dev_start(*port);
4364 : : TEST_ASSERT(ret == 0, "failed to start port %u: %d", *port, ret);
4365 : :
4366 : : return 0;
4367 : : }
4368 : :
4369 : : static unsigned int
4370 : : setup_mbufs(struct rte_mbuf *burst[], unsigned int n)
4371 : : {
4372 : : struct rte_ether_hdr eh = {
4373 : : .ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4),
4374 : : };
4375 : : const struct rte_ipv4_hdr iph = {
4376 : : .version_ihl = RTE_IPV4_VHL_DEF,
4377 : : .total_length = rte_cpu_to_be_16(BPF_TEST_PKT_LEN - sizeof(eh)),
4378 : : .time_to_live = IPDEFTTL,
4379 : : .src_addr = rte_cpu_to_be_32(ip_src_addr),
4380 : : .dst_addr = rte_cpu_to_be_32(ip_dst_addr),
4381 : : };
4382 : : unsigned int tcp_count = 0;
4383 : :
4384 : : rte_eth_random_addr(eh.dst_addr.addr_bytes);
4385 : :
4386 : : for (unsigned int i = 0; i < n; i++) {
4387 : : struct rte_mbuf *mb = burst[i];
4388 : :
4389 : : /* Setup Ethernet header */
4390 : : *rte_pktmbuf_mtod(mb, struct rte_ether_hdr *) = eh;
4391 : :
4392 : : /* Setup IP header */
4393 : : struct rte_ipv4_hdr *ip
4394 : : = rte_pktmbuf_mtod_offset(mb, struct rte_ipv4_hdr *, sizeof(eh));
4395 : : *ip = iph;
4396 : :
4397 : : if (rte_rand() & 1) {
4398 : : struct rte_udp_hdr *udp
4399 : : = rte_pktmbuf_mtod_offset(mb, struct rte_udp_hdr *,
4400 : : sizeof(eh) + sizeof(iph));
4401 : :
4402 : : ip->next_proto_id = IPPROTO_UDP;
4403 : : *udp = (struct rte_udp_hdr) {
4404 : : .src_port = rte_cpu_to_be_16(9), /* discard */
4405 : : .dst_port = rte_cpu_to_be_16(9), /* discard */
4406 : : .dgram_len = BPF_TEST_PKT_LEN - sizeof(eh) - sizeof(iph),
4407 : : };
4408 : :
4409 : : } else {
4410 : : struct rte_tcp_hdr *tcp
4411 : : = rte_pktmbuf_mtod_offset(mb, struct rte_tcp_hdr *,
4412 : : sizeof(eh) + sizeof(iph));
4413 : :
4414 : : ip->next_proto_id = IPPROTO_TCP;
4415 : : *tcp = (struct rte_tcp_hdr) {
4416 : : .src_port = rte_cpu_to_be_16(9), /* discard */
4417 : : .dst_port = rte_cpu_to_be_16(9), /* discard */
4418 : : .tcp_flags = RTE_TCP_RST_FLAG,
4419 : : };
4420 : : ++tcp_count;
4421 : : }
4422 : : }
4423 : :
4424 : : return tcp_count;
4425 : : }
4426 : :
4427 : : static int bpf_tx_test(uint16_t port, struct rte_mempool *pool, load_elf_image_t load_elf_image,
4428 : : const char *section, uint32_t flags)
4429 : : {
4430 : : static const struct rte_bpf_arg prog_arg = {
4431 : : .type = RTE_BPF_ARG_PTR,
4432 : : .size = sizeof(struct dummy_net),
4433 : : };
4434 : : struct rte_bpf *bpf;
4435 : : int ret;
4436 : :
4437 : : /* Try to load BPF program from image */
4438 : : bpf = load_elf_image(app_test_bpf_filter_o, app_test_bpf_filter_o_len, section,
4439 : : NULL, 0, &prog_arg);
4440 : : TEST_ASSERT_NOT_NULL(bpf, "failed to load BPF filter from image, error=%d:(%s)\n",
4441 : : rte_errno, rte_strerror(rte_errno));
4442 : :
4443 : : /* Try to install loaded BPF program */
4444 : : ret = rte_bpf_eth_tx_install(port, 0, bpf, flags);
4445 : : if (ret != 0) {
4446 : : printf("%s@%d: failed to install BPF filter, error=%d:(%s)\n",
4447 : : __func__, __LINE__, rte_errno, rte_strerror(rte_errno));
4448 : : rte_bpf_destroy(bpf);
4449 : : return ret;
4450 : : }
4451 : :
4452 : : struct rte_mbuf *pkts[BPF_TEST_BURST] = { };
4453 : : ret = rte_pktmbuf_alloc_bulk(pool, pkts, BPF_TEST_BURST);
4454 : : TEST_ASSERT(ret == 0, "failed to allocate mbufs");
4455 : :
4456 : : uint16_t expect = setup_mbufs(pkts, BPF_TEST_BURST);
4457 : :
4458 : : uint16_t sent = rte_eth_tx_burst(port, 0, pkts, BPF_TEST_BURST);
4459 : : TEST_ASSERT_EQUAL(sent, expect, "rte_eth_tx_burst returned: %u expected %u",
4460 : : sent, expect);
4461 : :
4462 : : /* The unsent packets should be dropped */
4463 : : rte_pktmbuf_free_bulk(pkts + sent, BPF_TEST_BURST - sent);
4464 : :
4465 : : /* Pool should have same number of packets avail */
4466 : : unsigned int avail = rte_mempool_avail_count(pool);
4467 : : TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE,
4468 : : "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE);
4469 : :
4470 : : rte_bpf_eth_tx_unload(port, 0);
4471 : : return TEST_SUCCESS;
4472 : : }
4473 : :
4474 : : /* Test loading a transmit filter which only allows IPv4 packets */
4475 : : static int
4476 : : test_bpf_elf_tx_load(load_elf_image_t load_elf_image)
4477 : : {
4478 : : static const char null_dev[] = "net_null_bpf0";
4479 : : struct rte_mempool *mb_pool = NULL;
4480 : : uint16_t port = UINT16_MAX;
4481 : : int ret;
4482 : :
4483 : : printf("%s start\n", __func__);
4484 : :
4485 : : /* Make a pool for packets */
4486 : : mb_pool = rte_pktmbuf_pool_create("bpf_tx_test_pool", BPF_TEST_POOLSIZE,
4487 : : 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
4488 : : SOCKET_ID_ANY);
4489 : : TEST_ASSERT(mb_pool != NULL, "failed to create mempool");
4490 : :
4491 : : ret = null_vdev_setup(null_dev, &port, mb_pool);
4492 : : if (ret != 0)
4493 : : goto fail;
4494 : :
4495 : : /* Do test with VM */
4496 : : ret = bpf_tx_test(port, mb_pool, load_elf_image, "filter", 0);
4497 : : if (ret != 0)
4498 : : goto fail;
4499 : :
4500 : : /* Repeat with JIT */
4501 : : ret = bpf_tx_test(port, mb_pool, load_elf_image, "filter", RTE_BPF_ETH_F_JIT);
4502 : : if (ret == 0)
4503 : : printf("%s: TX ELF load test passed\n", __func__);
4504 : :
4505 : : fail:
4506 : : if (port != UINT16_MAX)
4507 : : rte_vdev_uninit(null_dev);
4508 : :
4509 : : rte_mempool_free(mb_pool);
4510 : :
4511 : : if (ret == 0)
4512 : : return TEST_SUCCESS;
4513 : : else if (ret == -ENOTSUP)
4514 : : return TEST_SKIPPED;
4515 : : else
4516 : : return TEST_FAILED;
4517 : : }
4518 : :
4519 : : /* Test loading a receive filter */
4520 : : static int bpf_rx_test(uint16_t port, struct rte_mempool *pool, load_elf_image_t load_elf_image,
4521 : : const char *section, uint32_t flags, uint16_t expected)
4522 : : {
4523 : : static const struct rte_bpf_arg prog_arg = {
4524 : : .type = RTE_BPF_ARG_PTR,
4525 : : .size = sizeof(struct dummy_net),
4526 : : };
4527 : : struct rte_mbuf *pkts[BPF_TEST_BURST];
4528 : : struct rte_bpf *bpf;
4529 : : int ret;
4530 : :
4531 : : /* Try to load BPF program from image */
4532 : : bpf = load_elf_image(app_test_bpf_filter_o, app_test_bpf_filter_o_len, section,
4533 : : NULL, 0, &prog_arg);
4534 : : TEST_ASSERT_NOT_NULL(bpf, "failed to load BPF filter from image, error=%d:(%s)\n",
4535 : : rte_errno, rte_strerror(rte_errno));
4536 : :
4537 : : /* Try to install loaded BPF program */
4538 : : ret = rte_bpf_eth_rx_install(port, 0, bpf, flags);
4539 : : if (ret != 0) {
4540 : : printf("%s@%d: failed to install BPF filter, error=%d:(%s)\n",
4541 : : __func__, __LINE__, rte_errno, rte_strerror(rte_errno));
4542 : : rte_bpf_destroy(bpf);
4543 : : return ret;
4544 : : }
4545 : :
4546 : : uint16_t rcvd = rte_eth_rx_burst(port, 0, pkts, BPF_TEST_BURST);
4547 : : TEST_ASSERT_EQUAL(rcvd, expected,
4548 : : "rte_eth_rx_burst returned: %u expect: %u", rcvd, expected);
4549 : :
4550 : : /* Drop the received packets */
4551 : : rte_pktmbuf_free_bulk(pkts, rcvd);
4552 : :
4553 : : rte_bpf_eth_rx_unload(port, 0);
4554 : :
4555 : : /* Pool should now be full */
4556 : : unsigned int avail = rte_mempool_avail_count(pool);
4557 : : TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE,
4558 : : "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE);
4559 : :
4560 : : return TEST_SUCCESS;
4561 : : }
4562 : :
4563 : : /* Test loading a receive filters, first with drop all and then with allow all packets */
4564 : : static int
4565 : : test_bpf_elf_rx_load(load_elf_image_t load_elf_image)
4566 : : {
4567 : : static const char null_dev[] = "net_null_bpf0";
4568 : : struct rte_mempool *pool = NULL;
4569 : : uint16_t port = UINT16_MAX;
4570 : : int ret;
4571 : :
4572 : : printf("%s start\n", __func__);
4573 : :
4574 : : /* Make a pool for packets */
4575 : : pool = rte_pktmbuf_pool_create("bpf_rx_test_pool", 2 * BPF_TEST_BURST,
4576 : : 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
4577 : : SOCKET_ID_ANY);
4578 : : TEST_ASSERT(pool != NULL, "failed to create mempool");
4579 : :
4580 : : ret = null_vdev_setup(null_dev, &port, pool);
4581 : : if (ret != 0)
4582 : : goto fail;
4583 : :
4584 : : /* Do test with VM */
4585 : : ret = bpf_rx_test(port, pool, load_elf_image, "drop", 0, 0);
4586 : : if (ret != 0)
4587 : : goto fail;
4588 : :
4589 : : /* Repeat with JIT */
4590 : : ret = bpf_rx_test(port, pool, load_elf_image, "drop", RTE_BPF_ETH_F_JIT, 0);
4591 : : if (ret != 0)
4592 : : goto fail;
4593 : :
4594 : : /* Repeat with allow all */
4595 : : ret = bpf_rx_test(port, pool, load_elf_image, "allow", 0, BPF_TEST_BURST);
4596 : : if (ret != 0)
4597 : : goto fail;
4598 : :
4599 : : /* Repeat with JIT */
4600 : : ret = bpf_rx_test(port, pool, load_elf_image, "allow", RTE_BPF_ETH_F_JIT, BPF_TEST_BURST);
4601 : : if (ret != 0)
4602 : : goto fail;
4603 : :
4604 : : printf("%s: RX ELF load test passed\n", __func__);
4605 : :
4606 : : /* The filter should free the mbufs */
4607 : : unsigned int avail = rte_mempool_avail_count(pool);
4608 : : TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE,
4609 : : "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE);
4610 : :
4611 : : fail:
4612 : : if (port != UINT16_MAX)
4613 : : rte_vdev_uninit(null_dev);
4614 : :
4615 : : rte_mempool_free(pool);
4616 : :
4617 : : return ret == 0 ? TEST_SUCCESS : TEST_FAILED;
4618 : : }
4619 : :
4620 : :
4621 : : static int
4622 : : test_bpf_elf(void)
4623 : : {
4624 : : static const load_elf_image_t elf_image_loaders[] = {
4625 : : load_elf_image_temp_file,
4626 : : load_elf_image_direct,
4627 : : };
4628 : :
4629 : : int ret = TEST_SUCCESS;
4630 : :
4631 : : for (int li = 0; li != RTE_DIM(elf_image_loaders); ++li) {
4632 : : if (ret == TEST_SUCCESS)
4633 : : ret = test_bpf_elf_load(elf_image_loaders[li]);
4634 : : if (ret == TEST_SUCCESS)
4635 : : ret = test_bpf_elf_tx_load(elf_image_loaders[li]);
4636 : : if (ret == TEST_SUCCESS)
4637 : : ret = test_bpf_elf_rx_load(elf_image_loaders[li]);
4638 : : }
4639 : :
4640 : : return ret;
4641 : : }
4642 : :
4643 : : #else
4644 : :
4645 : : static int
4646 : 1 : test_bpf_elf(void)
4647 : : {
4648 : : printf("BPF compile or NULL PMD not supported, skipping test\n");
4649 : 1 : return TEST_SKIPPED;
4650 : : }
4651 : :
4652 : : #endif /* !(TEST_BPF_ELF_LOAD && RTE_NULL) */
4653 : :
4654 : 303 : REGISTER_FAST_TEST(bpf_elf_autotest, NOHUGE_OK, ASAN_OK, test_bpf_elf);
4655 : :
4656 : : #ifndef RTE_HAS_LIBPCAP
4657 : :
4658 : : static int
4659 : : test_bpf_convert(void)
4660 : : {
4661 : : int dummy = 0;
4662 : : struct rte_bpf_prm *prm;
4663 : :
4664 : : prm = rte_bpf_convert(NULL);
4665 : : rte_free(prm);
4666 : : RTE_TEST_ASSERT_NULL(prm, "rte_bpf_convert(NULL) without libpcap did not return NULL\n");
4667 : :
4668 : : prm = rte_bpf_convert((const struct bpf_program *)&dummy);
4669 : : rte_free(prm);
4670 : : RTE_TEST_ASSERT_NULL(prm, "rte_bpf_convert(&dummy) without libpcap did not return NULL\n");
4671 : :
4672 : : printf("BPF convert RTE_HAS_LIBPCAP is undefined, skipping full test\n");
4673 : : return TEST_SKIPPED;
4674 : : }
4675 : :
4676 : : #else
4677 : : #include <pcap/pcap.h>
4678 : :
4679 : : static void
4680 : 28 : test_bpf_dump(struct bpf_program *cbf, const struct rte_bpf_prm *prm)
4681 : : {
4682 : 28 : printf("cBPF program (%u insns)\n", cbf->bf_len);
4683 : 28 : bpf_dump(cbf, 1);
4684 : :
4685 [ + - ]: 28 : if (prm != NULL) {
4686 : 28 : printf("\neBPF program (%u insns)\n", prm->nb_ins);
4687 : 28 : rte_bpf_dump(stdout, prm->ins, prm->nb_ins);
4688 : : }
4689 : 28 : }
4690 : :
4691 : : /* Function loading BPF program from cBPF instructions array. */
4692 : : typedef struct rte_bpf *
4693 : : (*load_cbpf_program_t)(struct bpf_program *cbpf_program, const char *str);
4694 : :
4695 : : /* Load BPF program by converting cBPF array to rte_bpf_prm and then opening it. */
4696 : : static struct rte_bpf *
4697 : 28 : load_cbpf_program_convert(struct bpf_program *cbpf_program, const char *str)
4698 : : {
4699 : : struct rte_bpf_prm *prm = NULL;
4700 : : struct rte_bpf *bpf;
4701 : :
4702 : 28 : prm = rte_bpf_convert(cbpf_program);
4703 [ - + ]: 28 : if (prm == NULL) {
4704 : : printf("%s@%d: bpf_convert(\"%s\") failed\n",
4705 : : __func__, __LINE__, str);
4706 : 0 : return NULL;
4707 : : }
4708 : :
4709 : : printf("bpf convert(\"%s\") produced:\n", str);
4710 : 28 : rte_bpf_dump(stdout, prm->ins, prm->nb_ins);
4711 : :
4712 : : printf("%s \"%s\"\n", __func__, str);
4713 : 28 : test_bpf_dump(cbpf_program, prm);
4714 : :
4715 : 28 : bpf = rte_bpf_load(prm);
4716 : 28 : rte_free(prm);
4717 : :
4718 : 28 : return bpf;
4719 : : }
4720 : :
4721 : : /* Load BPF program by calling rte_bpf_load_ex and specifying cBPF array as the origin. */
4722 : : static struct rte_bpf *
4723 : 28 : load_cbpf_program_direct(struct bpf_program *cbpf_program, const char *str __rte_unused)
4724 : : {
4725 : 56 : return rte_bpf_load_ex(&(struct rte_bpf_prm_ex){
4726 : : .sz = sizeof(struct rte_bpf_prm_ex),
4727 : : .origin = RTE_BPF_ORIGIN_CBPF,
4728 : 28 : .cbpf.ins = cbpf_program->bf_insns,
4729 : 28 : .cbpf.nb_ins = cbpf_program->bf_len,
4730 : : .prog_arg[0] = {
4731 : : .type = RTE_BPF_ARG_PTR_MBUF,
4732 : : .size = sizeof(struct rte_mbuf),
4733 : : },
4734 : : .nb_prog_arg = 1,
4735 : : });
4736 : : }
4737 : :
4738 : : static int
4739 : 4 : test_bpf_match(pcap_t *pcap, const char *str, struct rte_mbuf *mb,
4740 : : load_cbpf_program_t load_cbpf_program)
4741 : : {
4742 : : struct bpf_program fcode;
4743 : : struct rte_bpf *bpf;
4744 : : int ret = -1;
4745 : : uint64_t rc;
4746 : :
4747 [ - + ]: 4 : if (pcap_compile(pcap, &fcode, str, 1, PCAP_NETMASK_UNKNOWN)) {
4748 : 0 : printf("%s@%d: pcap_compile(\"%s\") failed: %s;\n",
4749 : : __func__, __LINE__, str, pcap_geterr(pcap));
4750 : 0 : return -1;
4751 : : }
4752 : :
4753 : 4 : bpf = load_cbpf_program(&fcode, str);
4754 [ - + ]: 4 : if (bpf == NULL) {
4755 : 0 : printf("%s@%d: failed to load cbpf program for \"%s\", error=%d(%s);\n",
4756 : : __func__, __LINE__, str, rte_errno, strerror(rte_errno));
4757 : 0 : goto error;
4758 : : }
4759 : :
4760 : 4 : rc = rte_bpf_exec(bpf, mb);
4761 : : /* The return code from bpf capture filter is non-zero if matched */
4762 : 4 : ret = (rc == 0);
4763 : 4 : error:
4764 [ + - ]: 4 : if (bpf)
4765 : 4 : rte_bpf_destroy(bpf);
4766 : 4 : pcap_freecode(&fcode);
4767 : 4 : return ret;
4768 : : }
4769 : :
4770 : : /* Basic sanity test can we match a IP packet */
4771 : : static int
4772 : 1 : test_bpf_filter_sanity(pcap_t *pcap)
4773 : : {
4774 : : static const load_cbpf_program_t cbpf_program_loaders[] = {
4775 : : load_cbpf_program_convert,
4776 : : load_cbpf_program_direct,
4777 : : };
4778 : :
4779 : : const uint32_t plen = 100;
4780 : : struct rte_mbuf mb, *m;
4781 : : uint8_t tbuf[RTE_MBUF_DEFAULT_BUF_SIZE];
4782 : : struct {
4783 : : struct rte_ether_hdr eth_hdr;
4784 : : struct rte_ipv4_hdr ip_hdr;
4785 : : } *hdr;
4786 : :
4787 : : memset(&mb, 0, sizeof(mb));
4788 : 1 : dummy_mbuf_prep(&mb, tbuf, sizeof(tbuf), plen);
4789 : : m = &mb;
4790 : :
4791 : 1 : hdr = rte_pktmbuf_mtod(m, typeof(hdr));
4792 : 1 : hdr->eth_hdr = (struct rte_ether_hdr) {
4793 : : .dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
4794 : : .ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4),
4795 : : };
4796 : 1 : hdr->ip_hdr = (struct rte_ipv4_hdr) {
4797 : : .version_ihl = RTE_IPV4_VHL_DEF,
4798 : : .total_length = rte_cpu_to_be_16(plen),
4799 : : .time_to_live = IPDEFTTL,
4800 : : .next_proto_id = IPPROTO_RAW,
4801 : : .src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK),
4802 : : .dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST),
4803 : : };
4804 : :
4805 [ + + ]: 3 : for (int li = 0; li != RTE_DIM(cbpf_program_loaders); ++li) {
4806 [ - + ]: 2 : if (test_bpf_match(pcap, "ip", m, cbpf_program_loaders[li]) != 0) {
4807 : : printf("%s@%d: filter \"ip\" doesn't match test data\n",
4808 : : __func__, __LINE__);
4809 : 0 : return -1;
4810 : : }
4811 [ - + ]: 2 : if (test_bpf_match(pcap, "not ip", m, cbpf_program_loaders[li]) == 0) {
4812 : : printf("%s@%d: filter \"not ip\" does match test data\n",
4813 : : __func__, __LINE__);
4814 : 0 : return -1;
4815 : : }
4816 : : }
4817 : :
4818 : : return 0;
4819 : : }
4820 : :
4821 : : /*
4822 : : * Some sample pcap filter strings from
4823 : : * https://wiki.wireshark.org/CaptureFilters
4824 : : */
4825 : : static const char * const sample_filters[] = {
4826 : : "host 172.18.5.4",
4827 : : "net 192.168.0.0/24",
4828 : : "src net 192.168.0.0/24",
4829 : : "src net 192.168.0.0 mask 255.255.255.0",
4830 : : "dst net 192.168.0.0/24",
4831 : : "dst net 192.168.0.0 mask 255.255.255.0",
4832 : : "port 53",
4833 : : "host 192.0.2.1 and not (port 80 or port 25)",
4834 : : "host 2001:4b98:db0::8 and not port 80 and not port 25",
4835 : : "port not 53 and not arp",
4836 : : "(tcp[0:2] > 1500 and tcp[0:2] < 1550) or (tcp[2:2] > 1500 and tcp[2:2] < 1550)",
4837 : : "ether proto 0x888e",
4838 : : "ether[0] & 1 = 0 and ip[16] >= 224",
4839 : : "icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply",
4840 : : "tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net 127.0.0.1",
4841 : : "not ether dst 01:80:c2:00:00:0e",
4842 : : "not broadcast and not multicast",
4843 : : "dst host ff02::1",
4844 : : "port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420",
4845 : : /* Worms */
4846 : : "dst port 135 and tcp port 135 and ip[2:2]==48",
4847 : : "icmp[icmptype]==icmp-echo and ip[2:2]==92 and icmp[8:4]==0xAAAAAAAA",
4848 : : "dst port 135 or dst port 445 or dst port 1433"
4849 : : " and tcp[tcpflags] & (tcp-syn) != 0"
4850 : : " and tcp[tcpflags] & (tcp-ack) = 0 and src net 192.168.0.0/24",
4851 : : "tcp src port 443 and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4] = 0x18)"
4852 : : " and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4 + 1] = 0x03)"
4853 : : " and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4 + 2] < 0x04)"
4854 : : " and ((ip[2:2] - 4 * (ip[0] & 0x0F) - 4 * ((tcp[12] & 0xF0) >> 4) > 69))",
4855 : : /* Other */
4856 : : "len = 128",
4857 : : "host 1::1 or host 1::1 or host 1::1 or host 1::1 or host 1::1 or host 1::1",
4858 : : ("host 1::1 or host 1::2 or host 1::3 or host 1::4 or host 1::5 "
4859 : : "or host 192.0.2.1 or host 192.0.2.100 or host 192.0.2.200"),
4860 : : };
4861 : :
4862 : : static int
4863 : 52 : test_bpf_filter(pcap_t *pcap, const char *s, load_cbpf_program_t load_cbpf_program)
4864 : : {
4865 : : struct bpf_program fcode;
4866 : : struct rte_bpf *bpf;
4867 : :
4868 [ - + ]: 52 : if (pcap_compile(pcap, &fcode, s, 1, PCAP_NETMASK_UNKNOWN)) {
4869 : 0 : printf("%s@%d: pcap_compile(\"%s\") failed: %s;\n",
4870 : : __func__, __LINE__, s, pcap_geterr(pcap));
4871 : 0 : return -1;
4872 : : }
4873 : :
4874 : 52 : bpf = load_cbpf_program(&fcode, s);
4875 [ - + ]: 52 : if (bpf == NULL) {
4876 : 0 : printf("%s@%d: failed to load cbpf program for \"%s\", error=%d(%s);\n",
4877 : : __func__, __LINE__, s, rte_errno, strerror(rte_errno));
4878 : 0 : test_bpf_dump(&fcode, NULL);
4879 : : }
4880 : :
4881 : 52 : rte_bpf_destroy(bpf);
4882 : :
4883 : 52 : pcap_freecode(&fcode);
4884 [ + - ]: 52 : return (bpf == NULL) ? -1 : 0;
4885 : : }
4886 : :
4887 : : static int
4888 : 1 : test_bpf_convert(void)
4889 : : {
4890 : : unsigned int i;
4891 : : pcap_t *pcap;
4892 : : int rc;
4893 : :
4894 : 1 : pcap = pcap_open_dead(DLT_EN10MB, 262144);
4895 [ - + ]: 1 : if (!pcap) {
4896 : : printf("pcap_open_dead failed\n");
4897 : 0 : return -1;
4898 : : }
4899 : :
4900 : 1 : rc = test_bpf_filter_sanity(pcap);
4901 [ + + ]: 27 : for (i = 0; i < RTE_DIM(sample_filters); i++) {
4902 : 26 : rc |= test_bpf_filter(pcap, sample_filters[i], load_cbpf_program_convert);
4903 : 26 : rc |= test_bpf_filter(pcap, sample_filters[i], load_cbpf_program_direct);
4904 : : }
4905 : :
4906 : 1 : pcap_close(pcap);
4907 : 1 : return rc;
4908 : : }
4909 : :
4910 : : #endif /* RTE_HAS_LIBPCAP */
4911 : :
4912 : 303 : REGISTER_FAST_TEST(bpf_convert_autotest, NOHUGE_OK, ASAN_OK, test_bpf_convert);
4913 : :
4914 : : /*
4915 : : * Tests of BPF atomic instructions.
4916 : : */
4917 : :
4918 : : /* Value that should be returned by the xchg test programs. */
4919 : : #define XCHG_RETURN_VALUE 0xdeadbeefcafebabe
4920 : :
4921 : : /* Operand of XADD, should overflow both 32-bit and 64-bit parts of initial value. */
4922 : : #define XADD_OPERAND 0xc1c3c5c7c9cbcdcf
4923 : :
4924 : : /* Argument type of the xchg test program. */
4925 : : struct xchg_arg {
4926 : : uint64_t value0;
4927 : : uint64_t value1;
4928 : : };
4929 : :
4930 : : /* Initial value of the data area passed to the xchg test program. */
4931 : : static const struct xchg_arg xchg_input = {
4932 : : .value0 = 0xa0a1a2a3a4a5a6a7,
4933 : : .value1 = 0xb0b1b2b3b4b5b6b7,
4934 : : };
4935 : :
4936 : : /* Run program against xchg_input and compare output value with expected. */
4937 : : static int
4938 : 4 : run_xchg_test(uint32_t nb_ins, const struct ebpf_insn *ins, struct xchg_arg expected)
4939 : : {
4940 : 4 : const struct rte_bpf_prm prm = {
4941 : : .ins = ins,
4942 : : .nb_ins = nb_ins,
4943 : : .prog_arg = {
4944 : : .type = RTE_BPF_ARG_PTR,
4945 : : .size = sizeof(struct xchg_arg),
4946 : : },
4947 : : };
4948 : :
4949 [ + + ]: 12 : for (int use_jit = false; use_jit <= true; ++use_jit) {
4950 : 8 : struct xchg_arg argument = xchg_input;
4951 : : uint64_t return_value;
4952 : :
4953 : 8 : struct rte_bpf *const bpf = rte_bpf_load(&prm);
4954 [ - + ]: 8 : RTE_TEST_ASSERT_NOT_NULL(bpf, "expect rte_bpf_load() != NULL");
4955 : :
4956 [ + + ]: 8 : if (use_jit) {
4957 : : struct rte_bpf_jit jit;
4958 [ - + ]: 4 : RTE_TEST_ASSERT_SUCCESS(rte_bpf_get_jit(bpf, &jit),
4959 : : "expect rte_bpf_get_jit() to succeed");
4960 [ - + ]: 4 : if (jit.func == NULL) {
4961 : : /* No JIT on this platform. */
4962 : 0 : rte_bpf_destroy(bpf);
4963 : 0 : continue;
4964 : : }
4965 : :
4966 : 4 : return_value = jit.func(&argument);
4967 : : } else
4968 : 4 : return_value = rte_bpf_exec(bpf, &argument);
4969 : :
4970 : 8 : rte_bpf_destroy(bpf);
4971 : :
4972 [ - + ]: 8 : RTE_TEST_ASSERT_EQUAL(return_value, XCHG_RETURN_VALUE,
4973 : : "expect return_value == %#jx, found %#jx, use_jit=%d",
4974 : : (uintmax_t)XCHG_RETURN_VALUE, (uintmax_t)return_value,
4975 : : use_jit);
4976 : :
4977 [ - + ]: 8 : RTE_TEST_ASSERT_EQUAL(argument.value0, expected.value0,
4978 : : "expect value0 == %#jx, found %#jx, use_jit=%d",
4979 : : (uintmax_t)expected.value0, (uintmax_t)argument.value0,
4980 : : use_jit);
4981 : :
4982 [ - + ]: 8 : RTE_TEST_ASSERT_EQUAL(argument.value1, expected.value1,
4983 : : "expect value1 == %#jx, found %#jx, use_jit=%d",
4984 : : (uintmax_t)expected.value1, (uintmax_t)argument.value1,
4985 : : use_jit);
4986 : : }
4987 : :
4988 : : return TEST_SUCCESS;
4989 : : }
4990 : :
4991 : : /*
4992 : : * Test 32-bit XADD.
4993 : : *
4994 : : * - Pre-fill r0 with return value.
4995 : : * - Fill r2 with XADD_OPERAND.
4996 : : * - Add (uint32_t)XADD_OPERAND to *(uint32_t *)&value0.
4997 : : * - Negate r2 and use it in the next operation to verify it was not corrupted.
4998 : : * - Add (uint32_t)-XADD_OPERAND to *(uint32_t *)&value1.
4999 : : * - Return r0 which should remain unchanged.
5000 : : */
5001 : :
5002 : : static int
5003 : 1 : test_xadd32(void)
5004 : : {
5005 : : static const struct ebpf_insn ins[] = {
5006 : : {
5007 : : /* Set r0 to return value. */
5008 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5009 : : .dst_reg = EBPF_REG_0,
5010 : : .imm = (uint32_t)XCHG_RETURN_VALUE,
5011 : : },
5012 : : {
5013 : : /* Second part of 128-bit instruction. */
5014 : : .imm = XCHG_RETURN_VALUE >> 32,
5015 : : },
5016 : : {
5017 : : /* Set r2 to XADD operand. */
5018 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5019 : : .dst_reg = EBPF_REG_2,
5020 : : .imm = (uint32_t)XADD_OPERAND,
5021 : : },
5022 : : {
5023 : : /* Second part of 128-bit instruction. */
5024 : : .imm = XADD_OPERAND >> 32,
5025 : : },
5026 : : {
5027 : : /* Atomically add r2 to value0, 32-bit. */
5028 : : .code = (BPF_STX | EBPF_ATOMIC | BPF_W),
5029 : : .src_reg = EBPF_REG_2,
5030 : : .dst_reg = EBPF_REG_1,
5031 : : .off = offsetof(struct xchg_arg, value0),
5032 : : .imm = BPF_ATOMIC_ADD,
5033 : : },
5034 : : {
5035 : : /* Negate r2. */
5036 : : .code = (EBPF_ALU64 | BPF_NEG | BPF_K),
5037 : : .dst_reg = EBPF_REG_2,
5038 : : },
5039 : : {
5040 : : /* Atomically add r2 to value1, 32-bit. */
5041 : : .code = (BPF_STX | EBPF_ATOMIC | BPF_W),
5042 : : .src_reg = EBPF_REG_2,
5043 : : .dst_reg = EBPF_REG_1,
5044 : : .off = offsetof(struct xchg_arg, value1),
5045 : : .imm = BPF_ATOMIC_ADD,
5046 : : },
5047 : : {
5048 : : .code = (BPF_JMP | EBPF_EXIT),
5049 : : },
5050 : : };
5051 : 1 : const struct xchg_arg expected = {
5052 : : #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
5053 : : /* Only high 32 bits should be added. */
5054 : : .value0 = xchg_input.value0 + (XADD_OPERAND & RTE_GENMASK64(63, 32)),
5055 : : .value1 = xchg_input.value1 - (XADD_OPERAND & RTE_GENMASK64(63, 32)),
5056 : : #elif RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
5057 : : /* Only low 32 bits should be added, without carry. */
5058 : : .value0 = (xchg_input.value0 & RTE_GENMASK64(63, 32)) |
5059 : : ((xchg_input.value0 + XADD_OPERAND) & RTE_GENMASK64(31, 0)),
5060 : : .value1 = (xchg_input.value1 & RTE_GENMASK64(63, 32)) |
5061 : : ((xchg_input.value1 - XADD_OPERAND) & RTE_GENMASK64(31, 0)),
5062 : : #else
5063 : : #error Unsupported endianness.
5064 : : #endif
5065 : : };
5066 : 1 : return run_xchg_test(RTE_DIM(ins), ins, expected);
5067 : : }
5068 : :
5069 : 303 : REGISTER_FAST_TEST(bpf_xadd32_autotest, NOHUGE_OK, ASAN_OK, test_xadd32);
5070 : :
5071 : : /*
5072 : : * Test 64-bit XADD.
5073 : : *
5074 : : * - Pre-fill r0 with return value.
5075 : : * - Fill r2 with XADD_OPERAND.
5076 : : * - Add XADD_OPERAND to value0.
5077 : : * - Negate r2 and use it in the next operation to verify it was not corrupted.
5078 : : * - Add -XADD_OPERAND to value1.
5079 : : * - Return r0 which should remain unchanged.
5080 : : */
5081 : :
5082 : : static int
5083 : 1 : test_xadd64(void)
5084 : : {
5085 : : static const struct ebpf_insn ins[] = {
5086 : : {
5087 : : /* Set r0 to return value. */
5088 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5089 : : .dst_reg = EBPF_REG_0,
5090 : : .imm = (uint32_t)XCHG_RETURN_VALUE,
5091 : : },
5092 : : {
5093 : : /* Second part of 128-bit instruction. */
5094 : : .imm = XCHG_RETURN_VALUE >> 32,
5095 : : },
5096 : : {
5097 : : /* Set r2 to XADD operand. */
5098 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5099 : : .dst_reg = EBPF_REG_2,
5100 : : .imm = (uint32_t)XADD_OPERAND,
5101 : : },
5102 : : {
5103 : : /* Second part of 128-bit instruction. */
5104 : : .imm = XADD_OPERAND >> 32,
5105 : : },
5106 : : {
5107 : : /* Atomically add r2 to value0. */
5108 : : .code = (BPF_STX | EBPF_ATOMIC | EBPF_DW),
5109 : : .src_reg = EBPF_REG_2,
5110 : : .dst_reg = EBPF_REG_1,
5111 : : .off = offsetof(struct xchg_arg, value0),
5112 : : .imm = BPF_ATOMIC_ADD,
5113 : : },
5114 : : {
5115 : : /* Negate r2. */
5116 : : .code = (EBPF_ALU64 | BPF_NEG | BPF_K),
5117 : : .dst_reg = EBPF_REG_2,
5118 : : },
5119 : : {
5120 : : /* Atomically add r2 to value1. */
5121 : : .code = (BPF_STX | EBPF_ATOMIC | EBPF_DW),
5122 : : .src_reg = EBPF_REG_2,
5123 : : .dst_reg = EBPF_REG_1,
5124 : : .off = offsetof(struct xchg_arg, value1),
5125 : : .imm = BPF_ATOMIC_ADD,
5126 : : },
5127 : : {
5128 : : .code = (BPF_JMP | EBPF_EXIT),
5129 : : },
5130 : : };
5131 : 1 : const struct xchg_arg expected = {
5132 : : .value0 = xchg_input.value0 + XADD_OPERAND,
5133 : : .value1 = xchg_input.value1 - XADD_OPERAND,
5134 : : };
5135 : 1 : return run_xchg_test(RTE_DIM(ins), ins, expected);
5136 : : }
5137 : :
5138 : 303 : REGISTER_FAST_TEST(bpf_xadd64_autotest, NOHUGE_OK, ASAN_OK, test_xadd64);
5139 : :
5140 : : /*
5141 : : * Test 32-bit XCHG.
5142 : : *
5143 : : * - Pre-fill r2 with return value.
5144 : : * - Exchange *(uint32_t *)&value0 and *(uint32_t *)&value1 via r2.
5145 : : * - Upper half of r2 should get cleared, so add it back before returning.
5146 : : */
5147 : :
5148 : : static int
5149 : 1 : test_xchg32(void)
5150 : : {
5151 : : static const struct ebpf_insn ins[] = {
5152 : : {
5153 : : /* Set r2 to return value. */
5154 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5155 : : .dst_reg = EBPF_REG_2,
5156 : : .imm = (uint32_t)XCHG_RETURN_VALUE,
5157 : : },
5158 : : {
5159 : : /* Second part of 128-bit instruction. */
5160 : : .imm = XCHG_RETURN_VALUE >> 32,
5161 : : },
5162 : : {
5163 : : /* Atomically exchange r2 with value0, 32-bit. */
5164 : : .code = (BPF_STX | EBPF_ATOMIC | BPF_W),
5165 : : .src_reg = EBPF_REG_2,
5166 : : .dst_reg = EBPF_REG_1,
5167 : : .off = offsetof(struct xchg_arg, value0),
5168 : : .imm = BPF_ATOMIC_XCHG,
5169 : : },
5170 : : {
5171 : : /* Atomically exchange r2 with value1, 32-bit. */
5172 : : .code = (BPF_STX | EBPF_ATOMIC | BPF_W),
5173 : : .src_reg = EBPF_REG_2,
5174 : : .dst_reg = EBPF_REG_1,
5175 : : .off = offsetof(struct xchg_arg, value1),
5176 : : .imm = BPF_ATOMIC_XCHG,
5177 : : },
5178 : : {
5179 : : /* Atomically exchange r2 with value0, 32-bit. */
5180 : : .code = (BPF_STX | EBPF_ATOMIC | BPF_W),
5181 : : .src_reg = EBPF_REG_2,
5182 : : .dst_reg = EBPF_REG_1,
5183 : : .off = offsetof(struct xchg_arg, value0),
5184 : : .imm = BPF_ATOMIC_XCHG,
5185 : : },
5186 : : {
5187 : : /* Set upper half of r0 to return value. */
5188 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5189 : : .dst_reg = EBPF_REG_0,
5190 : : .imm = 0,
5191 : : },
5192 : : {
5193 : : /* Second part of 128-bit instruction. */
5194 : : .imm = XCHG_RETURN_VALUE >> 32,
5195 : : },
5196 : : {
5197 : : /*
5198 : : * Add r2 (should have upper half cleared by this time)
5199 : : * to r0 to use as a return value.
5200 : : */
5201 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
5202 : : .src_reg = EBPF_REG_2,
5203 : : .dst_reg = EBPF_REG_0,
5204 : : },
5205 : : {
5206 : : .code = (BPF_JMP | EBPF_EXIT),
5207 : : },
5208 : : };
5209 : 1 : struct xchg_arg expected = {
5210 : : #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
5211 : : /* Only high 32 bits should be exchanged. */
5212 : : .value0 =
5213 : : (xchg_input.value0 & RTE_GENMASK64(31, 0)) |
5214 : : (xchg_input.value1 & RTE_GENMASK64(63, 32)),
5215 : : .value1 =
5216 : : (xchg_input.value1 & RTE_GENMASK64(31, 0)) |
5217 : : (xchg_input.value0 & RTE_GENMASK64(63, 32)),
5218 : : #elif RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
5219 : : /* Only low 32 bits should be exchanged. */
5220 : : .value0 =
5221 : : (xchg_input.value1 & RTE_GENMASK64(31, 0)) |
5222 : : (xchg_input.value0 & RTE_GENMASK64(63, 32)),
5223 : : .value1 =
5224 : : (xchg_input.value0 & RTE_GENMASK64(31, 0)) |
5225 : : (xchg_input.value1 & RTE_GENMASK64(63, 32)),
5226 : : #else
5227 : : #error Unsupported endianness.
5228 : : #endif
5229 : : };
5230 : 1 : return run_xchg_test(RTE_DIM(ins), ins, expected);
5231 : : }
5232 : :
5233 : 303 : REGISTER_FAST_TEST(bpf_xchg32_autotest, NOHUGE_OK, ASAN_OK, test_xchg32);
5234 : :
5235 : : /*
5236 : : * Test 64-bit XCHG.
5237 : : *
5238 : : * - Pre-fill r2 with return value.
5239 : : * - Exchange value0 and value1 via r2.
5240 : : * - Return r2, which should remain unchanged.
5241 : : */
5242 : :
5243 : : static int
5244 : 1 : test_xchg64(void)
5245 : : {
5246 : : static const struct ebpf_insn ins[] = {
5247 : : {
5248 : : /* Set r2 to return value. */
5249 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5250 : : .dst_reg = EBPF_REG_2,
5251 : : .imm = (uint32_t)XCHG_RETURN_VALUE,
5252 : : },
5253 : : {
5254 : : /* Second part of 128-bit instruction. */
5255 : : .imm = XCHG_RETURN_VALUE >> 32,
5256 : : },
5257 : : {
5258 : : /* Atomically exchange r2 with value0. */
5259 : : .code = (BPF_STX | EBPF_ATOMIC | EBPF_DW),
5260 : : .src_reg = EBPF_REG_2,
5261 : : .dst_reg = EBPF_REG_1,
5262 : : .off = offsetof(struct xchg_arg, value0),
5263 : : .imm = BPF_ATOMIC_XCHG,
5264 : : },
5265 : : {
5266 : : /* Atomically exchange r2 with value1. */
5267 : : .code = (BPF_STX | EBPF_ATOMIC | EBPF_DW),
5268 : : .src_reg = EBPF_REG_2,
5269 : : .dst_reg = EBPF_REG_1,
5270 : : .off = offsetof(struct xchg_arg, value1),
5271 : : .imm = BPF_ATOMIC_XCHG,
5272 : : },
5273 : : {
5274 : : /* Atomically exchange r2 with value0. */
5275 : : .code = (BPF_STX | EBPF_ATOMIC | EBPF_DW),
5276 : : .src_reg = EBPF_REG_2,
5277 : : .dst_reg = EBPF_REG_1,
5278 : : .off = offsetof(struct xchg_arg, value0),
5279 : : .imm = BPF_ATOMIC_XCHG,
5280 : : },
5281 : : {
5282 : : /* Copy r2 to r0 to use as a return value. */
5283 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
5284 : : .src_reg = EBPF_REG_2,
5285 : : .dst_reg = EBPF_REG_0,
5286 : : },
5287 : : {
5288 : : .code = (BPF_JMP | EBPF_EXIT),
5289 : : },
5290 : : };
5291 : 1 : const struct xchg_arg expected = {
5292 : : .value0 = xchg_input.value1,
5293 : : .value1 = xchg_input.value0,
5294 : : };
5295 : 1 : return run_xchg_test(RTE_DIM(ins), ins, expected);
5296 : : }
5297 : :
5298 : 303 : REGISTER_FAST_TEST(bpf_xchg64_autotest, NOHUGE_OK, ASAN_OK, test_xchg64);
5299 : :
5300 : : /*
5301 : : * Test invalid and unsupported atomic imm values (also valid ones for control).
5302 : : *
5303 : : * For realism use a meaningful subset of the test_xchg64 program.
5304 : : */
5305 : :
5306 : : static int
5307 : 230 : test_atomic_imm(int32_t imm, bool is_valid)
5308 : : {
5309 : 230 : const struct ebpf_insn ins[] = {
5310 : : {
5311 : : /* Set r2 to return value. */
5312 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
5313 : : .dst_reg = EBPF_REG_2,
5314 : : .imm = (uint32_t)XCHG_RETURN_VALUE,
5315 : : },
5316 : : {
5317 : : /* Second part of 128-bit instruction. */
5318 : : .imm = XCHG_RETURN_VALUE >> 32,
5319 : : },
5320 : : {
5321 : : /* Atomically exchange r2 with value0. */
5322 : : .code = (BPF_STX | EBPF_ATOMIC | EBPF_DW),
5323 : : .src_reg = EBPF_REG_2,
5324 : : .dst_reg = EBPF_REG_1,
5325 : : .off = offsetof(struct xchg_arg, value0),
5326 : : .imm = imm,
5327 : : },
5328 : : {
5329 : : /* Copy r2 to r0 to use as a return value. */
5330 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
5331 : : .src_reg = EBPF_REG_2,
5332 : : .dst_reg = EBPF_REG_0,
5333 : : },
5334 : : {
5335 : : .code = (BPF_JMP | EBPF_EXIT),
5336 : : },
5337 : : };
5338 : 230 : const struct rte_bpf_prm prm = {
5339 : : .ins = ins,
5340 : : .nb_ins = RTE_DIM(ins),
5341 : : .prog_arg = {
5342 : : .type = RTE_BPF_ARG_PTR,
5343 : : .size = sizeof(struct xchg_arg),
5344 : : },
5345 : : };
5346 : :
5347 : 230 : struct rte_bpf *const bpf = rte_bpf_load(&prm);
5348 : 230 : rte_bpf_destroy(bpf);
5349 : :
5350 [ + + ]: 230 : if (is_valid)
5351 [ - + ]: 2 : RTE_TEST_ASSERT_NOT_NULL(bpf, "expect rte_bpf_load() != NULL, imm=%#x", imm);
5352 : : else
5353 [ - + ]: 228 : RTE_TEST_ASSERT_NULL(bpf, "expect rte_bpf_load() == NULL, imm=%#x", imm);
5354 : :
5355 : : return TEST_SUCCESS;
5356 : : }
5357 : :
5358 : : static int
5359 : 1 : test_atomic_imms(void)
5360 : : {
5361 [ - + ]: 1 : RTE_TEST_ASSERT_SUCCESS(test_atomic_imm(INT32_MIN, false), "expect success");
5362 [ + + ]: 229 : for (int32_t imm = BPF_ATOMIC_ADD - 1; imm <= BPF_ATOMIC_XCHG + 1; ++imm) {
5363 : 228 : const bool is_valid = imm == BPF_ATOMIC_ADD || imm == BPF_ATOMIC_XCHG;
5364 [ - + ]: 228 : RTE_TEST_ASSERT_SUCCESS(test_atomic_imm(imm, is_valid), "expect success");
5365 : : }
5366 [ - + ]: 1 : RTE_TEST_ASSERT_SUCCESS(test_atomic_imm(INT32_MAX, false), "expect success");
5367 : :
5368 : : return TEST_SUCCESS;
5369 : : }
5370 : :
5371 : 303 : REGISTER_FAST_TEST(bpf_atomic_imms_autotest, NOHUGE_OK, ASAN_OK, test_atomic_imms);
|