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