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
10 #include <rte_memory.h>
11 #include <rte_debug.h>
12 #include <rte_hexdump.h>
13 #include <rte_random.h>
14 #include <rte_byteorder.h>
15 #include <rte_errno.h>
16 #include <rte_bpf.h>
17 #include <rte_ether.h>
18 #include <rte_ip.h>
19
20 #include "test.h"
21
22 /*
23 * Basic functional tests for librte_bpf.
24 * The main procedure - load eBPF program, execute it and
25 * compare restuls with expected values.
26 */
27
28 struct dummy_offset {
29 uint64_t u64;
30 uint32_t u32;
31 uint16_t u16;
32 uint8_t u8;
33 };
34
35 struct dummy_vect8 {
36 struct dummy_offset in[8];
37 struct dummy_offset out[8];
38 };
39
40 struct dummy_net {
41 struct rte_ether_hdr eth_hdr;
42 struct rte_vlan_hdr vlan_hdr;
43 struct rte_ipv4_hdr ip_hdr;
44 };
45
46 #define DUMMY_MBUF_NUM 2
47
48 /* first mbuf in the packet, should always be at offset 0 */
49 struct dummy_mbuf {
50 struct rte_mbuf mb[DUMMY_MBUF_NUM];
51 uint8_t buf[DUMMY_MBUF_NUM][RTE_MBUF_DEFAULT_BUF_SIZE];
52 };
53
54 #define TEST_FILL_1 0xDEADBEEF
55
56 #define TEST_MUL_1 21
57 #define TEST_MUL_2 -100
58
59 #define TEST_SHIFT_1 15
60 #define TEST_SHIFT_2 33
61
62 #define TEST_JCC_1 0
63 #define TEST_JCC_2 -123
64 #define TEST_JCC_3 5678
65 #define TEST_JCC_4 TEST_FILL_1
66
67 #define TEST_IMM_1 UINT64_MAX
68 #define TEST_IMM_2 ((uint64_t)INT64_MIN)
69 #define TEST_IMM_3 ((uint64_t)INT64_MAX + INT32_MAX)
70 #define TEST_IMM_4 ((uint64_t)UINT32_MAX)
71 #define TEST_IMM_5 ((uint64_t)UINT32_MAX + 1)
72
73 #define TEST_MEMFROB 0x2a2a2a2a
74
75 #define STRING_GEEK 0x6B656567
76 #define STRING_WEEK 0x6B656577
77
78 #define TEST_NETMASK 0xffffff00
79 #define TEST_SUBNET 0xaca80200
80
81 uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
82 uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
83
84 uint32_t ip_src_addr = (172U << 24) | (168U << 16) | (2 << 8) | 1;
85 uint32_t ip_dst_addr = (172U << 24) | (168U << 16) | (2 << 8) | 2;
86
87 struct bpf_test {
88 const char *name;
89 size_t arg_sz;
90 struct rte_bpf_prm prm;
91 void (*prepare)(void *);
92 int (*check_result)(uint64_t, const void *);
93 uint32_t allow_fail;
94 };
95
96 /*
97 * Compare return value and result data with expected ones.
98 * Report a failure if they don't match.
99 */
100 static int
cmp_res(const char * func,uint64_t exp_rc,uint64_t ret_rc,const void * exp_res,const void * ret_res,size_t res_sz)101 cmp_res(const char *func, uint64_t exp_rc, uint64_t ret_rc,
102 const void *exp_res, const void *ret_res, size_t res_sz)
103 {
104 int32_t ret;
105
106 ret = 0;
107 if (exp_rc != ret_rc) {
108 printf("%s@%d: invalid return value, expected: 0x%" PRIx64
109 ",result: 0x%" PRIx64 "\n",
110 func, __LINE__, exp_rc, ret_rc);
111 ret |= -1;
112 }
113
114 if (memcmp(exp_res, ret_res, res_sz) != 0) {
115 printf("%s: invalid value\n", func);
116 rte_memdump(stdout, "expected", exp_res, res_sz);
117 rte_memdump(stdout, "result", ret_res, res_sz);
118 ret |= -1;
119 }
120
121 return ret;
122 }
123
124 /* store immediate test-cases */
125 static const struct ebpf_insn test_store1_prog[] = {
126 {
127 .code = (BPF_ST | BPF_MEM | BPF_B),
128 .dst_reg = EBPF_REG_1,
129 .off = offsetof(struct dummy_offset, u8),
130 .imm = TEST_FILL_1,
131 },
132 {
133 .code = (BPF_ST | BPF_MEM | BPF_H),
134 .dst_reg = EBPF_REG_1,
135 .off = offsetof(struct dummy_offset, u16),
136 .imm = TEST_FILL_1,
137 },
138 {
139 .code = (BPF_ST | BPF_MEM | BPF_W),
140 .dst_reg = EBPF_REG_1,
141 .off = offsetof(struct dummy_offset, u32),
142 .imm = TEST_FILL_1,
143 },
144 {
145 .code = (BPF_ST | BPF_MEM | EBPF_DW),
146 .dst_reg = EBPF_REG_1,
147 .off = offsetof(struct dummy_offset, u64),
148 .imm = TEST_FILL_1,
149 },
150 /* return 1 */
151 {
152 .code = (BPF_ALU | EBPF_MOV | BPF_K),
153 .dst_reg = EBPF_REG_0,
154 .imm = 1,
155 },
156 {
157 .code = (BPF_JMP | EBPF_EXIT),
158 },
159 };
160
161 static void
test_store1_prepare(void * arg)162 test_store1_prepare(void *arg)
163 {
164 struct dummy_offset *df;
165
166 df = arg;
167 memset(df, 0, sizeof(*df));
168 }
169
170 static int
test_store1_check(uint64_t rc,const void * arg)171 test_store1_check(uint64_t rc, const void *arg)
172 {
173 const struct dummy_offset *dft;
174 struct dummy_offset dfe;
175
176 dft = arg;
177
178 memset(&dfe, 0, sizeof(dfe));
179 dfe.u64 = (int32_t)TEST_FILL_1;
180 dfe.u32 = dfe.u64;
181 dfe.u16 = dfe.u64;
182 dfe.u8 = dfe.u64;
183
184 return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
185 }
186
187 /* store register test-cases */
188 static const struct ebpf_insn test_store2_prog[] = {
189
190 {
191 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
192 .dst_reg = EBPF_REG_2,
193 .imm = TEST_FILL_1,
194 },
195 {
196 .code = (BPF_STX | BPF_MEM | BPF_B),
197 .dst_reg = EBPF_REG_1,
198 .src_reg = EBPF_REG_2,
199 .off = offsetof(struct dummy_offset, u8),
200 },
201 {
202 .code = (BPF_STX | BPF_MEM | BPF_H),
203 .dst_reg = EBPF_REG_1,
204 .src_reg = EBPF_REG_2,
205 .off = offsetof(struct dummy_offset, u16),
206 },
207 {
208 .code = (BPF_STX | BPF_MEM | BPF_W),
209 .dst_reg = EBPF_REG_1,
210 .src_reg = EBPF_REG_2,
211 .off = offsetof(struct dummy_offset, u32),
212 },
213 {
214 .code = (BPF_STX | BPF_MEM | EBPF_DW),
215 .dst_reg = EBPF_REG_1,
216 .src_reg = EBPF_REG_2,
217 .off = offsetof(struct dummy_offset, u64),
218 },
219 /* return 1 */
220 {
221 .code = (BPF_ALU | EBPF_MOV | BPF_K),
222 .dst_reg = EBPF_REG_0,
223 .imm = 1,
224 },
225 {
226 .code = (BPF_JMP | EBPF_EXIT),
227 },
228 };
229
230 /* load test-cases */
231 static const struct ebpf_insn test_load1_prog[] = {
232
233 {
234 .code = (BPF_LDX | BPF_MEM | BPF_B),
235 .dst_reg = EBPF_REG_2,
236 .src_reg = EBPF_REG_1,
237 .off = offsetof(struct dummy_offset, u8),
238 },
239 {
240 .code = (BPF_LDX | BPF_MEM | BPF_H),
241 .dst_reg = EBPF_REG_3,
242 .src_reg = EBPF_REG_1,
243 .off = offsetof(struct dummy_offset, u16),
244 },
245 {
246 .code = (BPF_LDX | BPF_MEM | BPF_W),
247 .dst_reg = EBPF_REG_4,
248 .src_reg = EBPF_REG_1,
249 .off = offsetof(struct dummy_offset, u32),
250 },
251 {
252 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
253 .dst_reg = EBPF_REG_0,
254 .src_reg = EBPF_REG_1,
255 .off = offsetof(struct dummy_offset, u64),
256 },
257 /* return sum */
258 {
259 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
260 .dst_reg = EBPF_REG_0,
261 .src_reg = EBPF_REG_4,
262 },
263 {
264 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
265 .dst_reg = EBPF_REG_0,
266 .src_reg = EBPF_REG_3,
267 },
268 {
269 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
270 .dst_reg = EBPF_REG_0,
271 .src_reg = EBPF_REG_2,
272 },
273 {
274 .code = (BPF_JMP | EBPF_EXIT),
275 },
276 };
277
278 static void
test_load1_prepare(void * arg)279 test_load1_prepare(void *arg)
280 {
281 struct dummy_offset *df;
282
283 df = arg;
284
285 memset(df, 0, sizeof(*df));
286 df->u64 = (int32_t)TEST_FILL_1;
287 df->u32 = df->u64;
288 df->u16 = df->u64;
289 df->u8 = df->u64;
290 }
291
292 static int
test_load1_check(uint64_t rc,const void * arg)293 test_load1_check(uint64_t rc, const void *arg)
294 {
295 uint64_t v;
296 const struct dummy_offset *dft;
297
298 dft = arg;
299 v = dft->u64;
300 v += dft->u32;
301 v += dft->u16;
302 v += dft->u8;
303
304 return cmp_res(__func__, v, rc, dft, dft, sizeof(*dft));
305 }
306
307 /* load immediate test-cases */
308 static const struct ebpf_insn test_ldimm1_prog[] = {
309
310 {
311 .code = (BPF_LD | BPF_IMM | EBPF_DW),
312 .dst_reg = EBPF_REG_0,
313 .imm = (uint32_t)TEST_IMM_1,
314 },
315 {
316 .imm = TEST_IMM_1 >> 32,
317 },
318 {
319 .code = (BPF_LD | BPF_IMM | EBPF_DW),
320 .dst_reg = EBPF_REG_3,
321 .imm = (uint32_t)TEST_IMM_2,
322 },
323 {
324 .imm = TEST_IMM_2 >> 32,
325 },
326 {
327 .code = (BPF_LD | BPF_IMM | EBPF_DW),
328 .dst_reg = EBPF_REG_5,
329 .imm = (uint32_t)TEST_IMM_3,
330 },
331 {
332 .imm = TEST_IMM_3 >> 32,
333 },
334 {
335 .code = (BPF_LD | BPF_IMM | EBPF_DW),
336 .dst_reg = EBPF_REG_7,
337 .imm = (uint32_t)TEST_IMM_4,
338 },
339 {
340 .imm = TEST_IMM_4 >> 32,
341 },
342 {
343 .code = (BPF_LD | BPF_IMM | EBPF_DW),
344 .dst_reg = EBPF_REG_9,
345 .imm = (uint32_t)TEST_IMM_5,
346 },
347 {
348 .imm = TEST_IMM_5 >> 32,
349 },
350 /* return sum */
351 {
352 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
353 .dst_reg = EBPF_REG_0,
354 .src_reg = EBPF_REG_3,
355 },
356 {
357 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
358 .dst_reg = EBPF_REG_0,
359 .src_reg = EBPF_REG_5,
360 },
361 {
362 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
363 .dst_reg = EBPF_REG_0,
364 .src_reg = EBPF_REG_7,
365 },
366 {
367 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
368 .dst_reg = EBPF_REG_0,
369 .src_reg = EBPF_REG_9,
370 },
371 {
372 .code = (BPF_JMP | EBPF_EXIT),
373 },
374 };
375
376 static int
test_ldimm1_check(uint64_t rc,const void * arg)377 test_ldimm1_check(uint64_t rc, const void *arg)
378 {
379 uint64_t v1, v2;
380
381 v1 = TEST_IMM_1;
382 v2 = TEST_IMM_2;
383 v1 += v2;
384 v2 = TEST_IMM_3;
385 v1 += v2;
386 v2 = TEST_IMM_4;
387 v1 += v2;
388 v2 = TEST_IMM_5;
389 v1 += v2;
390
391 return cmp_res(__func__, v1, rc, arg, arg, 0);
392 }
393
394
395 /* alu mul test-cases */
396 static const struct ebpf_insn test_mul1_prog[] = {
397
398 {
399 .code = (BPF_LDX | BPF_MEM | BPF_W),
400 .dst_reg = EBPF_REG_2,
401 .src_reg = EBPF_REG_1,
402 .off = offsetof(struct dummy_vect8, in[0].u32),
403 },
404 {
405 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
406 .dst_reg = EBPF_REG_3,
407 .src_reg = EBPF_REG_1,
408 .off = offsetof(struct dummy_vect8, in[1].u64),
409 },
410 {
411 .code = (BPF_LDX | BPF_MEM | BPF_W),
412 .dst_reg = EBPF_REG_4,
413 .src_reg = EBPF_REG_1,
414 .off = offsetof(struct dummy_vect8, in[2].u32),
415 },
416 {
417 .code = (BPF_ALU | BPF_MUL | BPF_K),
418 .dst_reg = EBPF_REG_2,
419 .imm = TEST_MUL_1,
420 },
421 {
422 .code = (EBPF_ALU64 | BPF_MUL | BPF_K),
423 .dst_reg = EBPF_REG_3,
424 .imm = TEST_MUL_2,
425 },
426 {
427 .code = (BPF_ALU | BPF_MUL | BPF_X),
428 .dst_reg = EBPF_REG_4,
429 .src_reg = EBPF_REG_2,
430 },
431 {
432 .code = (EBPF_ALU64 | BPF_MUL | BPF_X),
433 .dst_reg = EBPF_REG_4,
434 .src_reg = EBPF_REG_3,
435 },
436 {
437 .code = (BPF_STX | BPF_MEM | EBPF_DW),
438 .dst_reg = EBPF_REG_1,
439 .src_reg = EBPF_REG_2,
440 .off = offsetof(struct dummy_vect8, out[0].u64),
441 },
442 {
443 .code = (BPF_STX | BPF_MEM | EBPF_DW),
444 .dst_reg = EBPF_REG_1,
445 .src_reg = EBPF_REG_3,
446 .off = offsetof(struct dummy_vect8, out[1].u64),
447 },
448 {
449 .code = (BPF_STX | BPF_MEM | EBPF_DW),
450 .dst_reg = EBPF_REG_1,
451 .src_reg = EBPF_REG_4,
452 .off = offsetof(struct dummy_vect8, out[2].u64),
453 },
454 /* return 1 */
455 {
456 .code = (BPF_ALU | EBPF_MOV | BPF_K),
457 .dst_reg = EBPF_REG_0,
458 .imm = 1,
459 },
460 {
461 .code = (BPF_JMP | EBPF_EXIT),
462 },
463 };
464
465 static void
test_mul1_prepare(void * arg)466 test_mul1_prepare(void *arg)
467 {
468 struct dummy_vect8 *dv;
469 uint64_t v;
470
471 dv = arg;
472
473 v = rte_rand();
474
475 memset(dv, 0, sizeof(*dv));
476 dv->in[0].u32 = v;
477 dv->in[1].u64 = v << 12 | v >> 6;
478 dv->in[2].u32 = -v;
479 }
480
481 static int
test_mul1_check(uint64_t rc,const void * arg)482 test_mul1_check(uint64_t rc, const void *arg)
483 {
484 uint64_t r2, r3, r4;
485 const struct dummy_vect8 *dvt;
486 struct dummy_vect8 dve;
487
488 dvt = arg;
489 memset(&dve, 0, sizeof(dve));
490
491 r2 = dvt->in[0].u32;
492 r3 = dvt->in[1].u64;
493 r4 = dvt->in[2].u32;
494
495 r2 = (uint32_t)r2 * TEST_MUL_1;
496 r3 *= TEST_MUL_2;
497 r4 = (uint32_t)(r4 * r2);
498 r4 *= r3;
499
500 dve.out[0].u64 = r2;
501 dve.out[1].u64 = r3;
502 dve.out[2].u64 = r4;
503
504 return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
505 }
506
507 /* alu shift test-cases */
508 static const struct ebpf_insn test_shift1_prog[] = {
509
510 {
511 .code = (BPF_LDX | BPF_MEM | BPF_W),
512 .dst_reg = EBPF_REG_2,
513 .src_reg = EBPF_REG_1,
514 .off = offsetof(struct dummy_vect8, in[0].u32),
515 },
516 {
517 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
518 .dst_reg = EBPF_REG_3,
519 .src_reg = EBPF_REG_1,
520 .off = offsetof(struct dummy_vect8, in[1].u64),
521 },
522 {
523 .code = (BPF_LDX | BPF_MEM | BPF_W),
524 .dst_reg = EBPF_REG_4,
525 .src_reg = EBPF_REG_1,
526 .off = offsetof(struct dummy_vect8, in[2].u32),
527 },
528 {
529 .code = (BPF_ALU | BPF_LSH | BPF_K),
530 .dst_reg = EBPF_REG_2,
531 .imm = TEST_SHIFT_1,
532 },
533 {
534 .code = (EBPF_ALU64 | EBPF_ARSH | BPF_K),
535 .dst_reg = EBPF_REG_3,
536 .imm = TEST_SHIFT_2,
537 },
538 {
539 .code = (BPF_STX | BPF_MEM | EBPF_DW),
540 .dst_reg = EBPF_REG_1,
541 .src_reg = EBPF_REG_2,
542 .off = offsetof(struct dummy_vect8, out[0].u64),
543 },
544 {
545 .code = (BPF_STX | BPF_MEM | EBPF_DW),
546 .dst_reg = EBPF_REG_1,
547 .src_reg = EBPF_REG_3,
548 .off = offsetof(struct dummy_vect8, out[1].u64),
549 },
550 {
551 .code = (BPF_ALU | BPF_RSH | BPF_X),
552 .dst_reg = EBPF_REG_2,
553 .src_reg = EBPF_REG_4,
554 },
555 {
556 .code = (EBPF_ALU64 | BPF_LSH | BPF_X),
557 .dst_reg = EBPF_REG_3,
558 .src_reg = EBPF_REG_4,
559 },
560 {
561 .code = (BPF_STX | BPF_MEM | EBPF_DW),
562 .dst_reg = EBPF_REG_1,
563 .src_reg = EBPF_REG_2,
564 .off = offsetof(struct dummy_vect8, out[2].u64),
565 },
566 {
567 .code = (BPF_STX | BPF_MEM | EBPF_DW),
568 .dst_reg = EBPF_REG_1,
569 .src_reg = EBPF_REG_3,
570 .off = offsetof(struct dummy_vect8, out[3].u64),
571 },
572 {
573 .code = (BPF_LDX | BPF_MEM | BPF_W),
574 .dst_reg = EBPF_REG_2,
575 .src_reg = EBPF_REG_1,
576 .off = offsetof(struct dummy_vect8, in[0].u32),
577 },
578 {
579 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
580 .dst_reg = EBPF_REG_3,
581 .src_reg = EBPF_REG_1,
582 .off = offsetof(struct dummy_vect8, in[1].u64),
583 },
584 {
585 .code = (BPF_LDX | BPF_MEM | BPF_W),
586 .dst_reg = EBPF_REG_4,
587 .src_reg = EBPF_REG_1,
588 .off = offsetof(struct dummy_vect8, in[2].u32),
589 },
590 {
591 .code = (BPF_ALU | BPF_AND | BPF_K),
592 .dst_reg = EBPF_REG_2,
593 .imm = sizeof(uint64_t) * CHAR_BIT - 1,
594 },
595 {
596 .code = (EBPF_ALU64 | EBPF_ARSH | BPF_X),
597 .dst_reg = EBPF_REG_3,
598 .src_reg = EBPF_REG_2,
599 },
600 {
601 .code = (BPF_ALU | BPF_AND | BPF_K),
602 .dst_reg = EBPF_REG_2,
603 .imm = sizeof(uint32_t) * CHAR_BIT - 1,
604 },
605 {
606 .code = (BPF_ALU | BPF_LSH | BPF_X),
607 .dst_reg = EBPF_REG_4,
608 .src_reg = EBPF_REG_2,
609 },
610 {
611 .code = (BPF_STX | BPF_MEM | EBPF_DW),
612 .dst_reg = EBPF_REG_1,
613 .src_reg = EBPF_REG_4,
614 .off = offsetof(struct dummy_vect8, out[4].u64),
615 },
616 {
617 .code = (BPF_STX | BPF_MEM | EBPF_DW),
618 .dst_reg = EBPF_REG_1,
619 .src_reg = EBPF_REG_3,
620 .off = offsetof(struct dummy_vect8, out[5].u64),
621 },
622 /* return 1 */
623 {
624 .code = (BPF_ALU | EBPF_MOV | BPF_K),
625 .dst_reg = EBPF_REG_0,
626 .imm = 1,
627 },
628 {
629 .code = (BPF_JMP | EBPF_EXIT),
630 },
631 };
632
633 static void
test_shift1_prepare(void * arg)634 test_shift1_prepare(void *arg)
635 {
636 struct dummy_vect8 *dv;
637 uint64_t v;
638
639 dv = arg;
640
641 v = rte_rand();
642
643 memset(dv, 0, sizeof(*dv));
644 dv->in[0].u32 = v;
645 dv->in[1].u64 = v << 12 | v >> 6;
646 dv->in[2].u32 = (-v ^ 5);
647 }
648
649 static int
test_shift1_check(uint64_t rc,const void * arg)650 test_shift1_check(uint64_t rc, const void *arg)
651 {
652 uint64_t r2, r3, r4;
653 const struct dummy_vect8 *dvt;
654 struct dummy_vect8 dve;
655
656 dvt = arg;
657 memset(&dve, 0, sizeof(dve));
658
659 r2 = dvt->in[0].u32;
660 r3 = dvt->in[1].u64;
661 r4 = dvt->in[2].u32;
662
663 r2 = (uint32_t)r2 << TEST_SHIFT_1;
664 r3 = (int64_t)r3 >> TEST_SHIFT_2;
665
666 dve.out[0].u64 = r2;
667 dve.out[1].u64 = r3;
668
669 r2 = (uint32_t)r2 >> r4;
670 r3 <<= r4;
671
672 dve.out[2].u64 = r2;
673 dve.out[3].u64 = r3;
674
675 r2 = dvt->in[0].u32;
676 r3 = dvt->in[1].u64;
677 r4 = dvt->in[2].u32;
678
679 r2 &= sizeof(uint64_t) * CHAR_BIT - 1;
680 r3 = (int64_t)r3 >> r2;
681 r2 &= sizeof(uint32_t) * CHAR_BIT - 1;
682 r4 = (uint32_t)r4 << r2;
683
684 dve.out[4].u64 = r4;
685 dve.out[5].u64 = r3;
686
687 return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
688 }
689
690 /* jmp test-cases */
691 static const struct ebpf_insn test_jump1_prog[] = {
692
693 [0] = {
694 .code = (BPF_ALU | EBPF_MOV | BPF_K),
695 .dst_reg = EBPF_REG_0,
696 .imm = 0,
697 },
698 [1] = {
699 .code = (BPF_LDX | BPF_MEM | BPF_W),
700 .dst_reg = EBPF_REG_2,
701 .src_reg = EBPF_REG_1,
702 .off = offsetof(struct dummy_vect8, in[0].u32),
703 },
704 [2] = {
705 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
706 .dst_reg = EBPF_REG_3,
707 .src_reg = EBPF_REG_1,
708 .off = offsetof(struct dummy_vect8, in[0].u64),
709 },
710 [3] = {
711 .code = (BPF_LDX | BPF_MEM | BPF_W),
712 .dst_reg = EBPF_REG_4,
713 .src_reg = EBPF_REG_1,
714 .off = offsetof(struct dummy_vect8, in[1].u32),
715 },
716 [4] = {
717 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
718 .dst_reg = EBPF_REG_5,
719 .src_reg = EBPF_REG_1,
720 .off = offsetof(struct dummy_vect8, in[1].u64),
721 },
722 [5] = {
723 .code = (BPF_JMP | BPF_JEQ | BPF_K),
724 .dst_reg = EBPF_REG_2,
725 .imm = TEST_JCC_1,
726 .off = 8,
727 },
728 [6] = {
729 .code = (BPF_JMP | EBPF_JSLE | BPF_K),
730 .dst_reg = EBPF_REG_3,
731 .imm = TEST_JCC_2,
732 .off = 9,
733 },
734 [7] = {
735 .code = (BPF_JMP | BPF_JGT | BPF_K),
736 .dst_reg = EBPF_REG_4,
737 .imm = TEST_JCC_3,
738 .off = 10,
739 },
740 [8] = {
741 .code = (BPF_JMP | BPF_JSET | BPF_K),
742 .dst_reg = EBPF_REG_5,
743 .imm = TEST_JCC_4,
744 .off = 11,
745 },
746 [9] = {
747 .code = (BPF_JMP | EBPF_JNE | BPF_X),
748 .dst_reg = EBPF_REG_2,
749 .src_reg = EBPF_REG_3,
750 .off = 12,
751 },
752 [10] = {
753 .code = (BPF_JMP | EBPF_JSGT | BPF_X),
754 .dst_reg = EBPF_REG_2,
755 .src_reg = EBPF_REG_4,
756 .off = 13,
757 },
758 [11] = {
759 .code = (BPF_JMP | EBPF_JLE | BPF_X),
760 .dst_reg = EBPF_REG_2,
761 .src_reg = EBPF_REG_5,
762 .off = 14,
763 },
764 [12] = {
765 .code = (BPF_JMP | BPF_JSET | BPF_X),
766 .dst_reg = EBPF_REG_3,
767 .src_reg = EBPF_REG_5,
768 .off = 15,
769 },
770 [13] = {
771 .code = (BPF_JMP | EBPF_EXIT),
772 },
773 [14] = {
774 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
775 .dst_reg = EBPF_REG_0,
776 .imm = 0x1,
777 },
778 [15] = {
779 .code = (BPF_JMP | BPF_JA),
780 .off = -10,
781 },
782 [16] = {
783 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
784 .dst_reg = EBPF_REG_0,
785 .imm = 0x2,
786 },
787 [17] = {
788 .code = (BPF_JMP | BPF_JA),
789 .off = -11,
790 },
791 [18] = {
792 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
793 .dst_reg = EBPF_REG_0,
794 .imm = 0x4,
795 },
796 [19] = {
797 .code = (BPF_JMP | BPF_JA),
798 .off = -12,
799 },
800 [20] = {
801 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
802 .dst_reg = EBPF_REG_0,
803 .imm = 0x8,
804 },
805 [21] = {
806 .code = (BPF_JMP | BPF_JA),
807 .off = -13,
808 },
809 [22] = {
810 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
811 .dst_reg = EBPF_REG_0,
812 .imm = 0x10,
813 },
814 [23] = {
815 .code = (BPF_JMP | BPF_JA),
816 .off = -14,
817 },
818 [24] = {
819 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
820 .dst_reg = EBPF_REG_0,
821 .imm = 0x20,
822 },
823 [25] = {
824 .code = (BPF_JMP | BPF_JA),
825 .off = -15,
826 },
827 [26] = {
828 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
829 .dst_reg = EBPF_REG_0,
830 .imm = 0x40,
831 },
832 [27] = {
833 .code = (BPF_JMP | BPF_JA),
834 .off = -16,
835 },
836 [28] = {
837 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
838 .dst_reg = EBPF_REG_0,
839 .imm = 0x80,
840 },
841 [29] = {
842 .code = (BPF_JMP | BPF_JA),
843 .off = -17,
844 },
845 };
846
847 static void
test_jump1_prepare(void * arg)848 test_jump1_prepare(void *arg)
849 {
850 struct dummy_vect8 *dv;
851 uint64_t v1, v2;
852
853 dv = arg;
854
855 v1 = rte_rand();
856 v2 = rte_rand();
857
858 memset(dv, 0, sizeof(*dv));
859 dv->in[0].u64 = v1;
860 dv->in[1].u64 = v2;
861 dv->in[0].u32 = (v1 << 12) + (v2 >> 6);
862 dv->in[1].u32 = (v2 << 12) - (v1 >> 6);
863 }
864
865 static int
test_jump1_check(uint64_t rc,const void * arg)866 test_jump1_check(uint64_t rc, const void *arg)
867 {
868 uint64_t r2, r3, r4, r5, rv;
869 const struct dummy_vect8 *dvt;
870
871 dvt = arg;
872
873 rv = 0;
874 r2 = dvt->in[0].u32;
875 r3 = dvt->in[0].u64;
876 r4 = dvt->in[1].u32;
877 r5 = dvt->in[1].u64;
878
879 if (r2 == TEST_JCC_1)
880 rv |= 0x1;
881 if ((int64_t)r3 <= TEST_JCC_2)
882 rv |= 0x2;
883 if (r4 > TEST_JCC_3)
884 rv |= 0x4;
885 if (r5 & TEST_JCC_4)
886 rv |= 0x8;
887 if (r2 != r3)
888 rv |= 0x10;
889 if ((int64_t)r2 > (int64_t)r4)
890 rv |= 0x20;
891 if (r2 <= r5)
892 rv |= 0x40;
893 if (r3 & r5)
894 rv |= 0x80;
895
896 return cmp_res(__func__, rv, rc, &rv, &rc, sizeof(rv));
897 }
898
899 /* Jump test case - check ip4_dest in particular subnet */
900 static const struct ebpf_insn test_jump2_prog[] = {
901
902 [0] = {
903 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
904 .dst_reg = EBPF_REG_2,
905 .imm = 0xe,
906 },
907 [1] = {
908 .code = (BPF_LDX | BPF_MEM | BPF_H),
909 .dst_reg = EBPF_REG_3,
910 .src_reg = EBPF_REG_1,
911 .off = 12,
912 },
913 [2] = {
914 .code = (BPF_JMP | EBPF_JNE | BPF_K),
915 .dst_reg = EBPF_REG_3,
916 .off = 2,
917 .imm = 0x81,
918 },
919 [3] = {
920 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
921 .dst_reg = EBPF_REG_2,
922 .imm = 0x12,
923 },
924 [4] = {
925 .code = (BPF_LDX | BPF_MEM | BPF_H),
926 .dst_reg = EBPF_REG_3,
927 .src_reg = EBPF_REG_1,
928 .off = 16,
929 },
930 [5] = {
931 .code = (EBPF_ALU64 | BPF_AND | BPF_K),
932 .dst_reg = EBPF_REG_3,
933 .imm = 0xffff,
934 },
935 [6] = {
936 .code = (BPF_JMP | EBPF_JNE | BPF_K),
937 .dst_reg = EBPF_REG_3,
938 .off = 9,
939 .imm = 0x8,
940 },
941 [7] = {
942 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
943 .dst_reg = EBPF_REG_1,
944 .src_reg = EBPF_REG_2,
945 },
946 [8] = {
947 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
948 .dst_reg = EBPF_REG_0,
949 .imm = 0,
950 },
951 [9] = {
952 .code = (BPF_LDX | BPF_MEM | BPF_W),
953 .dst_reg = EBPF_REG_1,
954 .src_reg = EBPF_REG_1,
955 .off = 16,
956 },
957 [10] = {
958 .code = (BPF_ALU | EBPF_MOV | BPF_K),
959 .dst_reg = EBPF_REG_3,
960 .imm = TEST_NETMASK,
961 },
962 [11] = {
963 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
964 .dst_reg = EBPF_REG_3,
965 .imm = sizeof(uint32_t) * CHAR_BIT,
966 },
967 [12] = {
968 .code = (BPF_ALU | BPF_AND | BPF_X),
969 .dst_reg = EBPF_REG_1,
970 .src_reg = EBPF_REG_3,
971 },
972 [13] = {
973 .code = (BPF_ALU | EBPF_MOV | BPF_K),
974 .dst_reg = EBPF_REG_3,
975 .imm = TEST_SUBNET,
976 },
977 [14] = {
978 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
979 .dst_reg = EBPF_REG_3,
980 .imm = sizeof(uint32_t) * CHAR_BIT,
981 },
982 [15] = {
983 .code = (BPF_JMP | BPF_JEQ | BPF_X),
984 .dst_reg = EBPF_REG_1,
985 .src_reg = EBPF_REG_3,
986 .off = 1,
987 },
988 [16] = {
989 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
990 .dst_reg = EBPF_REG_0,
991 .imm = -1,
992 },
993 [17] = {
994 .code = (BPF_JMP | EBPF_EXIT),
995 },
996 };
997
998 /* Preparing a vlan packet */
999 static void
test_jump2_prepare(void * arg)1000 test_jump2_prepare(void *arg)
1001 {
1002 struct dummy_net *dn;
1003
1004 dn = arg;
1005 memset(dn, 0, sizeof(*dn));
1006
1007 /*
1008 * Initialize ether header.
1009 */
1010 rte_ether_addr_copy((struct rte_ether_addr *)dst_mac,
1011 &dn->eth_hdr.d_addr);
1012 rte_ether_addr_copy((struct rte_ether_addr *)src_mac,
1013 &dn->eth_hdr.s_addr);
1014 dn->eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
1015
1016 /*
1017 * Initialize vlan header.
1018 */
1019 dn->vlan_hdr.eth_proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
1020 dn->vlan_hdr.vlan_tci = 32;
1021
1022 /*
1023 * Initialize IP header.
1024 */
1025 dn->ip_hdr.version_ihl = 0x45; /*IP_VERSION | IP_HDRLEN*/
1026 dn->ip_hdr.time_to_live = 64; /* IP_DEFTTL */
1027 dn->ip_hdr.next_proto_id = IPPROTO_TCP;
1028 dn->ip_hdr.packet_id = rte_cpu_to_be_16(0x463c);
1029 dn->ip_hdr.total_length = rte_cpu_to_be_16(60);
1030 dn->ip_hdr.src_addr = rte_cpu_to_be_32(ip_src_addr);
1031 dn->ip_hdr.dst_addr = rte_cpu_to_be_32(ip_dst_addr);
1032 }
1033
1034 static int
test_jump2_check(uint64_t rc,const void * arg)1035 test_jump2_check(uint64_t rc, const void *arg)
1036 {
1037 const struct rte_ether_hdr *eth_hdr = arg;
1038 const struct rte_ipv4_hdr *ipv4_hdr;
1039 const void *next = eth_hdr;
1040 uint16_t eth_type;
1041 uint64_t v = -1;
1042
1043 if (eth_hdr->ether_type == htons(0x8100)) {
1044 const struct rte_vlan_hdr *vlan_hdr =
1045 (const void *)(eth_hdr + 1);
1046 eth_type = vlan_hdr->eth_proto;
1047 next = vlan_hdr + 1;
1048 } else {
1049 eth_type = eth_hdr->ether_type;
1050 next = eth_hdr + 1;
1051 }
1052
1053 if (eth_type == htons(0x0800)) {
1054 ipv4_hdr = next;
1055 if ((ipv4_hdr->dst_addr & rte_cpu_to_be_32(TEST_NETMASK)) ==
1056 rte_cpu_to_be_32(TEST_SUBNET)) {
1057 v = 0;
1058 }
1059 }
1060
1061 return cmp_res(__func__, v, rc, arg, arg, sizeof(arg));
1062 }
1063
1064 /* alu (add, sub, and, or, xor, neg) test-cases */
1065 static const struct ebpf_insn test_alu1_prog[] = {
1066
1067 {
1068 .code = (BPF_LDX | BPF_MEM | BPF_W),
1069 .dst_reg = EBPF_REG_2,
1070 .src_reg = EBPF_REG_1,
1071 .off = offsetof(struct dummy_vect8, in[0].u32),
1072 },
1073 {
1074 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1075 .dst_reg = EBPF_REG_3,
1076 .src_reg = EBPF_REG_1,
1077 .off = offsetof(struct dummy_vect8, in[0].u64),
1078 },
1079 {
1080 .code = (BPF_LDX | BPF_MEM | BPF_W),
1081 .dst_reg = EBPF_REG_4,
1082 .src_reg = EBPF_REG_1,
1083 .off = offsetof(struct dummy_vect8, in[1].u32),
1084 },
1085 {
1086 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1087 .dst_reg = EBPF_REG_5,
1088 .src_reg = EBPF_REG_1,
1089 .off = offsetof(struct dummy_vect8, in[1].u64),
1090 },
1091 {
1092 .code = (BPF_ALU | BPF_AND | BPF_K),
1093 .dst_reg = EBPF_REG_2,
1094 .imm = TEST_FILL_1,
1095 },
1096 {
1097 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1098 .dst_reg = EBPF_REG_3,
1099 .imm = TEST_FILL_1,
1100 },
1101 {
1102 .code = (BPF_ALU | BPF_XOR | BPF_K),
1103 .dst_reg = EBPF_REG_4,
1104 .imm = TEST_FILL_1,
1105 },
1106 {
1107 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1108 .dst_reg = EBPF_REG_5,
1109 .imm = TEST_FILL_1,
1110 },
1111 {
1112 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1113 .dst_reg = EBPF_REG_1,
1114 .src_reg = EBPF_REG_2,
1115 .off = offsetof(struct dummy_vect8, out[0].u64),
1116 },
1117 {
1118 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1119 .dst_reg = EBPF_REG_1,
1120 .src_reg = EBPF_REG_3,
1121 .off = offsetof(struct dummy_vect8, out[1].u64),
1122 },
1123 {
1124 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1125 .dst_reg = EBPF_REG_1,
1126 .src_reg = EBPF_REG_4,
1127 .off = offsetof(struct dummy_vect8, out[2].u64),
1128 },
1129 {
1130 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1131 .dst_reg = EBPF_REG_1,
1132 .src_reg = EBPF_REG_5,
1133 .off = offsetof(struct dummy_vect8, out[3].u64),
1134 },
1135 {
1136 .code = (BPF_ALU | BPF_OR | BPF_X),
1137 .dst_reg = EBPF_REG_2,
1138 .src_reg = EBPF_REG_3,
1139 },
1140 {
1141 .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
1142 .dst_reg = EBPF_REG_3,
1143 .src_reg = EBPF_REG_4,
1144 },
1145 {
1146 .code = (BPF_ALU | BPF_SUB | BPF_X),
1147 .dst_reg = EBPF_REG_4,
1148 .src_reg = EBPF_REG_5,
1149 },
1150 {
1151 .code = (EBPF_ALU64 | BPF_AND | BPF_X),
1152 .dst_reg = EBPF_REG_5,
1153 .src_reg = EBPF_REG_2,
1154 },
1155 {
1156 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1157 .dst_reg = EBPF_REG_1,
1158 .src_reg = EBPF_REG_2,
1159 .off = offsetof(struct dummy_vect8, out[4].u64),
1160 },
1161 {
1162 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1163 .dst_reg = EBPF_REG_1,
1164 .src_reg = EBPF_REG_3,
1165 .off = offsetof(struct dummy_vect8, out[5].u64),
1166 },
1167 {
1168 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1169 .dst_reg = EBPF_REG_1,
1170 .src_reg = EBPF_REG_4,
1171 .off = offsetof(struct dummy_vect8, out[6].u64),
1172 },
1173 {
1174 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1175 .dst_reg = EBPF_REG_1,
1176 .src_reg = EBPF_REG_5,
1177 .off = offsetof(struct dummy_vect8, out[7].u64),
1178 },
1179 /* return (-r2 + (-r3)) */
1180 {
1181 .code = (BPF_ALU | BPF_NEG),
1182 .dst_reg = EBPF_REG_2,
1183 },
1184 {
1185 .code = (EBPF_ALU64 | BPF_NEG),
1186 .dst_reg = EBPF_REG_3,
1187 },
1188 {
1189 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1190 .dst_reg = EBPF_REG_2,
1191 .src_reg = EBPF_REG_3,
1192 },
1193 {
1194 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1195 .dst_reg = EBPF_REG_0,
1196 .src_reg = EBPF_REG_2,
1197 },
1198 {
1199 .code = (BPF_JMP | EBPF_EXIT),
1200 },
1201 };
1202
1203 static int
test_alu1_check(uint64_t rc,const void * arg)1204 test_alu1_check(uint64_t rc, const void *arg)
1205 {
1206 uint64_t r2, r3, r4, r5, rv;
1207 const struct dummy_vect8 *dvt;
1208 struct dummy_vect8 dve;
1209
1210 dvt = arg;
1211 memset(&dve, 0, sizeof(dve));
1212
1213 r2 = dvt->in[0].u32;
1214 r3 = dvt->in[0].u64;
1215 r4 = dvt->in[1].u32;
1216 r5 = dvt->in[1].u64;
1217
1218 r2 = (uint32_t)r2 & TEST_FILL_1;
1219 r3 |= (int32_t) TEST_FILL_1;
1220 r4 = (uint32_t)r4 ^ TEST_FILL_1;
1221 r5 += (int32_t)TEST_FILL_1;
1222
1223 dve.out[0].u64 = r2;
1224 dve.out[1].u64 = r3;
1225 dve.out[2].u64 = r4;
1226 dve.out[3].u64 = r5;
1227
1228 r2 = (uint32_t)r2 | (uint32_t)r3;
1229 r3 ^= r4;
1230 r4 = (uint32_t)r4 - (uint32_t)r5;
1231 r5 &= r2;
1232
1233 dve.out[4].u64 = r2;
1234 dve.out[5].u64 = r3;
1235 dve.out[6].u64 = r4;
1236 dve.out[7].u64 = r5;
1237
1238 r2 = -(int32_t)r2;
1239 rv = (uint32_t)r2;
1240 r3 = -r3;
1241 rv += r3;
1242
1243 return cmp_res(__func__, rv, rc, dve.out, dvt->out, sizeof(dve.out));
1244 }
1245
1246 /* endianness conversions (BE->LE/LE->BE) test-cases */
1247 static const struct ebpf_insn test_bele1_prog[] = {
1248
1249 {
1250 .code = (BPF_LDX | BPF_MEM | BPF_H),
1251 .dst_reg = EBPF_REG_2,
1252 .src_reg = EBPF_REG_1,
1253 .off = offsetof(struct dummy_vect8, in[0].u16),
1254 },
1255 {
1256 .code = (BPF_LDX | BPF_MEM | BPF_W),
1257 .dst_reg = EBPF_REG_3,
1258 .src_reg = EBPF_REG_1,
1259 .off = offsetof(struct dummy_vect8, in[0].u32),
1260 },
1261 {
1262 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1263 .dst_reg = EBPF_REG_4,
1264 .src_reg = EBPF_REG_1,
1265 .off = offsetof(struct dummy_vect8, in[0].u64),
1266 },
1267 {
1268 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1269 .dst_reg = EBPF_REG_2,
1270 .imm = sizeof(uint16_t) * CHAR_BIT,
1271 },
1272 {
1273 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1274 .dst_reg = EBPF_REG_3,
1275 .imm = sizeof(uint32_t) * CHAR_BIT,
1276 },
1277 {
1278 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1279 .dst_reg = EBPF_REG_4,
1280 .imm = sizeof(uint64_t) * CHAR_BIT,
1281 },
1282 {
1283 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1284 .dst_reg = EBPF_REG_1,
1285 .src_reg = EBPF_REG_2,
1286 .off = offsetof(struct dummy_vect8, out[0].u64),
1287 },
1288 {
1289 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1290 .dst_reg = EBPF_REG_1,
1291 .src_reg = EBPF_REG_3,
1292 .off = offsetof(struct dummy_vect8, out[1].u64),
1293 },
1294 {
1295 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1296 .dst_reg = EBPF_REG_1,
1297 .src_reg = EBPF_REG_4,
1298 .off = offsetof(struct dummy_vect8, out[2].u64),
1299 },
1300 {
1301 .code = (BPF_LDX | BPF_MEM | BPF_H),
1302 .dst_reg = EBPF_REG_2,
1303 .src_reg = EBPF_REG_1,
1304 .off = offsetof(struct dummy_vect8, in[0].u16),
1305 },
1306 {
1307 .code = (BPF_LDX | BPF_MEM | BPF_W),
1308 .dst_reg = EBPF_REG_3,
1309 .src_reg = EBPF_REG_1,
1310 .off = offsetof(struct dummy_vect8, in[0].u32),
1311 },
1312 {
1313 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1314 .dst_reg = EBPF_REG_4,
1315 .src_reg = EBPF_REG_1,
1316 .off = offsetof(struct dummy_vect8, in[0].u64),
1317 },
1318 {
1319 .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1320 .dst_reg = EBPF_REG_2,
1321 .imm = sizeof(uint16_t) * CHAR_BIT,
1322 },
1323 {
1324 .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1325 .dst_reg = EBPF_REG_3,
1326 .imm = sizeof(uint32_t) * CHAR_BIT,
1327 },
1328 {
1329 .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1330 .dst_reg = EBPF_REG_4,
1331 .imm = sizeof(uint64_t) * CHAR_BIT,
1332 },
1333 {
1334 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1335 .dst_reg = EBPF_REG_1,
1336 .src_reg = EBPF_REG_2,
1337 .off = offsetof(struct dummy_vect8, out[3].u64),
1338 },
1339 {
1340 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1341 .dst_reg = EBPF_REG_1,
1342 .src_reg = EBPF_REG_3,
1343 .off = offsetof(struct dummy_vect8, out[4].u64),
1344 },
1345 {
1346 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1347 .dst_reg = EBPF_REG_1,
1348 .src_reg = EBPF_REG_4,
1349 .off = offsetof(struct dummy_vect8, out[5].u64),
1350 },
1351 /* return 1 */
1352 {
1353 .code = (BPF_ALU | EBPF_MOV | BPF_K),
1354 .dst_reg = EBPF_REG_0,
1355 .imm = 1,
1356 },
1357 {
1358 .code = (BPF_JMP | EBPF_EXIT),
1359 },
1360 };
1361
1362 static void
test_bele1_prepare(void * arg)1363 test_bele1_prepare(void *arg)
1364 {
1365 struct dummy_vect8 *dv;
1366
1367 dv = arg;
1368
1369 memset(dv, 0, sizeof(*dv));
1370 dv->in[0].u64 = rte_rand();
1371 dv->in[0].u32 = dv->in[0].u64;
1372 dv->in[0].u16 = dv->in[0].u64;
1373 }
1374
1375 static int
test_bele1_check(uint64_t rc,const void * arg)1376 test_bele1_check(uint64_t rc, const void *arg)
1377 {
1378 uint64_t r2, r3, r4;
1379 const struct dummy_vect8 *dvt;
1380 struct dummy_vect8 dve;
1381
1382 dvt = arg;
1383 memset(&dve, 0, sizeof(dve));
1384
1385 r2 = dvt->in[0].u16;
1386 r3 = dvt->in[0].u32;
1387 r4 = dvt->in[0].u64;
1388
1389 r2 = rte_cpu_to_be_16(r2);
1390 r3 = rte_cpu_to_be_32(r3);
1391 r4 = rte_cpu_to_be_64(r4);
1392
1393 dve.out[0].u64 = r2;
1394 dve.out[1].u64 = r3;
1395 dve.out[2].u64 = r4;
1396
1397 r2 = dvt->in[0].u16;
1398 r3 = dvt->in[0].u32;
1399 r4 = dvt->in[0].u64;
1400
1401 r2 = rte_cpu_to_le_16(r2);
1402 r3 = rte_cpu_to_le_32(r3);
1403 r4 = rte_cpu_to_le_64(r4);
1404
1405 dve.out[3].u64 = r2;
1406 dve.out[4].u64 = r3;
1407 dve.out[5].u64 = r4;
1408
1409 return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
1410 }
1411
1412 /* atomic add test-cases */
1413 static const struct ebpf_insn test_xadd1_prog[] = {
1414
1415 {
1416 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1417 .dst_reg = EBPF_REG_2,
1418 .imm = 1,
1419 },
1420 {
1421 .code = (BPF_STX | EBPF_XADD | BPF_W),
1422 .dst_reg = EBPF_REG_1,
1423 .src_reg = EBPF_REG_2,
1424 .off = offsetof(struct dummy_offset, u32),
1425 },
1426 {
1427 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1428 .dst_reg = EBPF_REG_1,
1429 .src_reg = EBPF_REG_2,
1430 .off = offsetof(struct dummy_offset, u64),
1431 },
1432 {
1433 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1434 .dst_reg = EBPF_REG_3,
1435 .imm = -1,
1436 },
1437 {
1438 .code = (BPF_STX | EBPF_XADD | BPF_W),
1439 .dst_reg = EBPF_REG_1,
1440 .src_reg = EBPF_REG_3,
1441 .off = offsetof(struct dummy_offset, u32),
1442 },
1443 {
1444 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1445 .dst_reg = EBPF_REG_1,
1446 .src_reg = EBPF_REG_3,
1447 .off = offsetof(struct dummy_offset, u64),
1448 },
1449 {
1450 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1451 .dst_reg = EBPF_REG_4,
1452 .imm = TEST_FILL_1,
1453 },
1454 {
1455 .code = (BPF_STX | EBPF_XADD | BPF_W),
1456 .dst_reg = EBPF_REG_1,
1457 .src_reg = EBPF_REG_4,
1458 .off = offsetof(struct dummy_offset, u32),
1459 },
1460 {
1461 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1462 .dst_reg = EBPF_REG_1,
1463 .src_reg = EBPF_REG_4,
1464 .off = offsetof(struct dummy_offset, u64),
1465 },
1466 {
1467 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1468 .dst_reg = EBPF_REG_5,
1469 .imm = TEST_MUL_1,
1470 },
1471 {
1472 .code = (BPF_STX | EBPF_XADD | BPF_W),
1473 .dst_reg = EBPF_REG_1,
1474 .src_reg = EBPF_REG_5,
1475 .off = offsetof(struct dummy_offset, u32),
1476 },
1477 {
1478 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1479 .dst_reg = EBPF_REG_1,
1480 .src_reg = EBPF_REG_5,
1481 .off = offsetof(struct dummy_offset, u64),
1482 },
1483 {
1484 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1485 .dst_reg = EBPF_REG_6,
1486 .imm = TEST_MUL_2,
1487 },
1488 {
1489 .code = (BPF_STX | EBPF_XADD | BPF_W),
1490 .dst_reg = EBPF_REG_1,
1491 .src_reg = EBPF_REG_6,
1492 .off = offsetof(struct dummy_offset, u32),
1493 },
1494 {
1495 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1496 .dst_reg = EBPF_REG_1,
1497 .src_reg = EBPF_REG_6,
1498 .off = offsetof(struct dummy_offset, u64),
1499 },
1500 {
1501 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1502 .dst_reg = EBPF_REG_7,
1503 .imm = TEST_JCC_2,
1504 },
1505 {
1506 .code = (BPF_STX | EBPF_XADD | BPF_W),
1507 .dst_reg = EBPF_REG_1,
1508 .src_reg = EBPF_REG_7,
1509 .off = offsetof(struct dummy_offset, u32),
1510 },
1511 {
1512 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1513 .dst_reg = EBPF_REG_1,
1514 .src_reg = EBPF_REG_7,
1515 .off = offsetof(struct dummy_offset, u64),
1516 },
1517 {
1518 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1519 .dst_reg = EBPF_REG_8,
1520 .imm = TEST_JCC_3,
1521 },
1522 {
1523 .code = (BPF_STX | EBPF_XADD | BPF_W),
1524 .dst_reg = EBPF_REG_1,
1525 .src_reg = EBPF_REG_8,
1526 .off = offsetof(struct dummy_offset, u32),
1527 },
1528 {
1529 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1530 .dst_reg = EBPF_REG_1,
1531 .src_reg = EBPF_REG_8,
1532 .off = offsetof(struct dummy_offset, u64),
1533 },
1534 /* return 1 */
1535 {
1536 .code = (BPF_ALU | EBPF_MOV | BPF_K),
1537 .dst_reg = EBPF_REG_0,
1538 .imm = 1,
1539 },
1540 {
1541 .code = (BPF_JMP | EBPF_EXIT),
1542 },
1543 };
1544
1545 static int
test_xadd1_check(uint64_t rc,const void * arg)1546 test_xadd1_check(uint64_t rc, const void *arg)
1547 {
1548 uint64_t rv;
1549 const struct dummy_offset *dft;
1550 struct dummy_offset dfe;
1551
1552 dft = arg;
1553 memset(&dfe, 0, sizeof(dfe));
1554
1555 rv = 1;
1556 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1557 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1558
1559 rv = -1;
1560 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1561 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1562
1563 rv = (int32_t)TEST_FILL_1;
1564 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1565 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1566
1567 rv = TEST_MUL_1;
1568 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1569 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1570
1571 rv = TEST_MUL_2;
1572 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1573 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1574
1575 rv = TEST_JCC_2;
1576 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1577 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1578
1579 rv = TEST_JCC_3;
1580 rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1581 rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1582
1583 return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
1584 }
1585
1586 /* alu div test-cases */
1587 static const struct ebpf_insn test_div1_prog[] = {
1588
1589 {
1590 .code = (BPF_LDX | BPF_MEM | BPF_W),
1591 .dst_reg = EBPF_REG_2,
1592 .src_reg = EBPF_REG_1,
1593 .off = offsetof(struct dummy_vect8, in[0].u32),
1594 },
1595 {
1596 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1597 .dst_reg = EBPF_REG_3,
1598 .src_reg = EBPF_REG_1,
1599 .off = offsetof(struct dummy_vect8, in[1].u64),
1600 },
1601 {
1602 .code = (BPF_LDX | BPF_MEM | BPF_W),
1603 .dst_reg = EBPF_REG_4,
1604 .src_reg = EBPF_REG_1,
1605 .off = offsetof(struct dummy_vect8, in[2].u32),
1606 },
1607 {
1608 .code = (BPF_ALU | BPF_DIV | BPF_K),
1609 .dst_reg = EBPF_REG_2,
1610 .imm = TEST_MUL_1,
1611 },
1612 {
1613 .code = (EBPF_ALU64 | BPF_MOD | BPF_K),
1614 .dst_reg = EBPF_REG_3,
1615 .imm = TEST_MUL_2,
1616 },
1617 {
1618 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1619 .dst_reg = EBPF_REG_2,
1620 .imm = 1,
1621 },
1622 {
1623 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1624 .dst_reg = EBPF_REG_3,
1625 .imm = 1,
1626 },
1627 {
1628 .code = (BPF_ALU | BPF_MOD | BPF_X),
1629 .dst_reg = EBPF_REG_4,
1630 .src_reg = EBPF_REG_2,
1631 },
1632 {
1633 .code = (EBPF_ALU64 | BPF_DIV | BPF_X),
1634 .dst_reg = EBPF_REG_4,
1635 .src_reg = EBPF_REG_3,
1636 },
1637 {
1638 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1639 .dst_reg = EBPF_REG_1,
1640 .src_reg = EBPF_REG_2,
1641 .off = offsetof(struct dummy_vect8, out[0].u64),
1642 },
1643 {
1644 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1645 .dst_reg = EBPF_REG_1,
1646 .src_reg = EBPF_REG_3,
1647 .off = offsetof(struct dummy_vect8, out[1].u64),
1648 },
1649 {
1650 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1651 .dst_reg = EBPF_REG_1,
1652 .src_reg = EBPF_REG_4,
1653 .off = offsetof(struct dummy_vect8, out[2].u64),
1654 },
1655 /* check that we can handle division by zero gracefully. */
1656 {
1657 .code = (BPF_LDX | BPF_MEM | BPF_W),
1658 .dst_reg = EBPF_REG_2,
1659 .src_reg = EBPF_REG_1,
1660 .off = offsetof(struct dummy_vect8, in[3].u32),
1661 },
1662 {
1663 .code = (BPF_ALU | BPF_DIV | BPF_X),
1664 .dst_reg = EBPF_REG_4,
1665 .src_reg = EBPF_REG_2,
1666 },
1667 /* return 1 */
1668 {
1669 .code = (BPF_ALU | EBPF_MOV | BPF_K),
1670 .dst_reg = EBPF_REG_0,
1671 .imm = 1,
1672 },
1673 {
1674 .code = (BPF_JMP | EBPF_EXIT),
1675 },
1676 };
1677
1678 static int
test_div1_check(uint64_t rc,const void * arg)1679 test_div1_check(uint64_t rc, const void *arg)
1680 {
1681 uint64_t r2, r3, r4;
1682 const struct dummy_vect8 *dvt;
1683 struct dummy_vect8 dve;
1684
1685 dvt = arg;
1686 memset(&dve, 0, sizeof(dve));
1687
1688 r2 = dvt->in[0].u32;
1689 r3 = dvt->in[1].u64;
1690 r4 = dvt->in[2].u32;
1691
1692 r2 = (uint32_t)r2 / TEST_MUL_1;
1693 r3 %= TEST_MUL_2;
1694 r2 |= 1;
1695 r3 |= 1;
1696 r4 = (uint32_t)(r4 % r2);
1697 r4 /= r3;
1698
1699 dve.out[0].u64 = r2;
1700 dve.out[1].u64 = r3;
1701 dve.out[2].u64 = r4;
1702
1703 /*
1704 * in the test prog we attempted to divide by zero.
1705 * so return value should return 0.
1706 */
1707 return cmp_res(__func__, 0, rc, dve.out, dvt->out, sizeof(dve.out));
1708 }
1709
1710 /* call test-cases */
1711 static const struct ebpf_insn test_call1_prog[] = {
1712
1713 {
1714 .code = (BPF_LDX | BPF_MEM | BPF_W),
1715 .dst_reg = EBPF_REG_2,
1716 .src_reg = EBPF_REG_1,
1717 .off = offsetof(struct dummy_offset, u32),
1718 },
1719 {
1720 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1721 .dst_reg = EBPF_REG_3,
1722 .src_reg = EBPF_REG_1,
1723 .off = offsetof(struct dummy_offset, u64),
1724 },
1725 {
1726 .code = (BPF_STX | BPF_MEM | BPF_W),
1727 .dst_reg = EBPF_REG_10,
1728 .src_reg = EBPF_REG_2,
1729 .off = -4,
1730 },
1731 {
1732 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1733 .dst_reg = EBPF_REG_10,
1734 .src_reg = EBPF_REG_3,
1735 .off = -16,
1736 },
1737 {
1738 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1739 .dst_reg = EBPF_REG_2,
1740 .src_reg = EBPF_REG_10,
1741 },
1742 {
1743 .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
1744 .dst_reg = EBPF_REG_2,
1745 .imm = 4,
1746 },
1747 {
1748 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1749 .dst_reg = EBPF_REG_3,
1750 .src_reg = EBPF_REG_10,
1751 },
1752 {
1753 .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
1754 .dst_reg = EBPF_REG_3,
1755 .imm = 16,
1756 },
1757 {
1758 .code = (BPF_JMP | EBPF_CALL),
1759 .imm = 0,
1760 },
1761 {
1762 .code = (BPF_LDX | BPF_MEM | BPF_W),
1763 .dst_reg = EBPF_REG_2,
1764 .src_reg = EBPF_REG_10,
1765 .off = -4,
1766 },
1767 {
1768 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1769 .dst_reg = EBPF_REG_0,
1770 .src_reg = EBPF_REG_10,
1771 .off = -16
1772 },
1773 {
1774 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1775 .dst_reg = EBPF_REG_0,
1776 .src_reg = EBPF_REG_2,
1777 },
1778 {
1779 .code = (BPF_JMP | EBPF_EXIT),
1780 },
1781 };
1782
1783 static void
dummy_func1(const void * p,uint32_t * v32,uint64_t * v64)1784 dummy_func1(const void *p, uint32_t *v32, uint64_t *v64)
1785 {
1786 const struct dummy_offset *dv;
1787
1788 dv = p;
1789
1790 v32[0] += dv->u16;
1791 v64[0] += dv->u8;
1792 }
1793
1794 static int
test_call1_check(uint64_t rc,const void * arg)1795 test_call1_check(uint64_t rc, const void *arg)
1796 {
1797 uint32_t v32;
1798 uint64_t v64;
1799 const struct dummy_offset *dv;
1800
1801 dv = arg;
1802
1803 v32 = dv->u32;
1804 v64 = dv->u64;
1805 dummy_func1(arg, &v32, &v64);
1806 v64 += v32;
1807
1808 return cmp_res(__func__, v64, rc, dv, dv, sizeof(*dv));
1809 }
1810
1811 static const struct rte_bpf_xsym test_call1_xsym[] = {
1812 {
1813 .name = RTE_STR(dummy_func1),
1814 .type = RTE_BPF_XTYPE_FUNC,
1815 .func = {
1816 .val = (void *)dummy_func1,
1817 .nb_args = 3,
1818 .args = {
1819 [0] = {
1820 .type = RTE_BPF_ARG_PTR,
1821 .size = sizeof(struct dummy_offset),
1822 },
1823 [1] = {
1824 .type = RTE_BPF_ARG_PTR,
1825 .size = sizeof(uint32_t),
1826 },
1827 [2] = {
1828 .type = RTE_BPF_ARG_PTR,
1829 .size = sizeof(uint64_t),
1830 },
1831 },
1832 },
1833 },
1834 };
1835
1836 static const struct ebpf_insn test_call2_prog[] = {
1837
1838 {
1839 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1840 .dst_reg = EBPF_REG_1,
1841 .src_reg = EBPF_REG_10,
1842 },
1843 {
1844 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1845 .dst_reg = EBPF_REG_1,
1846 .imm = -(int32_t)sizeof(struct dummy_offset),
1847 },
1848 {
1849 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1850 .dst_reg = EBPF_REG_2,
1851 .src_reg = EBPF_REG_10,
1852 },
1853 {
1854 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1855 .dst_reg = EBPF_REG_2,
1856 .imm = -2 * (int32_t)sizeof(struct dummy_offset),
1857 },
1858 {
1859 .code = (BPF_JMP | EBPF_CALL),
1860 .imm = 0,
1861 },
1862 {
1863 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1864 .dst_reg = EBPF_REG_1,
1865 .src_reg = EBPF_REG_10,
1866 .off = -(int32_t)(sizeof(struct dummy_offset) -
1867 offsetof(struct dummy_offset, u64)),
1868 },
1869 {
1870 .code = (BPF_LDX | BPF_MEM | BPF_W),
1871 .dst_reg = EBPF_REG_0,
1872 .src_reg = EBPF_REG_10,
1873 .off = -(int32_t)(sizeof(struct dummy_offset) -
1874 offsetof(struct dummy_offset, u32)),
1875 },
1876 {
1877 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1878 .dst_reg = EBPF_REG_0,
1879 .src_reg = EBPF_REG_1,
1880 },
1881 {
1882 .code = (BPF_LDX | BPF_MEM | BPF_H),
1883 .dst_reg = EBPF_REG_1,
1884 .src_reg = EBPF_REG_10,
1885 .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
1886 offsetof(struct dummy_offset, u16)),
1887 },
1888 {
1889 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1890 .dst_reg = EBPF_REG_0,
1891 .src_reg = EBPF_REG_1,
1892 },
1893 {
1894 .code = (BPF_LDX | BPF_MEM | BPF_B),
1895 .dst_reg = EBPF_REG_1,
1896 .src_reg = EBPF_REG_10,
1897 .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
1898 offsetof(struct dummy_offset, u8)),
1899 },
1900 {
1901 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1902 .dst_reg = EBPF_REG_0,
1903 .src_reg = EBPF_REG_1,
1904 },
1905 {
1906 .code = (BPF_JMP | EBPF_EXIT),
1907 },
1908
1909 };
1910
1911 static void
dummy_func2(struct dummy_offset * a,struct dummy_offset * b)1912 dummy_func2(struct dummy_offset *a, struct dummy_offset *b)
1913 {
1914 uint64_t v;
1915
1916 v = 0;
1917 a->u64 = v++;
1918 a->u32 = v++;
1919 a->u16 = v++;
1920 a->u8 = v++;
1921 b->u64 = v++;
1922 b->u32 = v++;
1923 b->u16 = v++;
1924 b->u8 = v++;
1925 }
1926
1927 static int
test_call2_check(uint64_t rc,const void * arg)1928 test_call2_check(uint64_t rc, const void *arg)
1929 {
1930 uint64_t v;
1931 struct dummy_offset a, b;
1932
1933 RTE_SET_USED(arg);
1934
1935 dummy_func2(&a, &b);
1936 v = a.u64 + a.u32 + b.u16 + b.u8;
1937
1938 return cmp_res(__func__, v, rc, arg, arg, 0);
1939 }
1940
1941 static const struct rte_bpf_xsym test_call2_xsym[] = {
1942 {
1943 .name = RTE_STR(dummy_func2),
1944 .type = RTE_BPF_XTYPE_FUNC,
1945 .func = {
1946 .val = (void *)dummy_func2,
1947 .nb_args = 2,
1948 .args = {
1949 [0] = {
1950 .type = RTE_BPF_ARG_PTR,
1951 .size = sizeof(struct dummy_offset),
1952 },
1953 [1] = {
1954 .type = RTE_BPF_ARG_PTR,
1955 .size = sizeof(struct dummy_offset),
1956 },
1957 },
1958 },
1959 },
1960 };
1961
1962 static const struct ebpf_insn test_call3_prog[] = {
1963
1964 {
1965 .code = (BPF_JMP | EBPF_CALL),
1966 .imm = 0,
1967 },
1968 {
1969 .code = (BPF_LDX | BPF_MEM | BPF_B),
1970 .dst_reg = EBPF_REG_2,
1971 .src_reg = EBPF_REG_0,
1972 .off = offsetof(struct dummy_offset, u8),
1973 },
1974 {
1975 .code = (BPF_LDX | BPF_MEM | BPF_H),
1976 .dst_reg = EBPF_REG_3,
1977 .src_reg = EBPF_REG_0,
1978 .off = offsetof(struct dummy_offset, u16),
1979 },
1980 {
1981 .code = (BPF_LDX | BPF_MEM | BPF_W),
1982 .dst_reg = EBPF_REG_4,
1983 .src_reg = EBPF_REG_0,
1984 .off = offsetof(struct dummy_offset, u32),
1985 },
1986 {
1987 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1988 .dst_reg = EBPF_REG_0,
1989 .src_reg = EBPF_REG_0,
1990 .off = offsetof(struct dummy_offset, u64),
1991 },
1992 /* return sum */
1993 {
1994 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1995 .dst_reg = EBPF_REG_0,
1996 .src_reg = EBPF_REG_4,
1997 },
1998 {
1999 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2000 .dst_reg = EBPF_REG_0,
2001 .src_reg = EBPF_REG_3,
2002 },
2003 {
2004 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2005 .dst_reg = EBPF_REG_0,
2006 .src_reg = EBPF_REG_2,
2007 },
2008 {
2009 .code = (BPF_JMP | EBPF_EXIT),
2010 },
2011 };
2012
2013 static const struct dummy_offset *
dummy_func3(const struct dummy_vect8 * p)2014 dummy_func3(const struct dummy_vect8 *p)
2015 {
2016 return &p->in[RTE_DIM(p->in) - 1];
2017 }
2018
2019 static void
test_call3_prepare(void * arg)2020 test_call3_prepare(void *arg)
2021 {
2022 struct dummy_vect8 *pv;
2023 struct dummy_offset *df;
2024
2025 pv = arg;
2026 df = (struct dummy_offset *)(uintptr_t)dummy_func3(pv);
2027
2028 memset(pv, 0, sizeof(*pv));
2029 df->u64 = (int32_t)TEST_FILL_1;
2030 df->u32 = df->u64;
2031 df->u16 = df->u64;
2032 df->u8 = df->u64;
2033 }
2034
2035 static int
test_call3_check(uint64_t rc,const void * arg)2036 test_call3_check(uint64_t rc, const void *arg)
2037 {
2038 uint64_t v;
2039 const struct dummy_vect8 *pv;
2040 const struct dummy_offset *dft;
2041
2042 pv = arg;
2043 dft = dummy_func3(pv);
2044
2045 v = dft->u64;
2046 v += dft->u32;
2047 v += dft->u16;
2048 v += dft->u8;
2049
2050 return cmp_res(__func__, v, rc, pv, pv, sizeof(*pv));
2051 }
2052
2053 static const struct rte_bpf_xsym test_call3_xsym[] = {
2054 {
2055 .name = RTE_STR(dummy_func3),
2056 .type = RTE_BPF_XTYPE_FUNC,
2057 .func = {
2058 .val = (void *)dummy_func3,
2059 .nb_args = 1,
2060 .args = {
2061 [0] = {
2062 .type = RTE_BPF_ARG_PTR,
2063 .size = sizeof(struct dummy_vect8),
2064 },
2065 },
2066 .ret = {
2067 .type = RTE_BPF_ARG_PTR,
2068 .size = sizeof(struct dummy_offset),
2069 },
2070 },
2071 },
2072 };
2073
2074 /* Test for stack corruption in multiple function calls */
2075 static const struct ebpf_insn test_call4_prog[] = {
2076 {
2077 .code = (BPF_ST | BPF_MEM | BPF_B),
2078 .dst_reg = EBPF_REG_10,
2079 .off = -4,
2080 .imm = 1,
2081 },
2082 {
2083 .code = (BPF_ST | BPF_MEM | BPF_B),
2084 .dst_reg = EBPF_REG_10,
2085 .off = -3,
2086 .imm = 2,
2087 },
2088 {
2089 .code = (BPF_ST | BPF_MEM | BPF_B),
2090 .dst_reg = EBPF_REG_10,
2091 .off = -2,
2092 .imm = 3,
2093 },
2094 {
2095 .code = (BPF_ST | BPF_MEM | BPF_B),
2096 .dst_reg = EBPF_REG_10,
2097 .off = -1,
2098 .imm = 4,
2099 },
2100 {
2101 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2102 .dst_reg = EBPF_REG_1,
2103 .src_reg = EBPF_REG_10,
2104 },
2105 {
2106 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2107 .dst_reg = EBPF_REG_2,
2108 .imm = 4,
2109 },
2110 {
2111 .code = (EBPF_ALU64 | BPF_SUB | BPF_X),
2112 .dst_reg = EBPF_REG_1,
2113 .src_reg = EBPF_REG_2,
2114 },
2115 {
2116 .code = (BPF_JMP | EBPF_CALL),
2117 .imm = 0,
2118 },
2119 {
2120 .code = (BPF_LDX | BPF_MEM | BPF_B),
2121 .dst_reg = EBPF_REG_1,
2122 .src_reg = EBPF_REG_10,
2123 .off = -4,
2124 },
2125 {
2126 .code = (BPF_LDX | BPF_MEM | BPF_B),
2127 .dst_reg = EBPF_REG_2,
2128 .src_reg = EBPF_REG_10,
2129 .off = -3,
2130 },
2131 {
2132 .code = (BPF_LDX | BPF_MEM | BPF_B),
2133 .dst_reg = EBPF_REG_3,
2134 .src_reg = EBPF_REG_10,
2135 .off = -2,
2136 },
2137 {
2138 .code = (BPF_LDX | BPF_MEM | BPF_B),
2139 .dst_reg = EBPF_REG_4,
2140 .src_reg = EBPF_REG_10,
2141 .off = -1,
2142 },
2143 {
2144 .code = (BPF_JMP | EBPF_CALL),
2145 .imm = 1,
2146 },
2147 {
2148 .code = (EBPF_ALU64 | BPF_XOR | BPF_K),
2149 .dst_reg = EBPF_REG_0,
2150 .imm = TEST_MEMFROB,
2151 },
2152 {
2153 .code = (BPF_JMP | EBPF_EXIT),
2154 },
2155 };
2156
2157 /* Gathering the bytes together */
2158 static uint32_t
dummy_func4_1(uint8_t a,uint8_t b,uint8_t c,uint8_t d)2159 dummy_func4_1(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
2160 {
2161 return (a << 24) | (b << 16) | (c << 8) | (d << 0);
2162 }
2163
2164 /* Implementation of memfrob */
2165 static uint32_t
dummy_func4_0(uint32_t * s,uint8_t n)2166 dummy_func4_0(uint32_t *s, uint8_t n)
2167 {
2168 char *p = (char *) s;
2169 while (n-- > 0)
2170 *p++ ^= 42;
2171 return *s;
2172 }
2173
2174
2175 static int
test_call4_check(uint64_t rc,const void * arg)2176 test_call4_check(uint64_t rc, const void *arg)
2177 {
2178 uint8_t a[4] = {1, 2, 3, 4};
2179 uint32_t s, v = 0;
2180
2181 RTE_SET_USED(arg);
2182
2183 s = dummy_func4_0((uint32_t *)a, 4);
2184
2185 s = dummy_func4_1(a[0], a[1], a[2], a[3]);
2186
2187 v = s ^ TEST_MEMFROB;
2188
2189 return cmp_res(__func__, v, rc, &v, &rc, sizeof(v));
2190 }
2191
2192 static const struct rte_bpf_xsym test_call4_xsym[] = {
2193 [0] = {
2194 .name = RTE_STR(dummy_func4_0),
2195 .type = RTE_BPF_XTYPE_FUNC,
2196 .func = {
2197 .val = (void *)dummy_func4_0,
2198 .nb_args = 2,
2199 .args = {
2200 [0] = {
2201 .type = RTE_BPF_ARG_PTR,
2202 .size = 4 * sizeof(uint8_t),
2203 },
2204 [1] = {
2205 .type = RTE_BPF_ARG_RAW,
2206 .size = sizeof(uint8_t),
2207 },
2208 },
2209 .ret = {
2210 .type = RTE_BPF_ARG_RAW,
2211 .size = sizeof(uint32_t),
2212 },
2213 },
2214 },
2215 [1] = {
2216 .name = RTE_STR(dummy_func4_1),
2217 .type = RTE_BPF_XTYPE_FUNC,
2218 .func = {
2219 .val = (void *)dummy_func4_1,
2220 .nb_args = 4,
2221 .args = {
2222 [0] = {
2223 .type = RTE_BPF_ARG_RAW,
2224 .size = sizeof(uint8_t),
2225 },
2226 [1] = {
2227 .type = RTE_BPF_ARG_RAW,
2228 .size = sizeof(uint8_t),
2229 },
2230 [2] = {
2231 .type = RTE_BPF_ARG_RAW,
2232 .size = sizeof(uint8_t),
2233 },
2234 [3] = {
2235 .type = RTE_BPF_ARG_RAW,
2236 .size = sizeof(uint8_t),
2237 },
2238 },
2239 .ret = {
2240 .type = RTE_BPF_ARG_RAW,
2241 .size = sizeof(uint32_t),
2242 },
2243 },
2244 },
2245 };
2246
2247 /* string compare test case */
2248 static const struct ebpf_insn test_call5_prog[] = {
2249
2250 [0] = {
2251 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2252 .dst_reg = EBPF_REG_1,
2253 .imm = STRING_GEEK,
2254 },
2255 [1] = {
2256 .code = (BPF_STX | BPF_MEM | BPF_W),
2257 .dst_reg = EBPF_REG_10,
2258 .src_reg = EBPF_REG_1,
2259 .off = -8,
2260 },
2261 [2] = {
2262 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2263 .dst_reg = EBPF_REG_6,
2264 .imm = 0,
2265 },
2266 [3] = {
2267 .code = (BPF_STX | BPF_MEM | BPF_B),
2268 .dst_reg = EBPF_REG_10,
2269 .src_reg = EBPF_REG_6,
2270 .off = -4,
2271 },
2272 [4] = {
2273 .code = (BPF_STX | BPF_MEM | BPF_W),
2274 .dst_reg = EBPF_REG_10,
2275 .src_reg = EBPF_REG_6,
2276 .off = -12,
2277 },
2278 [5] = {
2279 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2280 .dst_reg = EBPF_REG_1,
2281 .imm = STRING_WEEK,
2282 },
2283 [6] = {
2284 .code = (BPF_STX | BPF_MEM | BPF_W),
2285 .dst_reg = EBPF_REG_10,
2286 .src_reg = EBPF_REG_1,
2287 .off = -16,
2288 },
2289 [7] = {
2290 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2291 .dst_reg = EBPF_REG_1,
2292 .src_reg = EBPF_REG_10,
2293 },
2294 [8] = {
2295 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2296 .dst_reg = EBPF_REG_1,
2297 .imm = -8,
2298 },
2299 [9] = {
2300 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2301 .dst_reg = EBPF_REG_2,
2302 .src_reg = EBPF_REG_1,
2303 },
2304 [10] = {
2305 .code = (BPF_JMP | EBPF_CALL),
2306 .imm = 0,
2307 },
2308 [11] = {
2309 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2310 .dst_reg = EBPF_REG_1,
2311 .src_reg = EBPF_REG_0,
2312 },
2313 [12] = {
2314 .code = (BPF_ALU | EBPF_MOV | BPF_K),
2315 .dst_reg = EBPF_REG_0,
2316 .imm = -1,
2317 },
2318 [13] = {
2319 .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
2320 .dst_reg = EBPF_REG_1,
2321 .imm = 0x20,
2322 },
2323 [14] = {
2324 .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2325 .dst_reg = EBPF_REG_1,
2326 .imm = 0x20,
2327 },
2328 [15] = {
2329 .code = (BPF_JMP | EBPF_JNE | BPF_K),
2330 .dst_reg = EBPF_REG_1,
2331 .off = 11,
2332 .imm = 0,
2333 },
2334 [16] = {
2335 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2336 .dst_reg = EBPF_REG_1,
2337 .src_reg = EBPF_REG_10,
2338 },
2339 [17] = {
2340 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2341 .dst_reg = EBPF_REG_1,
2342 .imm = -8,
2343 },
2344 [18] = {
2345 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2346 .dst_reg = EBPF_REG_2,
2347 .src_reg = EBPF_REG_10,
2348 },
2349 [19] = {
2350 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2351 .dst_reg = EBPF_REG_2,
2352 .imm = -16,
2353 },
2354 [20] = {
2355 .code = (BPF_JMP | EBPF_CALL),
2356 .imm = 0,
2357 },
2358 [21] = {
2359 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2360 .dst_reg = EBPF_REG_1,
2361 .src_reg = EBPF_REG_0,
2362 },
2363 [22] = {
2364 .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
2365 .dst_reg = EBPF_REG_1,
2366 .imm = 0x20,
2367 },
2368 [23] = {
2369 .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2370 .dst_reg = EBPF_REG_1,
2371 .imm = 0x20,
2372 },
2373 [24] = {
2374 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2375 .dst_reg = EBPF_REG_0,
2376 .src_reg = EBPF_REG_1,
2377 },
2378 [25] = {
2379 .code = (BPF_JMP | BPF_JEQ | BPF_X),
2380 .dst_reg = EBPF_REG_1,
2381 .src_reg = EBPF_REG_6,
2382 .off = 1,
2383 },
2384 [26] = {
2385 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2386 .dst_reg = EBPF_REG_0,
2387 .imm = 0,
2388 },
2389 [27] = {
2390 .code = (BPF_JMP | EBPF_EXIT),
2391 },
2392 };
2393
2394 /* String comparision impelementation, return 0 if equal else difference */
2395 static uint32_t
dummy_func5(const char * s1,const char * s2)2396 dummy_func5(const char *s1, const char *s2)
2397 {
2398 while (*s1 && (*s1 == *s2)) {
2399 s1++;
2400 s2++;
2401 }
2402 return *(const unsigned char *)s1 - *(const unsigned char *)s2;
2403 }
2404
2405 static int
test_call5_check(uint64_t rc,const void * arg)2406 test_call5_check(uint64_t rc, const void *arg)
2407 {
2408 char a[] = "geek";
2409 char b[] = "week";
2410 uint32_t v;
2411
2412 RTE_SET_USED(arg);
2413
2414 v = dummy_func5(a, a);
2415 if (v != 0) {
2416 v = -1;
2417 goto fail;
2418 }
2419
2420 v = dummy_func5(a, b);
2421 if (v == 0)
2422 goto fail;
2423
2424 v = 0;
2425
2426 fail:
2427 return cmp_res(__func__, v, rc, &v, &rc, sizeof(v));
2428 }
2429
2430 static const struct rte_bpf_xsym test_call5_xsym[] = {
2431 [0] = {
2432 .name = RTE_STR(dummy_func5),
2433 .type = RTE_BPF_XTYPE_FUNC,
2434 .func = {
2435 .val = (void *)dummy_func5,
2436 .nb_args = 2,
2437 .args = {
2438 [0] = {
2439 .type = RTE_BPF_ARG_PTR,
2440 .size = sizeof(char),
2441 },
2442 [1] = {
2443 .type = RTE_BPF_ARG_PTR,
2444 .size = sizeof(char),
2445 },
2446 },
2447 .ret = {
2448 .type = RTE_BPF_ARG_RAW,
2449 .size = sizeof(uint32_t),
2450 },
2451 },
2452 },
2453 };
2454
2455 /* load mbuf (BPF_ABS/BPF_IND) test-cases */
2456 static const struct ebpf_insn test_ld_mbuf1_prog[] = {
2457
2458 /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
2459 {
2460 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2461 .dst_reg = EBPF_REG_6,
2462 .src_reg = EBPF_REG_1,
2463 },
2464 /* load IPv4 version and IHL */
2465 {
2466 .code = (BPF_LD | BPF_ABS | BPF_B),
2467 .imm = offsetof(struct rte_ipv4_hdr, version_ihl),
2468 },
2469 /* check IP version */
2470 {
2471 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2472 .dst_reg = EBPF_REG_2,
2473 .src_reg = EBPF_REG_0,
2474 },
2475 {
2476 .code = (BPF_ALU | BPF_AND | BPF_K),
2477 .dst_reg = EBPF_REG_2,
2478 .imm = 0xf0,
2479 },
2480 {
2481 .code = (BPF_JMP | BPF_JEQ | BPF_K),
2482 .dst_reg = EBPF_REG_2,
2483 .imm = IPVERSION << 4,
2484 .off = 2,
2485 },
2486 /* invalid IP version, return 0 */
2487 {
2488 .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
2489 .dst_reg = EBPF_REG_0,
2490 .src_reg = EBPF_REG_0,
2491 },
2492 {
2493 .code = (BPF_JMP | EBPF_EXIT),
2494 },
2495 /* load 3-rd byte of IP data */
2496 {
2497 .code = (BPF_ALU | BPF_AND | BPF_K),
2498 .dst_reg = EBPF_REG_0,
2499 .imm = RTE_IPV4_HDR_IHL_MASK,
2500 },
2501 {
2502 .code = (BPF_ALU | BPF_LSH | BPF_K),
2503 .dst_reg = EBPF_REG_0,
2504 .imm = 2,
2505 },
2506 {
2507 .code = (BPF_LD | BPF_IND | BPF_B),
2508 .src_reg = EBPF_REG_0,
2509 .imm = 3,
2510 },
2511 {
2512 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2513 .dst_reg = EBPF_REG_7,
2514 .src_reg = EBPF_REG_0,
2515 },
2516 /* load IPv4 src addr */
2517 {
2518 .code = (BPF_LD | BPF_ABS | BPF_W),
2519 .imm = offsetof(struct rte_ipv4_hdr, src_addr),
2520 },
2521 {
2522 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2523 .dst_reg = EBPF_REG_7,
2524 .src_reg = EBPF_REG_0,
2525 },
2526 /* load IPv4 total length */
2527 {
2528 .code = (BPF_LD | BPF_ABS | BPF_H),
2529 .imm = offsetof(struct rte_ipv4_hdr, total_length),
2530 },
2531 {
2532 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2533 .dst_reg = EBPF_REG_8,
2534 .src_reg = EBPF_REG_0,
2535 },
2536 /* load last 4 bytes of IP data */
2537 {
2538 .code = (BPF_LD | BPF_IND | BPF_W),
2539 .src_reg = EBPF_REG_8,
2540 .imm = -(int32_t)sizeof(uint32_t),
2541 },
2542 {
2543 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2544 .dst_reg = EBPF_REG_7,
2545 .src_reg = EBPF_REG_0,
2546 },
2547 /* load 2 bytes from the middle of IP data */
2548 {
2549 .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2550 .dst_reg = EBPF_REG_8,
2551 .imm = 1,
2552 },
2553 {
2554 .code = (BPF_LD | BPF_IND | BPF_H),
2555 .src_reg = EBPF_REG_8,
2556 },
2557 {
2558 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2559 .dst_reg = EBPF_REG_0,
2560 .src_reg = EBPF_REG_7,
2561 },
2562 {
2563 .code = (BPF_JMP | EBPF_EXIT),
2564 },
2565 };
2566
2567 static void
dummy_mbuf_prep(struct rte_mbuf * mb,uint8_t buf[],uint32_t buf_len,uint32_t data_len)2568 dummy_mbuf_prep(struct rte_mbuf *mb, uint8_t buf[], uint32_t buf_len,
2569 uint32_t data_len)
2570 {
2571 uint32_t i;
2572 uint8_t *db;
2573
2574 mb->buf_addr = buf;
2575 mb->buf_iova = (uintptr_t)buf;
2576 mb->buf_len = buf_len;
2577 rte_mbuf_refcnt_set(mb, 1);
2578
2579 /* set pool pointer to dummy value, test doesn't use it */
2580 mb->pool = (void *)buf;
2581
2582 rte_pktmbuf_reset(mb);
2583 db = (uint8_t *)rte_pktmbuf_append(mb, data_len);
2584
2585 for (i = 0; i != data_len; i++)
2586 db[i] = i;
2587 }
2588
2589 static void
test_ld_mbuf1_prepare(void * arg)2590 test_ld_mbuf1_prepare(void *arg)
2591 {
2592 struct dummy_mbuf *dm;
2593 struct rte_ipv4_hdr *ph;
2594
2595 const uint32_t plen = 400;
2596 const struct rte_ipv4_hdr iph = {
2597 .version_ihl = RTE_IPV4_VHL_DEF,
2598 .total_length = rte_cpu_to_be_16(plen),
2599 .time_to_live = IPDEFTTL,
2600 .next_proto_id = IPPROTO_RAW,
2601 .src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK),
2602 .dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST),
2603 };
2604
2605 dm = arg;
2606 memset(dm, 0, sizeof(*dm));
2607
2608 dummy_mbuf_prep(&dm->mb[0], dm->buf[0], sizeof(dm->buf[0]),
2609 plen / 2 + 1);
2610 dummy_mbuf_prep(&dm->mb[1], dm->buf[1], sizeof(dm->buf[0]),
2611 plen / 2 - 1);
2612
2613 rte_pktmbuf_chain(&dm->mb[0], &dm->mb[1]);
2614
2615 ph = rte_pktmbuf_mtod(dm->mb, typeof(ph));
2616 memcpy(ph, &iph, sizeof(iph));
2617 }
2618
2619 static uint64_t
test_ld_mbuf1(const struct rte_mbuf * pkt)2620 test_ld_mbuf1(const struct rte_mbuf *pkt)
2621 {
2622 uint64_t n, v;
2623 const uint8_t *p8;
2624 const uint16_t *p16;
2625 const uint32_t *p32;
2626 struct dummy_offset dof;
2627
2628 /* load IPv4 version and IHL */
2629 p8 = rte_pktmbuf_read(pkt,
2630 offsetof(struct rte_ipv4_hdr, version_ihl), sizeof(*p8),
2631 &dof);
2632 if (p8 == NULL)
2633 return 0;
2634
2635 /* check IP version */
2636 if ((p8[0] & 0xf0) != IPVERSION << 4)
2637 return 0;
2638
2639 n = (p8[0] & RTE_IPV4_HDR_IHL_MASK) * RTE_IPV4_IHL_MULTIPLIER;
2640
2641 /* load 3-rd byte of IP data */
2642 p8 = rte_pktmbuf_read(pkt, n + 3, sizeof(*p8), &dof);
2643 if (p8 == NULL)
2644 return 0;
2645
2646 v = p8[0];
2647
2648 /* load IPv4 src addr */
2649 p32 = rte_pktmbuf_read(pkt,
2650 offsetof(struct rte_ipv4_hdr, src_addr), sizeof(*p32),
2651 &dof);
2652 if (p32 == NULL)
2653 return 0;
2654
2655 v += rte_be_to_cpu_32(p32[0]);
2656
2657 /* load IPv4 total length */
2658 p16 = rte_pktmbuf_read(pkt,
2659 offsetof(struct rte_ipv4_hdr, total_length), sizeof(*p16),
2660 &dof);
2661 if (p16 == NULL)
2662 return 0;
2663
2664 n = rte_be_to_cpu_16(p16[0]);
2665
2666 /* load last 4 bytes of IP data */
2667 p32 = rte_pktmbuf_read(pkt, n - sizeof(*p32), sizeof(*p32), &dof);
2668 if (p32 == NULL)
2669 return 0;
2670
2671 v += rte_be_to_cpu_32(p32[0]);
2672
2673 /* load 2 bytes from the middle of IP data */
2674 p16 = rte_pktmbuf_read(pkt, n / 2, sizeof(*p16), &dof);
2675 if (p16 == NULL)
2676 return 0;
2677
2678 v += rte_be_to_cpu_16(p16[0]);
2679 return v;
2680 }
2681
2682 static int
test_ld_mbuf1_check(uint64_t rc,const void * arg)2683 test_ld_mbuf1_check(uint64_t rc, const void *arg)
2684 {
2685 const struct dummy_mbuf *dm;
2686 uint64_t v;
2687
2688 dm = arg;
2689 v = test_ld_mbuf1(dm->mb);
2690 return cmp_res(__func__, v, rc, arg, arg, 0);
2691 }
2692
2693 /*
2694 * same as ld_mbuf1, but then trancate the mbuf by 1B,
2695 * so load of last 4B fail.
2696 */
2697 static void
test_ld_mbuf2_prepare(void * arg)2698 test_ld_mbuf2_prepare(void *arg)
2699 {
2700 struct dummy_mbuf *dm;
2701
2702 test_ld_mbuf1_prepare(arg);
2703 dm = arg;
2704 rte_pktmbuf_trim(dm->mb, 1);
2705 }
2706
2707 static int
test_ld_mbuf2_check(uint64_t rc,const void * arg)2708 test_ld_mbuf2_check(uint64_t rc, const void *arg)
2709 {
2710 return cmp_res(__func__, 0, rc, arg, arg, 0);
2711 }
2712
2713 /* same as test_ld_mbuf1, but now store intermediate results on the stack */
2714 static const struct ebpf_insn test_ld_mbuf3_prog[] = {
2715
2716 /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
2717 {
2718 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2719 .dst_reg = EBPF_REG_6,
2720 .src_reg = EBPF_REG_1,
2721 },
2722 /* load IPv4 version and IHL */
2723 {
2724 .code = (BPF_LD | BPF_ABS | BPF_B),
2725 .imm = offsetof(struct rte_ipv4_hdr, version_ihl),
2726 },
2727 /* check IP version */
2728 {
2729 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2730 .dst_reg = EBPF_REG_2,
2731 .src_reg = EBPF_REG_0,
2732 },
2733 {
2734 .code = (BPF_ALU | BPF_AND | BPF_K),
2735 .dst_reg = EBPF_REG_2,
2736 .imm = 0xf0,
2737 },
2738 {
2739 .code = (BPF_JMP | BPF_JEQ | BPF_K),
2740 .dst_reg = EBPF_REG_2,
2741 .imm = IPVERSION << 4,
2742 .off = 2,
2743 },
2744 /* invalid IP version, return 0 */
2745 {
2746 .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
2747 .dst_reg = EBPF_REG_0,
2748 .src_reg = EBPF_REG_0,
2749 },
2750 {
2751 .code = (BPF_JMP | EBPF_EXIT),
2752 },
2753 /* load 3-rd byte of IP data */
2754 {
2755 .code = (BPF_ALU | BPF_AND | BPF_K),
2756 .dst_reg = EBPF_REG_0,
2757 .imm = RTE_IPV4_HDR_IHL_MASK,
2758 },
2759 {
2760 .code = (BPF_ALU | BPF_LSH | BPF_K),
2761 .dst_reg = EBPF_REG_0,
2762 .imm = 2,
2763 },
2764 {
2765 .code = (BPF_LD | BPF_IND | BPF_B),
2766 .src_reg = EBPF_REG_0,
2767 .imm = 3,
2768 },
2769 {
2770 .code = (BPF_STX | BPF_MEM | BPF_B),
2771 .dst_reg = EBPF_REG_10,
2772 .src_reg = EBPF_REG_0,
2773 .off = (int16_t)(offsetof(struct dummy_offset, u8) -
2774 sizeof(struct dummy_offset)),
2775 },
2776 /* load IPv4 src addr */
2777 {
2778 .code = (BPF_LD | BPF_ABS | BPF_W),
2779 .imm = offsetof(struct rte_ipv4_hdr, src_addr),
2780 },
2781 {
2782 .code = (BPF_STX | BPF_MEM | BPF_W),
2783 .dst_reg = EBPF_REG_10,
2784 .src_reg = EBPF_REG_0,
2785 .off = (int16_t)(offsetof(struct dummy_offset, u32) -
2786 sizeof(struct dummy_offset)),
2787 },
2788 /* load IPv4 total length */
2789 {
2790 .code = (BPF_LD | BPF_ABS | BPF_H),
2791 .imm = offsetof(struct rte_ipv4_hdr, total_length),
2792 },
2793 {
2794 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2795 .dst_reg = EBPF_REG_8,
2796 .src_reg = EBPF_REG_0,
2797 },
2798 /* load last 4 bytes of IP data */
2799 {
2800 .code = (BPF_LD | BPF_IND | BPF_W),
2801 .src_reg = EBPF_REG_8,
2802 .imm = -(int32_t)sizeof(uint32_t),
2803 },
2804 {
2805 .code = (BPF_STX | BPF_MEM | EBPF_DW),
2806 .dst_reg = EBPF_REG_10,
2807 .src_reg = EBPF_REG_0,
2808 .off = (int16_t)(offsetof(struct dummy_offset, u64) -
2809 sizeof(struct dummy_offset)),
2810 },
2811 /* load 2 bytes from the middle of IP data */
2812 {
2813 .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2814 .dst_reg = EBPF_REG_8,
2815 .imm = 1,
2816 },
2817 {
2818 .code = (BPF_LD | BPF_IND | BPF_H),
2819 .src_reg = EBPF_REG_8,
2820 },
2821 {
2822 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2823 .dst_reg = EBPF_REG_1,
2824 .src_reg = EBPF_REG_10,
2825 .off = (int16_t)(offsetof(struct dummy_offset, u64) -
2826 sizeof(struct dummy_offset)),
2827 },
2828 {
2829 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2830 .dst_reg = EBPF_REG_0,
2831 .src_reg = EBPF_REG_1,
2832 },
2833 {
2834 .code = (BPF_LDX | BPF_MEM | BPF_W),
2835 .dst_reg = EBPF_REG_1,
2836 .src_reg = EBPF_REG_10,
2837 .off = (int16_t)(offsetof(struct dummy_offset, u32) -
2838 sizeof(struct dummy_offset)),
2839 },
2840 {
2841 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2842 .dst_reg = EBPF_REG_0,
2843 .src_reg = EBPF_REG_1,
2844 },
2845 {
2846 .code = (BPF_LDX | BPF_MEM | BPF_B),
2847 .dst_reg = EBPF_REG_1,
2848 .src_reg = EBPF_REG_10,
2849 .off = (int16_t)(offsetof(struct dummy_offset, u8) -
2850 sizeof(struct dummy_offset)),
2851 },
2852 {
2853 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2854 .dst_reg = EBPF_REG_0,
2855 .src_reg = EBPF_REG_1,
2856 },
2857 {
2858 .code = (BPF_JMP | EBPF_EXIT),
2859 },
2860 };
2861
2862 /* all bpf test cases */
2863 static const struct bpf_test tests[] = {
2864 {
2865 .name = "test_store1",
2866 .arg_sz = sizeof(struct dummy_offset),
2867 .prm = {
2868 .ins = test_store1_prog,
2869 .nb_ins = RTE_DIM(test_store1_prog),
2870 .prog_arg = {
2871 .type = RTE_BPF_ARG_PTR,
2872 .size = sizeof(struct dummy_offset),
2873 },
2874 },
2875 .prepare = test_store1_prepare,
2876 .check_result = test_store1_check,
2877 },
2878 {
2879 .name = "test_store2",
2880 .arg_sz = sizeof(struct dummy_offset),
2881 .prm = {
2882 .ins = test_store2_prog,
2883 .nb_ins = RTE_DIM(test_store2_prog),
2884 .prog_arg = {
2885 .type = RTE_BPF_ARG_PTR,
2886 .size = sizeof(struct dummy_offset),
2887 },
2888 },
2889 .prepare = test_store1_prepare,
2890 .check_result = test_store1_check,
2891 },
2892 {
2893 .name = "test_load1",
2894 .arg_sz = sizeof(struct dummy_offset),
2895 .prm = {
2896 .ins = test_load1_prog,
2897 .nb_ins = RTE_DIM(test_load1_prog),
2898 .prog_arg = {
2899 .type = RTE_BPF_ARG_PTR,
2900 .size = sizeof(struct dummy_offset),
2901 },
2902 },
2903 .prepare = test_load1_prepare,
2904 .check_result = test_load1_check,
2905 },
2906 {
2907 .name = "test_ldimm1",
2908 .arg_sz = sizeof(struct dummy_offset),
2909 .prm = {
2910 .ins = test_ldimm1_prog,
2911 .nb_ins = RTE_DIM(test_ldimm1_prog),
2912 .prog_arg = {
2913 .type = RTE_BPF_ARG_PTR,
2914 .size = sizeof(struct dummy_offset),
2915 },
2916 },
2917 .prepare = test_store1_prepare,
2918 .check_result = test_ldimm1_check,
2919 },
2920 {
2921 .name = "test_mul1",
2922 .arg_sz = sizeof(struct dummy_vect8),
2923 .prm = {
2924 .ins = test_mul1_prog,
2925 .nb_ins = RTE_DIM(test_mul1_prog),
2926 .prog_arg = {
2927 .type = RTE_BPF_ARG_PTR,
2928 .size = sizeof(struct dummy_vect8),
2929 },
2930 },
2931 .prepare = test_mul1_prepare,
2932 .check_result = test_mul1_check,
2933 },
2934 {
2935 .name = "test_shift1",
2936 .arg_sz = sizeof(struct dummy_vect8),
2937 .prm = {
2938 .ins = test_shift1_prog,
2939 .nb_ins = RTE_DIM(test_shift1_prog),
2940 .prog_arg = {
2941 .type = RTE_BPF_ARG_PTR,
2942 .size = sizeof(struct dummy_vect8),
2943 },
2944 },
2945 .prepare = test_shift1_prepare,
2946 .check_result = test_shift1_check,
2947 },
2948 {
2949 .name = "test_jump1",
2950 .arg_sz = sizeof(struct dummy_vect8),
2951 .prm = {
2952 .ins = test_jump1_prog,
2953 .nb_ins = RTE_DIM(test_jump1_prog),
2954 .prog_arg = {
2955 .type = RTE_BPF_ARG_PTR,
2956 .size = sizeof(struct dummy_vect8),
2957 },
2958 },
2959 .prepare = test_jump1_prepare,
2960 .check_result = test_jump1_check,
2961 },
2962 {
2963 .name = "test_jump2",
2964 .arg_sz = sizeof(struct dummy_net),
2965 .prm = {
2966 .ins = test_jump2_prog,
2967 .nb_ins = RTE_DIM(test_jump2_prog),
2968 .prog_arg = {
2969 .type = RTE_BPF_ARG_PTR,
2970 .size = sizeof(struct dummy_net),
2971 },
2972 },
2973 .prepare = test_jump2_prepare,
2974 .check_result = test_jump2_check,
2975 },
2976 {
2977 .name = "test_alu1",
2978 .arg_sz = sizeof(struct dummy_vect8),
2979 .prm = {
2980 .ins = test_alu1_prog,
2981 .nb_ins = RTE_DIM(test_alu1_prog),
2982 .prog_arg = {
2983 .type = RTE_BPF_ARG_PTR,
2984 .size = sizeof(struct dummy_vect8),
2985 },
2986 },
2987 .prepare = test_jump1_prepare,
2988 .check_result = test_alu1_check,
2989 },
2990 {
2991 .name = "test_bele1",
2992 .arg_sz = sizeof(struct dummy_vect8),
2993 .prm = {
2994 .ins = test_bele1_prog,
2995 .nb_ins = RTE_DIM(test_bele1_prog),
2996 .prog_arg = {
2997 .type = RTE_BPF_ARG_PTR,
2998 .size = sizeof(struct dummy_vect8),
2999 },
3000 },
3001 .prepare = test_bele1_prepare,
3002 .check_result = test_bele1_check,
3003 },
3004 {
3005 .name = "test_xadd1",
3006 .arg_sz = sizeof(struct dummy_offset),
3007 .prm = {
3008 .ins = test_xadd1_prog,
3009 .nb_ins = RTE_DIM(test_xadd1_prog),
3010 .prog_arg = {
3011 .type = RTE_BPF_ARG_PTR,
3012 .size = sizeof(struct dummy_offset),
3013 },
3014 },
3015 .prepare = test_store1_prepare,
3016 .check_result = test_xadd1_check,
3017 },
3018 {
3019 .name = "test_div1",
3020 .arg_sz = sizeof(struct dummy_vect8),
3021 .prm = {
3022 .ins = test_div1_prog,
3023 .nb_ins = RTE_DIM(test_div1_prog),
3024 .prog_arg = {
3025 .type = RTE_BPF_ARG_PTR,
3026 .size = sizeof(struct dummy_vect8),
3027 },
3028 },
3029 .prepare = test_mul1_prepare,
3030 .check_result = test_div1_check,
3031 },
3032 {
3033 .name = "test_call1",
3034 .arg_sz = sizeof(struct dummy_offset),
3035 .prm = {
3036 .ins = test_call1_prog,
3037 .nb_ins = RTE_DIM(test_call1_prog),
3038 .prog_arg = {
3039 .type = RTE_BPF_ARG_PTR,
3040 .size = sizeof(struct dummy_offset),
3041 },
3042 .xsym = test_call1_xsym,
3043 .nb_xsym = RTE_DIM(test_call1_xsym),
3044 },
3045 .prepare = test_load1_prepare,
3046 .check_result = test_call1_check,
3047 /* for now don't support function calls on 32 bit platform */
3048 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3049 },
3050 {
3051 .name = "test_call2",
3052 .arg_sz = sizeof(struct dummy_offset),
3053 .prm = {
3054 .ins = test_call2_prog,
3055 .nb_ins = RTE_DIM(test_call2_prog),
3056 .prog_arg = {
3057 .type = RTE_BPF_ARG_PTR,
3058 .size = sizeof(struct dummy_offset),
3059 },
3060 .xsym = test_call2_xsym,
3061 .nb_xsym = RTE_DIM(test_call2_xsym),
3062 },
3063 .prepare = test_store1_prepare,
3064 .check_result = test_call2_check,
3065 /* for now don't support function calls on 32 bit platform */
3066 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3067 },
3068 {
3069 .name = "test_call3",
3070 .arg_sz = sizeof(struct dummy_vect8),
3071 .prm = {
3072 .ins = test_call3_prog,
3073 .nb_ins = RTE_DIM(test_call3_prog),
3074 .prog_arg = {
3075 .type = RTE_BPF_ARG_PTR,
3076 .size = sizeof(struct dummy_vect8),
3077 },
3078 .xsym = test_call3_xsym,
3079 .nb_xsym = RTE_DIM(test_call3_xsym),
3080 },
3081 .prepare = test_call3_prepare,
3082 .check_result = test_call3_check,
3083 /* for now don't support function calls on 32 bit platform */
3084 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3085 },
3086 {
3087 .name = "test_call4",
3088 .arg_sz = sizeof(struct dummy_offset),
3089 .prm = {
3090 .ins = test_call4_prog,
3091 .nb_ins = RTE_DIM(test_call4_prog),
3092 .prog_arg = {
3093 .type = RTE_BPF_ARG_PTR,
3094 .size = 2 * sizeof(struct dummy_offset),
3095 },
3096 .xsym = test_call4_xsym,
3097 .nb_xsym = RTE_DIM(test_call4_xsym),
3098 },
3099 .prepare = test_store1_prepare,
3100 .check_result = test_call4_check,
3101 /* for now don't support function calls on 32 bit platform */
3102 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3103 },
3104 {
3105 .name = "test_call5",
3106 .arg_sz = sizeof(struct dummy_offset),
3107 .prm = {
3108 .ins = test_call5_prog,
3109 .nb_ins = RTE_DIM(test_call5_prog),
3110 .prog_arg = {
3111 .type = RTE_BPF_ARG_PTR,
3112 .size = sizeof(struct dummy_offset),
3113 },
3114 .xsym = test_call5_xsym,
3115 .nb_xsym = RTE_DIM(test_call5_xsym),
3116 },
3117 .prepare = test_store1_prepare,
3118 .check_result = test_call5_check,
3119 /* for now don't support function calls on 32 bit platform */
3120 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3121 },
3122 {
3123 .name = "test_ld_mbuf1",
3124 .arg_sz = sizeof(struct dummy_mbuf),
3125 .prm = {
3126 .ins = test_ld_mbuf1_prog,
3127 .nb_ins = RTE_DIM(test_ld_mbuf1_prog),
3128 .prog_arg = {
3129 .type = RTE_BPF_ARG_PTR_MBUF,
3130 .buf_size = sizeof(struct dummy_mbuf),
3131 },
3132 },
3133 .prepare = test_ld_mbuf1_prepare,
3134 .check_result = test_ld_mbuf1_check,
3135 /* mbuf as input argument is not supported on 32 bit platform */
3136 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3137 },
3138 {
3139 .name = "test_ld_mbuf2",
3140 .arg_sz = sizeof(struct dummy_mbuf),
3141 .prm = {
3142 .ins = test_ld_mbuf1_prog,
3143 .nb_ins = RTE_DIM(test_ld_mbuf1_prog),
3144 .prog_arg = {
3145 .type = RTE_BPF_ARG_PTR_MBUF,
3146 .buf_size = sizeof(struct dummy_mbuf),
3147 },
3148 },
3149 .prepare = test_ld_mbuf2_prepare,
3150 .check_result = test_ld_mbuf2_check,
3151 /* mbuf as input argument is not supported on 32 bit platform */
3152 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3153 },
3154 {
3155 .name = "test_ld_mbuf3",
3156 .arg_sz = sizeof(struct dummy_mbuf),
3157 .prm = {
3158 .ins = test_ld_mbuf3_prog,
3159 .nb_ins = RTE_DIM(test_ld_mbuf3_prog),
3160 .prog_arg = {
3161 .type = RTE_BPF_ARG_PTR_MBUF,
3162 .buf_size = sizeof(struct dummy_mbuf),
3163 },
3164 },
3165 .prepare = test_ld_mbuf1_prepare,
3166 .check_result = test_ld_mbuf1_check,
3167 /* mbuf as input argument is not supported on 32 bit platform */
3168 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3169 },
3170 };
3171
3172 static int
run_test(const struct bpf_test * tst)3173 run_test(const struct bpf_test *tst)
3174 {
3175 int32_t ret, rv;
3176 int64_t rc;
3177 struct rte_bpf *bpf;
3178 struct rte_bpf_jit jit;
3179 uint8_t tbuf[tst->arg_sz];
3180
3181 printf("%s(%s) start\n", __func__, tst->name);
3182
3183 bpf = rte_bpf_load(&tst->prm);
3184 if (bpf == NULL) {
3185 printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
3186 __func__, __LINE__, rte_errno, strerror(rte_errno));
3187 return -1;
3188 }
3189
3190 tst->prepare(tbuf);
3191 rc = rte_bpf_exec(bpf, tbuf);
3192 ret = tst->check_result(rc, tbuf);
3193 if (ret != 0) {
3194 printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
3195 __func__, __LINE__, tst->name, ret, strerror(ret));
3196 }
3197
3198 /* repeat the same test with jit, when possible */
3199 rte_bpf_get_jit(bpf, &jit);
3200 if (jit.func != NULL) {
3201
3202 tst->prepare(tbuf);
3203 rc = jit.func(tbuf);
3204 rv = tst->check_result(rc, tbuf);
3205 ret |= rv;
3206 if (rv != 0) {
3207 printf("%s@%d: check_result(%s) failed, "
3208 "error: %d(%s);\n",
3209 __func__, __LINE__, tst->name,
3210 rv, strerror(ret));
3211 }
3212 }
3213
3214 rte_bpf_destroy(bpf);
3215 return ret;
3216
3217 }
3218
3219 static int
test_bpf(void)3220 test_bpf(void)
3221 {
3222 int32_t rc, rv;
3223 uint32_t i;
3224
3225 rc = 0;
3226 for (i = 0; i != RTE_DIM(tests); i++) {
3227 rv = run_test(tests + i);
3228 if (tests[i].allow_fail == 0)
3229 rc |= rv;
3230 }
3231
3232 return rc;
3233 }
3234
3235 REGISTER_TEST_COMMAND(bpf_autotest, test_bpf);
3236