New upstream version 18.08
[deb_dpdk.git] / test / test / test_bpf.c
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
18 #include "test.h"
19
20 /*
21  * Basic functional tests for librte_bpf.
22  * The main procedure - load eBPF program, execute it and
23  * compare restuls with expected values.
24  */
25
26 struct dummy_offset {
27         uint64_t u64;
28         uint32_t u32;
29         uint16_t u16;
30         uint8_t  u8;
31 };
32
33 struct dummy_vect8 {
34         struct dummy_offset in[8];
35         struct dummy_offset out[8];
36 };
37
38 #define TEST_FILL_1     0xDEADBEEF
39
40 #define TEST_MUL_1      21
41 #define TEST_MUL_2      -100
42
43 #define TEST_SHIFT_1    15
44 #define TEST_SHIFT_2    33
45
46 #define TEST_JCC_1      0
47 #define TEST_JCC_2      -123
48 #define TEST_JCC_3      5678
49 #define TEST_JCC_4      TEST_FILL_1
50
51 struct bpf_test {
52         const char *name;
53         size_t arg_sz;
54         struct rte_bpf_prm prm;
55         void (*prepare)(void *);
56         int (*check_result)(uint64_t, const void *);
57         uint32_t allow_fail;
58 };
59
60 /*
61  * Compare return value and result data with expected ones.
62  * Report a failure if they don't match.
63  */
64 static int
65 cmp_res(const char *func, uint64_t exp_rc, uint64_t ret_rc,
66         const void *exp_res, const void *ret_res, size_t res_sz)
67 {
68         int32_t ret;
69
70         ret = 0;
71         if (exp_rc != ret_rc) {
72                 printf("%s@%d: invalid return value, expected: 0x%" PRIx64
73                         ",result: 0x%" PRIx64 "\n",
74                         func, __LINE__, exp_rc, ret_rc);
75                 ret |= -1;
76         }
77
78         if (memcmp(exp_res, ret_res, res_sz) != 0) {
79                 printf("%s: invalid value\n", func);
80                 rte_memdump(stdout, "expected", exp_res, res_sz);
81                 rte_memdump(stdout, "result", ret_res, res_sz);
82                 ret |= -1;
83         }
84
85         return ret;
86 }
87
88 /* store immediate test-cases */
89 static const struct ebpf_insn test_store1_prog[] = {
90         {
91                 .code = (BPF_ST | BPF_MEM | BPF_B),
92                 .dst_reg = EBPF_REG_1,
93                 .off = offsetof(struct dummy_offset, u8),
94                 .imm = TEST_FILL_1,
95         },
96         {
97                 .code = (BPF_ST | BPF_MEM | BPF_H),
98                 .dst_reg = EBPF_REG_1,
99                 .off = offsetof(struct dummy_offset, u16),
100                 .imm = TEST_FILL_1,
101         },
102         {
103                 .code = (BPF_ST | BPF_MEM | BPF_W),
104                 .dst_reg = EBPF_REG_1,
105                 .off = offsetof(struct dummy_offset, u32),
106                 .imm = TEST_FILL_1,
107         },
108         {
109                 .code = (BPF_ST | BPF_MEM | EBPF_DW),
110                 .dst_reg = EBPF_REG_1,
111                 .off = offsetof(struct dummy_offset, u64),
112                 .imm = TEST_FILL_1,
113         },
114         /* return 1 */
115         {
116                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
117                 .dst_reg = EBPF_REG_0,
118                 .imm = 1,
119         },
120         {
121                 .code = (BPF_JMP | EBPF_EXIT),
122         },
123 };
124
125 static void
126 test_store1_prepare(void *arg)
127 {
128         struct dummy_offset *df;
129
130         df = arg;
131         memset(df, 0, sizeof(*df));
132 }
133
134 static int
135 test_store1_check(uint64_t rc, const void *arg)
136 {
137         const struct dummy_offset *dft;
138         struct dummy_offset dfe;
139
140         dft = arg;
141
142         memset(&dfe, 0, sizeof(dfe));
143         dfe.u64 = (int32_t)TEST_FILL_1;
144         dfe.u32 = dfe.u64;
145         dfe.u16 = dfe.u64;
146         dfe.u8 = dfe.u64;
147
148         return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
149 }
150
151 /* store register test-cases */
152 static const struct ebpf_insn test_store2_prog[] = {
153
154         {
155                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
156                 .dst_reg = EBPF_REG_2,
157                 .imm = TEST_FILL_1,
158         },
159         {
160                 .code = (BPF_STX | BPF_MEM | BPF_B),
161                 .dst_reg = EBPF_REG_1,
162                 .src_reg = EBPF_REG_2,
163                 .off = offsetof(struct dummy_offset, u8),
164         },
165         {
166                 .code = (BPF_STX | BPF_MEM | BPF_H),
167                 .dst_reg = EBPF_REG_1,
168                 .src_reg = EBPF_REG_2,
169                 .off = offsetof(struct dummy_offset, u16),
170         },
171         {
172                 .code = (BPF_STX | BPF_MEM | BPF_W),
173                 .dst_reg = EBPF_REG_1,
174                 .src_reg = EBPF_REG_2,
175                 .off = offsetof(struct dummy_offset, u32),
176         },
177         {
178                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
179                 .dst_reg = EBPF_REG_1,
180                 .src_reg = EBPF_REG_2,
181                 .off = offsetof(struct dummy_offset, u64),
182         },
183         /* return 1 */
184         {
185                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
186                 .dst_reg = EBPF_REG_0,
187                 .imm = 1,
188         },
189         {
190                 .code = (BPF_JMP | EBPF_EXIT),
191         },
192 };
193
194 /* load test-cases */
195 static const struct ebpf_insn test_load1_prog[] = {
196
197         {
198                 .code = (BPF_LDX | BPF_MEM | BPF_B),
199                 .dst_reg = EBPF_REG_2,
200                 .src_reg = EBPF_REG_1,
201                 .off = offsetof(struct dummy_offset, u8),
202         },
203         {
204                 .code = (BPF_LDX | BPF_MEM | BPF_H),
205                 .dst_reg = EBPF_REG_3,
206                 .src_reg = EBPF_REG_1,
207                 .off = offsetof(struct dummy_offset, u16),
208         },
209         {
210                 .code = (BPF_LDX | BPF_MEM | BPF_W),
211                 .dst_reg = EBPF_REG_4,
212                 .src_reg = EBPF_REG_1,
213                 .off = offsetof(struct dummy_offset, u32),
214         },
215         {
216                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
217                 .dst_reg = EBPF_REG_0,
218                 .src_reg = EBPF_REG_1,
219                 .off = offsetof(struct dummy_offset, u64),
220         },
221         /* return sum */
222         {
223                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
224                 .dst_reg = EBPF_REG_0,
225                 .src_reg = EBPF_REG_4,
226         },
227         {
228                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
229                 .dst_reg = EBPF_REG_0,
230                 .src_reg = EBPF_REG_3,
231         },
232         {
233                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
234                 .dst_reg = EBPF_REG_0,
235                 .src_reg = EBPF_REG_2,
236         },
237         {
238                 .code = (BPF_JMP | EBPF_EXIT),
239         },
240 };
241
242 static void
243 test_load1_prepare(void *arg)
244 {
245         struct dummy_offset *df;
246
247         df = arg;
248
249         memset(df, 0, sizeof(*df));
250         df->u64 = (int32_t)TEST_FILL_1;
251         df->u32 = df->u64;
252         df->u16 = df->u64;
253         df->u8 = df->u64;
254 }
255
256 static int
257 test_load1_check(uint64_t rc, const void *arg)
258 {
259         uint64_t v;
260         const struct dummy_offset *dft;
261
262         dft = arg;
263         v = dft->u64;
264         v += dft->u32;
265         v += dft->u16;
266         v += dft->u8;
267
268         return cmp_res(__func__, v, rc, dft, dft, sizeof(*dft));
269 }
270
271 /* alu mul test-cases */
272 static const struct ebpf_insn test_mul1_prog[] = {
273
274         {
275                 .code = (BPF_LDX | BPF_MEM | BPF_W),
276                 .dst_reg = EBPF_REG_2,
277                 .src_reg = EBPF_REG_1,
278                 .off = offsetof(struct dummy_vect8, in[0].u32),
279         },
280         {
281                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
282                 .dst_reg = EBPF_REG_3,
283                 .src_reg = EBPF_REG_1,
284                 .off = offsetof(struct dummy_vect8, in[1].u64),
285         },
286         {
287                 .code = (BPF_LDX | BPF_MEM | BPF_W),
288                 .dst_reg = EBPF_REG_4,
289                 .src_reg = EBPF_REG_1,
290                 .off = offsetof(struct dummy_vect8, in[2].u32),
291         },
292         {
293                 .code = (BPF_ALU | BPF_MUL | BPF_K),
294                 .dst_reg = EBPF_REG_2,
295                 .imm = TEST_MUL_1,
296         },
297         {
298                 .code = (EBPF_ALU64 | BPF_MUL | BPF_K),
299                 .dst_reg = EBPF_REG_3,
300                 .imm = TEST_MUL_2,
301         },
302         {
303                 .code = (BPF_ALU | BPF_MUL | BPF_X),
304                 .dst_reg = EBPF_REG_4,
305                 .src_reg = EBPF_REG_2,
306         },
307         {
308                 .code = (EBPF_ALU64 | BPF_MUL | BPF_X),
309                 .dst_reg = EBPF_REG_4,
310                 .src_reg = EBPF_REG_3,
311         },
312         {
313                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
314                 .dst_reg = EBPF_REG_1,
315                 .src_reg = EBPF_REG_2,
316                 .off = offsetof(struct dummy_vect8, out[0].u64),
317         },
318         {
319                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
320                 .dst_reg = EBPF_REG_1,
321                 .src_reg = EBPF_REG_3,
322                 .off = offsetof(struct dummy_vect8, out[1].u64),
323         },
324         {
325                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
326                 .dst_reg = EBPF_REG_1,
327                 .src_reg = EBPF_REG_4,
328                 .off = offsetof(struct dummy_vect8, out[2].u64),
329         },
330         /* return 1 */
331         {
332                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
333                 .dst_reg = EBPF_REG_0,
334                 .imm = 1,
335         },
336         {
337                 .code = (BPF_JMP | EBPF_EXIT),
338         },
339 };
340
341 static void
342 test_mul1_prepare(void *arg)
343 {
344         struct dummy_vect8 *dv;
345         uint64_t v;
346
347         dv = arg;
348
349         v = rte_rand();
350
351         memset(dv, 0, sizeof(*dv));
352         dv->in[0].u32 = v;
353         dv->in[1].u64 = v << 12 | v >> 6;
354         dv->in[2].u32 = -v;
355 }
356
357 static int
358 test_mul1_check(uint64_t rc, const void *arg)
359 {
360         uint64_t r2, r3, r4;
361         const struct dummy_vect8 *dvt;
362         struct dummy_vect8 dve;
363
364         dvt = arg;
365         memset(&dve, 0, sizeof(dve));
366
367         r2 = dvt->in[0].u32;
368         r3 = dvt->in[1].u64;
369         r4 = dvt->in[2].u32;
370
371         r2 = (uint32_t)r2 * TEST_MUL_1;
372         r3 *= TEST_MUL_2;
373         r4 = (uint32_t)(r4 * r2);
374         r4 *= r3;
375
376         dve.out[0].u64 = r2;
377         dve.out[1].u64 = r3;
378         dve.out[2].u64 = r4;
379
380         return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
381 }
382
383 /* alu shift test-cases */
384 static const struct ebpf_insn test_shift1_prog[] = {
385
386         {
387                 .code = (BPF_LDX | BPF_MEM | BPF_W),
388                 .dst_reg = EBPF_REG_2,
389                 .src_reg = EBPF_REG_1,
390                 .off = offsetof(struct dummy_vect8, in[0].u32),
391         },
392         {
393                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
394                 .dst_reg = EBPF_REG_3,
395                 .src_reg = EBPF_REG_1,
396                 .off = offsetof(struct dummy_vect8, in[1].u64),
397         },
398         {
399                 .code = (BPF_LDX | BPF_MEM | BPF_W),
400                 .dst_reg = EBPF_REG_4,
401                 .src_reg = EBPF_REG_1,
402                 .off = offsetof(struct dummy_vect8, in[2].u32),
403         },
404         {
405                 .code = (BPF_ALU | BPF_LSH | BPF_K),
406                 .dst_reg = EBPF_REG_2,
407                 .imm = TEST_SHIFT_1,
408         },
409         {
410                 .code = (EBPF_ALU64 | EBPF_ARSH | BPF_K),
411                 .dst_reg = EBPF_REG_3,
412                 .imm = TEST_SHIFT_2,
413         },
414         {
415                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
416                 .dst_reg = EBPF_REG_1,
417                 .src_reg = EBPF_REG_2,
418                 .off = offsetof(struct dummy_vect8, out[0].u64),
419         },
420         {
421                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
422                 .dst_reg = EBPF_REG_1,
423                 .src_reg = EBPF_REG_3,
424                 .off = offsetof(struct dummy_vect8, out[1].u64),
425         },
426         {
427                 .code = (BPF_ALU | BPF_RSH | BPF_X),
428                 .dst_reg = EBPF_REG_2,
429                 .src_reg = EBPF_REG_4,
430         },
431         {
432                 .code = (EBPF_ALU64 | BPF_LSH | BPF_X),
433                 .dst_reg = EBPF_REG_3,
434                 .src_reg = EBPF_REG_4,
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[2].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[3].u64),
447         },
448         {
449                 .code = (BPF_LDX | BPF_MEM | BPF_W),
450                 .dst_reg = EBPF_REG_2,
451                 .src_reg = EBPF_REG_1,
452                 .off = offsetof(struct dummy_vect8, in[0].u32),
453         },
454         {
455                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
456                 .dst_reg = EBPF_REG_3,
457                 .src_reg = EBPF_REG_1,
458                 .off = offsetof(struct dummy_vect8, in[1].u64),
459         },
460         {
461                 .code = (BPF_LDX | BPF_MEM | BPF_W),
462                 .dst_reg = EBPF_REG_4,
463                 .src_reg = EBPF_REG_1,
464                 .off = offsetof(struct dummy_vect8, in[2].u32),
465         },
466         {
467                 .code = (BPF_ALU | BPF_AND | BPF_K),
468                 .dst_reg = EBPF_REG_2,
469                 .imm = sizeof(uint64_t) * CHAR_BIT - 1,
470         },
471         {
472                 .code = (EBPF_ALU64 | EBPF_ARSH | BPF_X),
473                 .dst_reg = EBPF_REG_3,
474                 .src_reg = EBPF_REG_2,
475         },
476         {
477                 .code = (BPF_ALU | BPF_AND | BPF_K),
478                 .dst_reg = EBPF_REG_2,
479                 .imm = sizeof(uint32_t) * CHAR_BIT - 1,
480         },
481         {
482                 .code = (BPF_ALU | BPF_LSH | BPF_X),
483                 .dst_reg = EBPF_REG_4,
484                 .src_reg = EBPF_REG_2,
485         },
486         {
487                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
488                 .dst_reg = EBPF_REG_1,
489                 .src_reg = EBPF_REG_4,
490                 .off = offsetof(struct dummy_vect8, out[4].u64),
491         },
492         {
493                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
494                 .dst_reg = EBPF_REG_1,
495                 .src_reg = EBPF_REG_3,
496                 .off = offsetof(struct dummy_vect8, out[5].u64),
497         },
498         /* return 1 */
499         {
500                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
501                 .dst_reg = EBPF_REG_0,
502                 .imm = 1,
503         },
504         {
505                 .code = (BPF_JMP | EBPF_EXIT),
506         },
507 };
508
509 static void
510 test_shift1_prepare(void *arg)
511 {
512         struct dummy_vect8 *dv;
513         uint64_t v;
514
515         dv = arg;
516
517         v = rte_rand();
518
519         memset(dv, 0, sizeof(*dv));
520         dv->in[0].u32 = v;
521         dv->in[1].u64 = v << 12 | v >> 6;
522         dv->in[2].u32 = (-v ^ 5);
523 }
524
525 static int
526 test_shift1_check(uint64_t rc, const void *arg)
527 {
528         uint64_t r2, r3, r4;
529         const struct dummy_vect8 *dvt;
530         struct dummy_vect8 dve;
531
532         dvt = arg;
533         memset(&dve, 0, sizeof(dve));
534
535         r2 = dvt->in[0].u32;
536         r3 = dvt->in[1].u64;
537         r4 = dvt->in[2].u32;
538
539         r2 = (uint32_t)r2 << TEST_SHIFT_1;
540         r3 = (int64_t)r3 >> TEST_SHIFT_2;
541
542         dve.out[0].u64 = r2;
543         dve.out[1].u64 = r3;
544
545         r2 = (uint32_t)r2 >> r4;
546         r3 <<= r4;
547
548         dve.out[2].u64 = r2;
549         dve.out[3].u64 = r3;
550
551         r2 = dvt->in[0].u32;
552         r3 = dvt->in[1].u64;
553         r4 = dvt->in[2].u32;
554
555         r2 &= sizeof(uint64_t) * CHAR_BIT - 1;
556         r3 = (int64_t)r3 >> r2;
557         r2 &= sizeof(uint32_t) * CHAR_BIT - 1;
558         r4 = (uint32_t)r4 << r2;
559
560         dve.out[4].u64 = r4;
561         dve.out[5].u64 = r3;
562
563         return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
564 }
565
566 /* jmp test-cases */
567 static const struct ebpf_insn test_jump1_prog[] = {
568
569         [0] = {
570                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
571                 .dst_reg = EBPF_REG_0,
572                 .imm = 0,
573         },
574         [1] = {
575                 .code = (BPF_LDX | BPF_MEM | BPF_W),
576                 .dst_reg = EBPF_REG_2,
577                 .src_reg = EBPF_REG_1,
578                 .off = offsetof(struct dummy_vect8, in[0].u32),
579         },
580         [2] = {
581                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
582                 .dst_reg = EBPF_REG_3,
583                 .src_reg = EBPF_REG_1,
584                 .off = offsetof(struct dummy_vect8, in[0].u64),
585         },
586         [3] = {
587                 .code = (BPF_LDX | BPF_MEM | BPF_W),
588                 .dst_reg = EBPF_REG_4,
589                 .src_reg = EBPF_REG_1,
590                 .off = offsetof(struct dummy_vect8, in[1].u32),
591         },
592         [4] = {
593                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
594                 .dst_reg = EBPF_REG_5,
595                 .src_reg = EBPF_REG_1,
596                 .off = offsetof(struct dummy_vect8, in[1].u64),
597         },
598         [5] = {
599                 .code = (BPF_JMP | BPF_JEQ | BPF_K),
600                 .dst_reg = EBPF_REG_2,
601                 .imm = TEST_JCC_1,
602                 .off = 8,
603         },
604         [6] = {
605                 .code = (BPF_JMP | EBPF_JSLE | BPF_K),
606                 .dst_reg = EBPF_REG_3,
607                 .imm = TEST_JCC_2,
608                 .off = 9,
609         },
610         [7] = {
611                 .code = (BPF_JMP | BPF_JGT | BPF_K),
612                 .dst_reg = EBPF_REG_4,
613                 .imm = TEST_JCC_3,
614                 .off = 10,
615         },
616         [8] = {
617                 .code = (BPF_JMP | BPF_JSET | BPF_K),
618                 .dst_reg = EBPF_REG_5,
619                 .imm = TEST_JCC_4,
620                 .off = 11,
621         },
622         [9] = {
623                 .code = (BPF_JMP | EBPF_JNE | BPF_X),
624                 .dst_reg = EBPF_REG_2,
625                 .src_reg = EBPF_REG_3,
626                 .off = 12,
627         },
628         [10] = {
629                 .code = (BPF_JMP | EBPF_JSGT | BPF_X),
630                 .dst_reg = EBPF_REG_2,
631                 .src_reg = EBPF_REG_4,
632                 .off = 13,
633         },
634         [11] = {
635                 .code = (BPF_JMP | EBPF_JLE | BPF_X),
636                 .dst_reg = EBPF_REG_2,
637                 .src_reg = EBPF_REG_5,
638                 .off = 14,
639         },
640         [12] = {
641                 .code = (BPF_JMP | BPF_JSET | BPF_X),
642                 .dst_reg = EBPF_REG_3,
643                 .src_reg = EBPF_REG_5,
644                 .off = 15,
645         },
646         [13] = {
647                 .code = (BPF_JMP | EBPF_EXIT),
648         },
649         [14] = {
650                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
651                 .dst_reg = EBPF_REG_0,
652                 .imm = 0x1,
653         },
654         [15] = {
655                 .code = (BPF_JMP | BPF_JA),
656                 .off = -10,
657         },
658         [16] = {
659                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
660                 .dst_reg = EBPF_REG_0,
661                 .imm = 0x2,
662         },
663         [17] = {
664                 .code = (BPF_JMP | BPF_JA),
665                 .off = -11,
666         },
667         [18] = {
668                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
669                 .dst_reg = EBPF_REG_0,
670                 .imm = 0x4,
671         },
672         [19] = {
673                 .code = (BPF_JMP | BPF_JA),
674                 .off = -12,
675         },
676         [20] = {
677                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
678                 .dst_reg = EBPF_REG_0,
679                 .imm = 0x8,
680         },
681         [21] = {
682                 .code = (BPF_JMP | BPF_JA),
683                 .off = -13,
684         },
685         [22] = {
686                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
687                 .dst_reg = EBPF_REG_0,
688                 .imm = 0x10,
689         },
690         [23] = {
691                 .code = (BPF_JMP | BPF_JA),
692                 .off = -14,
693         },
694         [24] = {
695                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
696                 .dst_reg = EBPF_REG_0,
697                 .imm = 0x20,
698         },
699         [25] = {
700                 .code = (BPF_JMP | BPF_JA),
701                 .off = -15,
702         },
703         [26] = {
704                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
705                 .dst_reg = EBPF_REG_0,
706                 .imm = 0x40,
707         },
708         [27] = {
709                 .code = (BPF_JMP | BPF_JA),
710                 .off = -16,
711         },
712         [28] = {
713                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
714                 .dst_reg = EBPF_REG_0,
715                 .imm = 0x80,
716         },
717         [29] = {
718                 .code = (BPF_JMP | BPF_JA),
719                 .off = -17,
720         },
721 };
722
723 static void
724 test_jump1_prepare(void *arg)
725 {
726         struct dummy_vect8 *dv;
727         uint64_t v1, v2;
728
729         dv = arg;
730
731         v1 = rte_rand();
732         v2 = rte_rand();
733
734         memset(dv, 0, sizeof(*dv));
735         dv->in[0].u64 = v1;
736         dv->in[1].u64 = v2;
737         dv->in[0].u32 = (v1 << 12) + (v2 >> 6);
738         dv->in[1].u32 = (v2 << 12) - (v1 >> 6);
739 }
740
741 static int
742 test_jump1_check(uint64_t rc, const void *arg)
743 {
744         uint64_t r2, r3, r4, r5, rv;
745         const struct dummy_vect8 *dvt;
746
747         dvt = arg;
748
749         rv = 0;
750         r2 = dvt->in[0].u32;
751         r3 = dvt->in[0].u64;
752         r4 = dvt->in[1].u32;
753         r5 = dvt->in[1].u64;
754
755         if (r2 == TEST_JCC_1)
756                 rv |= 0x1;
757         if ((int64_t)r3 <= TEST_JCC_2)
758                 rv |= 0x2;
759         if (r4 > TEST_JCC_3)
760                 rv |= 0x4;
761         if (r5 & TEST_JCC_4)
762                 rv |= 0x8;
763         if (r2 != r3)
764                 rv |= 0x10;
765         if ((int64_t)r2 > (int64_t)r4)
766                 rv |= 0x20;
767         if (r2 <= r5)
768                 rv |= 0x40;
769         if (r3 & r5)
770                 rv |= 0x80;
771
772         return cmp_res(__func__, rv, rc, &rv, &rc, sizeof(rv));
773 }
774
775 /* alu (add, sub, and, or, xor, neg)  test-cases */
776 static const struct ebpf_insn test_alu1_prog[] = {
777
778         {
779                 .code = (BPF_LDX | BPF_MEM | BPF_W),
780                 .dst_reg = EBPF_REG_2,
781                 .src_reg = EBPF_REG_1,
782                 .off = offsetof(struct dummy_vect8, in[0].u32),
783         },
784         {
785                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
786                 .dst_reg = EBPF_REG_3,
787                 .src_reg = EBPF_REG_1,
788                 .off = offsetof(struct dummy_vect8, in[0].u64),
789         },
790         {
791                 .code = (BPF_LDX | BPF_MEM | BPF_W),
792                 .dst_reg = EBPF_REG_4,
793                 .src_reg = EBPF_REG_1,
794                 .off = offsetof(struct dummy_vect8, in[1].u32),
795         },
796         {
797                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
798                 .dst_reg = EBPF_REG_5,
799                 .src_reg = EBPF_REG_1,
800                 .off = offsetof(struct dummy_vect8, in[1].u64),
801         },
802         {
803                 .code = (BPF_ALU | BPF_AND | BPF_K),
804                 .dst_reg = EBPF_REG_2,
805                 .imm = TEST_FILL_1,
806         },
807         {
808                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
809                 .dst_reg = EBPF_REG_3,
810                 .imm = TEST_FILL_1,
811         },
812         {
813                 .code = (BPF_ALU | BPF_XOR | BPF_K),
814                 .dst_reg = EBPF_REG_4,
815                 .imm = TEST_FILL_1,
816         },
817         {
818                 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
819                 .dst_reg = EBPF_REG_5,
820                 .imm = TEST_FILL_1,
821         },
822         {
823                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
824                 .dst_reg = EBPF_REG_1,
825                 .src_reg = EBPF_REG_2,
826                 .off = offsetof(struct dummy_vect8, out[0].u64),
827         },
828         {
829                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
830                 .dst_reg = EBPF_REG_1,
831                 .src_reg = EBPF_REG_3,
832                 .off = offsetof(struct dummy_vect8, out[1].u64),
833         },
834         {
835                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
836                 .dst_reg = EBPF_REG_1,
837                 .src_reg = EBPF_REG_4,
838                 .off = offsetof(struct dummy_vect8, out[2].u64),
839         },
840         {
841                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
842                 .dst_reg = EBPF_REG_1,
843                 .src_reg = EBPF_REG_5,
844                 .off = offsetof(struct dummy_vect8, out[3].u64),
845         },
846         {
847                 .code = (BPF_ALU | BPF_OR | BPF_X),
848                 .dst_reg = EBPF_REG_2,
849                 .src_reg = EBPF_REG_3,
850         },
851         {
852                 .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
853                 .dst_reg = EBPF_REG_3,
854                 .src_reg = EBPF_REG_4,
855         },
856         {
857                 .code = (BPF_ALU | BPF_SUB | BPF_X),
858                 .dst_reg = EBPF_REG_4,
859                 .src_reg = EBPF_REG_5,
860         },
861         {
862                 .code = (EBPF_ALU64 | BPF_AND | BPF_X),
863                 .dst_reg = EBPF_REG_5,
864                 .src_reg = EBPF_REG_2,
865         },
866         {
867                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
868                 .dst_reg = EBPF_REG_1,
869                 .src_reg = EBPF_REG_2,
870                 .off = offsetof(struct dummy_vect8, out[4].u64),
871         },
872         {
873                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
874                 .dst_reg = EBPF_REG_1,
875                 .src_reg = EBPF_REG_3,
876                 .off = offsetof(struct dummy_vect8, out[5].u64),
877         },
878         {
879                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
880                 .dst_reg = EBPF_REG_1,
881                 .src_reg = EBPF_REG_4,
882                 .off = offsetof(struct dummy_vect8, out[6].u64),
883         },
884         {
885                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
886                 .dst_reg = EBPF_REG_1,
887                 .src_reg = EBPF_REG_5,
888                 .off = offsetof(struct dummy_vect8, out[7].u64),
889         },
890         /* return (-r2 + (-r3)) */
891         {
892                 .code = (BPF_ALU | BPF_NEG),
893                 .dst_reg = EBPF_REG_2,
894         },
895         {
896                 .code = (EBPF_ALU64 | BPF_NEG),
897                 .dst_reg = EBPF_REG_3,
898         },
899         {
900                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
901                 .dst_reg = EBPF_REG_2,
902                 .src_reg = EBPF_REG_3,
903         },
904         {
905                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
906                 .dst_reg = EBPF_REG_0,
907                 .src_reg = EBPF_REG_2,
908         },
909         {
910                 .code = (BPF_JMP | EBPF_EXIT),
911         },
912 };
913
914 static int
915 test_alu1_check(uint64_t rc, const void *arg)
916 {
917         uint64_t r2, r3, r4, r5, rv;
918         const struct dummy_vect8 *dvt;
919         struct dummy_vect8 dve;
920
921         dvt = arg;
922         memset(&dve, 0, sizeof(dve));
923
924         r2 = dvt->in[0].u32;
925         r3 = dvt->in[0].u64;
926         r4 = dvt->in[1].u32;
927         r5 = dvt->in[1].u64;
928
929         r2 = (uint32_t)r2 & TEST_FILL_1;
930         r3 |= (int32_t) TEST_FILL_1;
931         r4 = (uint32_t)r4 ^ TEST_FILL_1;
932         r5 += (int32_t)TEST_FILL_1;
933
934         dve.out[0].u64 = r2;
935         dve.out[1].u64 = r3;
936         dve.out[2].u64 = r4;
937         dve.out[3].u64 = r5;
938
939         r2 = (uint32_t)r2 | (uint32_t)r3;
940         r3 ^= r4;
941         r4 = (uint32_t)r4 - (uint32_t)r5;
942         r5 &= r2;
943
944         dve.out[4].u64 = r2;
945         dve.out[5].u64 = r3;
946         dve.out[6].u64 = r4;
947         dve.out[7].u64 = r5;
948
949         r2 = -(int32_t)r2;
950         rv = (uint32_t)r2;
951         r3 = -r3;
952         rv += r3;
953
954         return cmp_res(__func__, rv, rc, dve.out, dvt->out, sizeof(dve.out));
955 }
956
957 /* endianness conversions (BE->LE/LE->BE)  test-cases */
958 static const struct ebpf_insn test_bele1_prog[] = {
959
960         {
961                 .code = (BPF_LDX | BPF_MEM | BPF_H),
962                 .dst_reg = EBPF_REG_2,
963                 .src_reg = EBPF_REG_1,
964                 .off = offsetof(struct dummy_vect8, in[0].u16),
965         },
966         {
967                 .code = (BPF_LDX | BPF_MEM | BPF_W),
968                 .dst_reg = EBPF_REG_3,
969                 .src_reg = EBPF_REG_1,
970                 .off = offsetof(struct dummy_vect8, in[0].u32),
971         },
972         {
973                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
974                 .dst_reg = EBPF_REG_4,
975                 .src_reg = EBPF_REG_1,
976                 .off = offsetof(struct dummy_vect8, in[0].u64),
977         },
978         {
979                 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
980                 .dst_reg = EBPF_REG_2,
981                 .imm = sizeof(uint16_t) * CHAR_BIT,
982         },
983         {
984                 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
985                 .dst_reg = EBPF_REG_3,
986                 .imm = sizeof(uint32_t) * CHAR_BIT,
987         },
988         {
989                 .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
990                 .dst_reg = EBPF_REG_4,
991                 .imm = sizeof(uint64_t) * CHAR_BIT,
992         },
993         {
994                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
995                 .dst_reg = EBPF_REG_1,
996                 .src_reg = EBPF_REG_2,
997                 .off = offsetof(struct dummy_vect8, out[0].u64),
998         },
999         {
1000                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1001                 .dst_reg = EBPF_REG_1,
1002                 .src_reg = EBPF_REG_3,
1003                 .off = offsetof(struct dummy_vect8, out[1].u64),
1004         },
1005         {
1006                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1007                 .dst_reg = EBPF_REG_1,
1008                 .src_reg = EBPF_REG_4,
1009                 .off = offsetof(struct dummy_vect8, out[2].u64),
1010         },
1011         {
1012                 .code = (BPF_LDX | BPF_MEM | BPF_H),
1013                 .dst_reg = EBPF_REG_2,
1014                 .src_reg = EBPF_REG_1,
1015                 .off = offsetof(struct dummy_vect8, in[0].u16),
1016         },
1017         {
1018                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1019                 .dst_reg = EBPF_REG_3,
1020                 .src_reg = EBPF_REG_1,
1021                 .off = offsetof(struct dummy_vect8, in[0].u32),
1022         },
1023         {
1024                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1025                 .dst_reg = EBPF_REG_4,
1026                 .src_reg = EBPF_REG_1,
1027                 .off = offsetof(struct dummy_vect8, in[0].u64),
1028         },
1029         {
1030                 .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1031                 .dst_reg = EBPF_REG_2,
1032                 .imm = sizeof(uint16_t) * CHAR_BIT,
1033         },
1034         {
1035                 .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1036                 .dst_reg = EBPF_REG_3,
1037                 .imm = sizeof(uint32_t) * CHAR_BIT,
1038         },
1039         {
1040                 .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1041                 .dst_reg = EBPF_REG_4,
1042                 .imm = sizeof(uint64_t) * CHAR_BIT,
1043         },
1044         {
1045                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1046                 .dst_reg = EBPF_REG_1,
1047                 .src_reg = EBPF_REG_2,
1048                 .off = offsetof(struct dummy_vect8, out[3].u64),
1049         },
1050         {
1051                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1052                 .dst_reg = EBPF_REG_1,
1053                 .src_reg = EBPF_REG_3,
1054                 .off = offsetof(struct dummy_vect8, out[4].u64),
1055         },
1056         {
1057                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1058                 .dst_reg = EBPF_REG_1,
1059                 .src_reg = EBPF_REG_4,
1060                 .off = offsetof(struct dummy_vect8, out[5].u64),
1061         },
1062         /* return 1 */
1063         {
1064                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
1065                 .dst_reg = EBPF_REG_0,
1066                 .imm = 1,
1067         },
1068         {
1069                 .code = (BPF_JMP | EBPF_EXIT),
1070         },
1071 };
1072
1073 static void
1074 test_bele1_prepare(void *arg)
1075 {
1076         struct dummy_vect8 *dv;
1077
1078         dv = arg;
1079
1080         memset(dv, 0, sizeof(*dv));
1081         dv->in[0].u64 = rte_rand();
1082         dv->in[0].u32 = dv->in[0].u64;
1083         dv->in[0].u16 = dv->in[0].u64;
1084 }
1085
1086 static int
1087 test_bele1_check(uint64_t rc, const void *arg)
1088 {
1089         uint64_t r2, r3, r4;
1090         const struct dummy_vect8 *dvt;
1091         struct dummy_vect8 dve;
1092
1093         dvt = arg;
1094         memset(&dve, 0, sizeof(dve));
1095
1096         r2 = dvt->in[0].u16;
1097         r3 = dvt->in[0].u32;
1098         r4 = dvt->in[0].u64;
1099
1100         r2 =  rte_cpu_to_be_16(r2);
1101         r3 =  rte_cpu_to_be_32(r3);
1102         r4 =  rte_cpu_to_be_64(r4);
1103
1104         dve.out[0].u64 = r2;
1105         dve.out[1].u64 = r3;
1106         dve.out[2].u64 = r4;
1107
1108         r2 = dvt->in[0].u16;
1109         r3 = dvt->in[0].u32;
1110         r4 = dvt->in[0].u64;
1111
1112         r2 =  rte_cpu_to_le_16(r2);
1113         r3 =  rte_cpu_to_le_32(r3);
1114         r4 =  rte_cpu_to_le_64(r4);
1115
1116         dve.out[3].u64 = r2;
1117         dve.out[4].u64 = r3;
1118         dve.out[5].u64 = r4;
1119
1120         return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
1121 }
1122
1123 /* atomic add test-cases */
1124 static const struct ebpf_insn test_xadd1_prog[] = {
1125
1126         {
1127                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1128                 .dst_reg = EBPF_REG_2,
1129                 .imm = 1,
1130         },
1131         {
1132                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1133                 .dst_reg = EBPF_REG_1,
1134                 .src_reg = EBPF_REG_2,
1135                 .off = offsetof(struct dummy_offset, u32),
1136         },
1137         {
1138                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1139                 .dst_reg = EBPF_REG_1,
1140                 .src_reg = EBPF_REG_2,
1141                 .off = offsetof(struct dummy_offset, u64),
1142         },
1143         {
1144                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1145                 .dst_reg = EBPF_REG_3,
1146                 .imm = -1,
1147         },
1148         {
1149                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1150                 .dst_reg = EBPF_REG_1,
1151                 .src_reg = EBPF_REG_3,
1152                 .off = offsetof(struct dummy_offset, u32),
1153         },
1154         {
1155                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1156                 .dst_reg = EBPF_REG_1,
1157                 .src_reg = EBPF_REG_3,
1158                 .off = offsetof(struct dummy_offset, u64),
1159         },
1160         {
1161                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1162                 .dst_reg = EBPF_REG_4,
1163                 .imm = TEST_FILL_1,
1164         },
1165         {
1166                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1167                 .dst_reg = EBPF_REG_1,
1168                 .src_reg = EBPF_REG_4,
1169                 .off = offsetof(struct dummy_offset, u32),
1170         },
1171         {
1172                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1173                 .dst_reg = EBPF_REG_1,
1174                 .src_reg = EBPF_REG_4,
1175                 .off = offsetof(struct dummy_offset, u64),
1176         },
1177         {
1178                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1179                 .dst_reg = EBPF_REG_5,
1180                 .imm = TEST_MUL_1,
1181         },
1182         {
1183                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1184                 .dst_reg = EBPF_REG_1,
1185                 .src_reg = EBPF_REG_5,
1186                 .off = offsetof(struct dummy_offset, u32),
1187         },
1188         {
1189                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1190                 .dst_reg = EBPF_REG_1,
1191                 .src_reg = EBPF_REG_5,
1192                 .off = offsetof(struct dummy_offset, u64),
1193         },
1194         {
1195                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1196                 .dst_reg = EBPF_REG_6,
1197                 .imm = TEST_MUL_2,
1198         },
1199         {
1200                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1201                 .dst_reg = EBPF_REG_1,
1202                 .src_reg = EBPF_REG_6,
1203                 .off = offsetof(struct dummy_offset, u32),
1204         },
1205         {
1206                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1207                 .dst_reg = EBPF_REG_1,
1208                 .src_reg = EBPF_REG_6,
1209                 .off = offsetof(struct dummy_offset, u64),
1210         },
1211         {
1212                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1213                 .dst_reg = EBPF_REG_7,
1214                 .imm = TEST_JCC_2,
1215         },
1216         {
1217                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1218                 .dst_reg = EBPF_REG_1,
1219                 .src_reg = EBPF_REG_7,
1220                 .off = offsetof(struct dummy_offset, u32),
1221         },
1222         {
1223                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1224                 .dst_reg = EBPF_REG_1,
1225                 .src_reg = EBPF_REG_7,
1226                 .off = offsetof(struct dummy_offset, u64),
1227         },
1228         {
1229                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1230                 .dst_reg = EBPF_REG_8,
1231                 .imm = TEST_JCC_3,
1232         },
1233         {
1234                 .code = (BPF_STX | EBPF_XADD | BPF_W),
1235                 .dst_reg = EBPF_REG_1,
1236                 .src_reg = EBPF_REG_8,
1237                 .off = offsetof(struct dummy_offset, u32),
1238         },
1239         {
1240                 .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1241                 .dst_reg = EBPF_REG_1,
1242                 .src_reg = EBPF_REG_8,
1243                 .off = offsetof(struct dummy_offset, u64),
1244         },
1245         /* return 1 */
1246         {
1247                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
1248                 .dst_reg = EBPF_REG_0,
1249                 .imm = 1,
1250         },
1251         {
1252                 .code = (BPF_JMP | EBPF_EXIT),
1253         },
1254 };
1255
1256 static int
1257 test_xadd1_check(uint64_t rc, const void *arg)
1258 {
1259         uint64_t rv;
1260         const struct dummy_offset *dft;
1261         struct dummy_offset dfe;
1262
1263         dft = arg;
1264         memset(&dfe, 0, sizeof(dfe));
1265
1266         rv = 1;
1267         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1268         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1269
1270         rv = -1;
1271         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1272         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1273
1274         rv = (int32_t)TEST_FILL_1;
1275         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1276         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1277
1278         rv = TEST_MUL_1;
1279         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1280         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1281
1282         rv = TEST_MUL_2;
1283         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1284         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1285
1286         rv = TEST_JCC_2;
1287         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1288         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1289
1290         rv = TEST_JCC_3;
1291         rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
1292         rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
1293
1294         return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
1295 }
1296
1297 /* alu div test-cases */
1298 static const struct ebpf_insn test_div1_prog[] = {
1299
1300         {
1301                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1302                 .dst_reg = EBPF_REG_2,
1303                 .src_reg = EBPF_REG_1,
1304                 .off = offsetof(struct dummy_vect8, in[0].u32),
1305         },
1306         {
1307                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1308                 .dst_reg = EBPF_REG_3,
1309                 .src_reg = EBPF_REG_1,
1310                 .off = offsetof(struct dummy_vect8, in[1].u64),
1311         },
1312         {
1313                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1314                 .dst_reg = EBPF_REG_4,
1315                 .src_reg = EBPF_REG_1,
1316                 .off = offsetof(struct dummy_vect8, in[2].u32),
1317         },
1318         {
1319                 .code = (BPF_ALU | BPF_DIV | BPF_K),
1320                 .dst_reg = EBPF_REG_2,
1321                 .imm = TEST_MUL_1,
1322         },
1323         {
1324                 .code = (EBPF_ALU64 | BPF_MOD | BPF_K),
1325                 .dst_reg = EBPF_REG_3,
1326                 .imm = TEST_MUL_2,
1327         },
1328         {
1329                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1330                 .dst_reg = EBPF_REG_2,
1331                 .imm = 1,
1332         },
1333         {
1334                 .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1335                 .dst_reg = EBPF_REG_3,
1336                 .imm = 1,
1337         },
1338         {
1339                 .code = (BPF_ALU | BPF_MOD | BPF_X),
1340                 .dst_reg = EBPF_REG_4,
1341                 .src_reg = EBPF_REG_2,
1342         },
1343         {
1344                 .code = (EBPF_ALU64 | BPF_DIV | BPF_X),
1345                 .dst_reg = EBPF_REG_4,
1346                 .src_reg = EBPF_REG_3,
1347         },
1348         {
1349                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1350                 .dst_reg = EBPF_REG_1,
1351                 .src_reg = EBPF_REG_2,
1352                 .off = offsetof(struct dummy_vect8, out[0].u64),
1353         },
1354         {
1355                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1356                 .dst_reg = EBPF_REG_1,
1357                 .src_reg = EBPF_REG_3,
1358                 .off = offsetof(struct dummy_vect8, out[1].u64),
1359         },
1360         {
1361                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1362                 .dst_reg = EBPF_REG_1,
1363                 .src_reg = EBPF_REG_4,
1364                 .off = offsetof(struct dummy_vect8, out[2].u64),
1365         },
1366         /* check that we can handle division by zero gracefully. */
1367         {
1368                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1369                 .dst_reg = EBPF_REG_2,
1370                 .src_reg = EBPF_REG_1,
1371                 .off = offsetof(struct dummy_vect8, in[3].u32),
1372         },
1373         {
1374                 .code = (BPF_ALU | BPF_DIV | BPF_X),
1375                 .dst_reg = EBPF_REG_4,
1376                 .src_reg = EBPF_REG_2,
1377         },
1378         /* return 1 */
1379         {
1380                 .code = (BPF_ALU | EBPF_MOV | BPF_K),
1381                 .dst_reg = EBPF_REG_0,
1382                 .imm = 1,
1383         },
1384         {
1385                 .code = (BPF_JMP | EBPF_EXIT),
1386         },
1387 };
1388
1389 static int
1390 test_div1_check(uint64_t rc, const void *arg)
1391 {
1392         uint64_t r2, r3, r4;
1393         const struct dummy_vect8 *dvt;
1394         struct dummy_vect8 dve;
1395
1396         dvt = arg;
1397         memset(&dve, 0, sizeof(dve));
1398
1399         r2 = dvt->in[0].u32;
1400         r3 = dvt->in[1].u64;
1401         r4 = dvt->in[2].u32;
1402
1403         r2 = (uint32_t)r2 / TEST_MUL_1;
1404         r3 %= TEST_MUL_2;
1405         r2 |= 1;
1406         r3 |= 1;
1407         r4 = (uint32_t)(r4 % r2);
1408         r4 /= r3;
1409
1410         dve.out[0].u64 = r2;
1411         dve.out[1].u64 = r3;
1412         dve.out[2].u64 = r4;
1413
1414         /*
1415          * in the test prog we attempted to divide by zero.
1416          * so return value should return 0.
1417          */
1418         return cmp_res(__func__, 0, rc, dve.out, dvt->out, sizeof(dve.out));
1419 }
1420
1421 /* call test-cases */
1422 static const struct ebpf_insn test_call1_prog[] = {
1423
1424         {
1425                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1426                 .dst_reg = EBPF_REG_2,
1427                 .src_reg = EBPF_REG_1,
1428                 .off = offsetof(struct dummy_offset, u32),
1429         },
1430         {
1431                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1432                 .dst_reg = EBPF_REG_3,
1433                 .src_reg = EBPF_REG_1,
1434                 .off = offsetof(struct dummy_offset, u64),
1435         },
1436         {
1437                 .code = (BPF_STX | BPF_MEM | BPF_W),
1438                 .dst_reg = EBPF_REG_10,
1439                 .src_reg = EBPF_REG_2,
1440                 .off = -4,
1441         },
1442         {
1443                 .code = (BPF_STX | BPF_MEM | EBPF_DW),
1444                 .dst_reg = EBPF_REG_10,
1445                 .src_reg = EBPF_REG_3,
1446                 .off = -16,
1447         },
1448         {
1449                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1450                 .dst_reg = EBPF_REG_2,
1451                 .src_reg = EBPF_REG_10,
1452         },
1453         {
1454                 .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
1455                 .dst_reg = EBPF_REG_2,
1456                 .imm = 4,
1457         },
1458         {
1459                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1460                 .dst_reg = EBPF_REG_3,
1461                 .src_reg = EBPF_REG_10,
1462         },
1463         {
1464                 .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
1465                 .dst_reg = EBPF_REG_3,
1466                 .imm = 16,
1467         },
1468         {
1469                 .code = (BPF_JMP | EBPF_CALL),
1470                 .imm = 0,
1471         },
1472         {
1473                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1474                 .dst_reg = EBPF_REG_2,
1475                 .src_reg = EBPF_REG_10,
1476                 .off = -4,
1477         },
1478         {
1479                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1480                 .dst_reg = EBPF_REG_0,
1481                 .src_reg = EBPF_REG_10,
1482                 .off = -16
1483         },
1484         {
1485                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1486                 .dst_reg = EBPF_REG_0,
1487                 .src_reg = EBPF_REG_2,
1488         },
1489         {
1490                 .code = (BPF_JMP | EBPF_EXIT),
1491         },
1492 };
1493
1494 static void
1495 dummy_func1(const void *p, uint32_t *v32, uint64_t *v64)
1496 {
1497         const struct dummy_offset *dv;
1498
1499         dv = p;
1500
1501         v32[0] += dv->u16;
1502         v64[0] += dv->u8;
1503 }
1504
1505 static int
1506 test_call1_check(uint64_t rc, const void *arg)
1507 {
1508         uint32_t v32;
1509         uint64_t v64;
1510         const struct dummy_offset *dv;
1511
1512         dv = arg;
1513
1514         v32 = dv->u32;
1515         v64 = dv->u64;
1516         dummy_func1(arg, &v32, &v64);
1517         v64 += v32;
1518
1519         if (v64 != rc) {
1520                 printf("%s@%d: invalid return value "
1521                         "expected=0x%" PRIx64 ", actual=0x%" PRIx64 "\n",
1522                         __func__, __LINE__, v64, rc);
1523                 return -1;
1524         }
1525         return 0;
1526         return cmp_res(__func__, v64, rc, dv, dv, sizeof(*dv));
1527 }
1528
1529 static const struct rte_bpf_xsym test_call1_xsym[] = {
1530         {
1531                 .name = RTE_STR(dummy_func1),
1532                 .type = RTE_BPF_XTYPE_FUNC,
1533                 .func = {
1534                         .val = (void *)dummy_func1,
1535                         .nb_args = 3,
1536                         .args = {
1537                                 [0] = {
1538                                         .type = RTE_BPF_ARG_PTR,
1539                                         .size = sizeof(struct dummy_offset),
1540                                 },
1541                                 [1] = {
1542                                         .type = RTE_BPF_ARG_PTR,
1543                                         .size = sizeof(uint32_t),
1544                                 },
1545                                 [2] = {
1546                                         .type = RTE_BPF_ARG_PTR,
1547                                         .size = sizeof(uint64_t),
1548                                 },
1549                         },
1550                 },
1551         },
1552 };
1553
1554 static const struct ebpf_insn test_call2_prog[] = {
1555
1556         {
1557                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1558                 .dst_reg = EBPF_REG_1,
1559                 .src_reg = EBPF_REG_10,
1560         },
1561         {
1562                 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1563                 .dst_reg = EBPF_REG_1,
1564                 .imm = -(int32_t)sizeof(struct dummy_offset),
1565         },
1566         {
1567                 .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1568                 .dst_reg = EBPF_REG_2,
1569                 .src_reg = EBPF_REG_10,
1570         },
1571         {
1572                 .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1573                 .dst_reg = EBPF_REG_2,
1574                 .imm = -2 * (int32_t)sizeof(struct dummy_offset),
1575         },
1576         {
1577                 .code = (BPF_JMP | EBPF_CALL),
1578                 .imm = 0,
1579         },
1580         {
1581                 .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1582                 .dst_reg = EBPF_REG_1,
1583                 .src_reg = EBPF_REG_10,
1584                 .off = -(int32_t)(sizeof(struct dummy_offset) -
1585                         offsetof(struct dummy_offset, u64)),
1586         },
1587         {
1588                 .code = (BPF_LDX | BPF_MEM | BPF_W),
1589                 .dst_reg = EBPF_REG_0,
1590                 .src_reg = EBPF_REG_10,
1591                 .off = -(int32_t)(sizeof(struct dummy_offset) -
1592                         offsetof(struct dummy_offset, u32)),
1593         },
1594         {
1595                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1596                 .dst_reg = EBPF_REG_0,
1597                 .src_reg = EBPF_REG_1,
1598         },
1599         {
1600                 .code = (BPF_LDX | BPF_MEM | BPF_H),
1601                 .dst_reg = EBPF_REG_1,
1602                 .src_reg = EBPF_REG_10,
1603                 .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
1604                         offsetof(struct dummy_offset, u16)),
1605         },
1606         {
1607                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1608                 .dst_reg = EBPF_REG_0,
1609                 .src_reg = EBPF_REG_1,
1610         },
1611         {
1612                 .code = (BPF_LDX | BPF_MEM | BPF_B),
1613                 .dst_reg = EBPF_REG_1,
1614                 .src_reg = EBPF_REG_10,
1615                 .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
1616                         offsetof(struct dummy_offset, u8)),
1617         },
1618         {
1619                 .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1620                 .dst_reg = EBPF_REG_0,
1621                 .src_reg = EBPF_REG_1,
1622         },
1623         {
1624                 .code = (BPF_JMP | EBPF_EXIT),
1625         },
1626
1627 };
1628
1629 static void
1630 dummy_func2(struct dummy_offset *a, struct dummy_offset *b)
1631 {
1632         uint64_t v;
1633
1634         v = 0;
1635         a->u64 = v++;
1636         a->u32 = v++;
1637         a->u16 = v++;
1638         a->u8 = v++;
1639         b->u64 = v++;
1640         b->u32 = v++;
1641         b->u16 = v++;
1642         b->u8 = v++;
1643 }
1644
1645 static int
1646 test_call2_check(uint64_t rc, const void *arg)
1647 {
1648         uint64_t v;
1649         struct dummy_offset a, b;
1650
1651         RTE_SET_USED(arg);
1652
1653         dummy_func2(&a, &b);
1654         v = a.u64 + a.u32 + b.u16 + b.u8;
1655
1656         if (v != rc) {
1657                 printf("%s@%d: invalid return value "
1658                         "expected=0x%" PRIx64 ", actual=0x%" PRIx64 "\n",
1659                         __func__, __LINE__, v, rc);
1660                 return -1;
1661         }
1662         return 0;
1663 }
1664
1665 static const struct rte_bpf_xsym test_call2_xsym[] = {
1666         {
1667                 .name = RTE_STR(dummy_func2),
1668                 .type = RTE_BPF_XTYPE_FUNC,
1669                 .func = {
1670                         .val = (void *)dummy_func2,
1671                         .nb_args = 2,
1672                         .args = {
1673                                 [0] = {
1674                                         .type = RTE_BPF_ARG_PTR,
1675                                         .size = sizeof(struct dummy_offset),
1676                                 },
1677                                 [1] = {
1678                                         .type = RTE_BPF_ARG_PTR,
1679                                         .size = sizeof(struct dummy_offset),
1680                                 },
1681                         },
1682                 },
1683         },
1684 };
1685
1686 static const struct bpf_test tests[] = {
1687         {
1688                 .name = "test_store1",
1689                 .arg_sz = sizeof(struct dummy_offset),
1690                 .prm = {
1691                         .ins = test_store1_prog,
1692                         .nb_ins = RTE_DIM(test_store1_prog),
1693                         .prog_arg = {
1694                                 .type = RTE_BPF_ARG_PTR,
1695                                 .size = sizeof(struct dummy_offset),
1696                         },
1697                 },
1698                 .prepare = test_store1_prepare,
1699                 .check_result = test_store1_check,
1700         },
1701         {
1702                 .name = "test_store2",
1703                 .arg_sz = sizeof(struct dummy_offset),
1704                 .prm = {
1705                         .ins = test_store2_prog,
1706                         .nb_ins = RTE_DIM(test_store2_prog),
1707                         .prog_arg = {
1708                                 .type = RTE_BPF_ARG_PTR,
1709                                 .size = sizeof(struct dummy_offset),
1710                         },
1711                 },
1712                 .prepare = test_store1_prepare,
1713                 .check_result = test_store1_check,
1714         },
1715         {
1716                 .name = "test_load1",
1717                 .arg_sz = sizeof(struct dummy_offset),
1718                 .prm = {
1719                         .ins = test_load1_prog,
1720                         .nb_ins = RTE_DIM(test_load1_prog),
1721                         .prog_arg = {
1722                                 .type = RTE_BPF_ARG_PTR,
1723                                 .size = sizeof(struct dummy_offset),
1724                         },
1725                 },
1726                 .prepare = test_load1_prepare,
1727                 .check_result = test_load1_check,
1728         },
1729         {
1730                 .name = "test_mul1",
1731                 .arg_sz = sizeof(struct dummy_vect8),
1732                 .prm = {
1733                         .ins = test_mul1_prog,
1734                         .nb_ins = RTE_DIM(test_mul1_prog),
1735                         .prog_arg = {
1736                                 .type = RTE_BPF_ARG_PTR,
1737                                 .size = sizeof(struct dummy_vect8),
1738                         },
1739                 },
1740                 .prepare = test_mul1_prepare,
1741                 .check_result = test_mul1_check,
1742         },
1743         {
1744                 .name = "test_shift1",
1745                 .arg_sz = sizeof(struct dummy_vect8),
1746                 .prm = {
1747                         .ins = test_shift1_prog,
1748                         .nb_ins = RTE_DIM(test_shift1_prog),
1749                         .prog_arg = {
1750                                 .type = RTE_BPF_ARG_PTR,
1751                                 .size = sizeof(struct dummy_vect8),
1752                         },
1753                 },
1754                 .prepare = test_shift1_prepare,
1755                 .check_result = test_shift1_check,
1756         },
1757         {
1758                 .name = "test_jump1",
1759                 .arg_sz = sizeof(struct dummy_vect8),
1760                 .prm = {
1761                         .ins = test_jump1_prog,
1762                         .nb_ins = RTE_DIM(test_jump1_prog),
1763                         .prog_arg = {
1764                                 .type = RTE_BPF_ARG_PTR,
1765                                 .size = sizeof(struct dummy_vect8),
1766                         },
1767                 },
1768                 .prepare = test_jump1_prepare,
1769                 .check_result = test_jump1_check,
1770         },
1771         {
1772                 .name = "test_alu1",
1773                 .arg_sz = sizeof(struct dummy_vect8),
1774                 .prm = {
1775                         .ins = test_alu1_prog,
1776                         .nb_ins = RTE_DIM(test_alu1_prog),
1777                         .prog_arg = {
1778                                 .type = RTE_BPF_ARG_PTR,
1779                                 .size = sizeof(struct dummy_vect8),
1780                         },
1781                 },
1782                 .prepare = test_jump1_prepare,
1783                 .check_result = test_alu1_check,
1784         },
1785         {
1786                 .name = "test_bele1",
1787                 .arg_sz = sizeof(struct dummy_vect8),
1788                 .prm = {
1789                         .ins = test_bele1_prog,
1790                         .nb_ins = RTE_DIM(test_bele1_prog),
1791                         .prog_arg = {
1792                                 .type = RTE_BPF_ARG_PTR,
1793                                 .size = sizeof(struct dummy_vect8),
1794                         },
1795                 },
1796                 .prepare = test_bele1_prepare,
1797                 .check_result = test_bele1_check,
1798         },
1799         {
1800                 .name = "test_xadd1",
1801                 .arg_sz = sizeof(struct dummy_offset),
1802                 .prm = {
1803                         .ins = test_xadd1_prog,
1804                         .nb_ins = RTE_DIM(test_xadd1_prog),
1805                         .prog_arg = {
1806                                 .type = RTE_BPF_ARG_PTR,
1807                                 .size = sizeof(struct dummy_offset),
1808                         },
1809                 },
1810                 .prepare = test_store1_prepare,
1811                 .check_result = test_xadd1_check,
1812         },
1813         {
1814                 .name = "test_div1",
1815                 .arg_sz = sizeof(struct dummy_vect8),
1816                 .prm = {
1817                         .ins = test_div1_prog,
1818                         .nb_ins = RTE_DIM(test_div1_prog),
1819                         .prog_arg = {
1820                                 .type = RTE_BPF_ARG_PTR,
1821                                 .size = sizeof(struct dummy_vect8),
1822                         },
1823                 },
1824                 .prepare = test_mul1_prepare,
1825                 .check_result = test_div1_check,
1826         },
1827         {
1828                 .name = "test_call1",
1829                 .arg_sz = sizeof(struct dummy_offset),
1830                 .prm = {
1831                         .ins = test_call1_prog,
1832                         .nb_ins = RTE_DIM(test_call1_prog),
1833                         .prog_arg = {
1834                                 .type = RTE_BPF_ARG_PTR,
1835                                 .size = sizeof(struct dummy_offset),
1836                         },
1837                         .xsym = test_call1_xsym,
1838                         .nb_xsym = RTE_DIM(test_call1_xsym),
1839                 },
1840                 .prepare = test_load1_prepare,
1841                 .check_result = test_call1_check,
1842                 /* for now don't support function calls on 32 bit platform */
1843                 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
1844         },
1845         {
1846                 .name = "test_call2",
1847                 .arg_sz = sizeof(struct dummy_offset),
1848                 .prm = {
1849                         .ins = test_call2_prog,
1850                         .nb_ins = RTE_DIM(test_call2_prog),
1851                         .prog_arg = {
1852                                 .type = RTE_BPF_ARG_PTR,
1853                                 .size = sizeof(struct dummy_offset),
1854                         },
1855                         .xsym = test_call2_xsym,
1856                         .nb_xsym = RTE_DIM(test_call2_xsym),
1857                 },
1858                 .prepare = test_store1_prepare,
1859                 .check_result = test_call2_check,
1860                 /* for now don't support function calls on 32 bit platform */
1861                 .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
1862         },
1863 };
1864
1865 static int
1866 run_test(const struct bpf_test *tst)
1867 {
1868         int32_t ret, rv;
1869         int64_t rc;
1870         struct rte_bpf *bpf;
1871         struct rte_bpf_jit jit;
1872         uint8_t tbuf[tst->arg_sz];
1873
1874         printf("%s(%s) start\n", __func__, tst->name);
1875
1876         bpf = rte_bpf_load(&tst->prm);
1877         if (bpf == NULL) {
1878                 printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
1879                         __func__, __LINE__, rte_errno, strerror(rte_errno));
1880                 return -1;
1881         }
1882
1883         tst->prepare(tbuf);
1884
1885         rc = rte_bpf_exec(bpf, tbuf);
1886         ret = tst->check_result(rc, tbuf);
1887         if (ret != 0) {
1888                 printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
1889                         __func__, __LINE__, tst->name, ret, strerror(ret));
1890         }
1891
1892         rte_bpf_get_jit(bpf, &jit);
1893         if (jit.func == NULL)
1894                 return 0;
1895
1896         tst->prepare(tbuf);
1897         rc = jit.func(tbuf);
1898         rv = tst->check_result(rc, tbuf);
1899         ret |= rv;
1900         if (rv != 0) {
1901                 printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
1902                         __func__, __LINE__, tst->name, rv, strerror(ret));
1903         }
1904
1905         rte_bpf_destroy(bpf);
1906         return ret;
1907
1908 }
1909
1910 static int
1911 test_bpf(void)
1912 {
1913         int32_t rc, rv;
1914         uint32_t i;
1915
1916         rc = 0;
1917         for (i = 0; i != RTE_DIM(tests); i++) {
1918                 rv = run_test(tests + i);
1919                 if (tests[i].allow_fail == 0)
1920                         rc |= rv;
1921         }
1922
1923         return rc;
1924 }
1925
1926 REGISTER_TEST_COMMAND(bpf_autotest, test_bpf);