Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : : #include <stdint.h>
8 : : #include <inttypes.h>
9 : : #include <unistd.h>
10 : :
11 : : #include <rte_memory.h>
12 : : #include <rte_debug.h>
13 : : #include <rte_hexdump.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_random.h>
16 : : #include <rte_byteorder.h>
17 : : #include <rte_errno.h>
18 : :
19 : : #include "test.h"
20 : :
21 : : #if !defined(RTE_LIB_BPF)
22 : :
23 : : static int
24 : : test_bpf(void)
25 : : {
26 : : printf("BPF not supported, skipping test\n");
27 : : return TEST_SKIPPED;
28 : : }
29 : :
30 : : #else
31 : :
32 : : #include <rte_bpf.h>
33 : : #include <rte_ether.h>
34 : : #include <rte_ip.h>
35 : :
36 : :
37 : : /*
38 : : * Basic functional tests for librte_bpf.
39 : : * The main procedure - load eBPF program, execute it and
40 : : * compare results with expected values.
41 : : */
42 : :
43 : : struct dummy_offset {
44 : : RTE_ATOMIC(uint64_t) u64;
45 : : RTE_ATOMIC(uint32_t) u32;
46 : : uint16_t u16;
47 : : uint8_t u8;
48 : : };
49 : :
50 : : struct dummy_vect8 {
51 : : struct dummy_offset in[8];
52 : : struct dummy_offset out[8];
53 : : };
54 : :
55 : : struct dummy_net {
56 : : struct rte_ether_hdr eth_hdr;
57 : : struct rte_vlan_hdr vlan_hdr;
58 : : struct rte_ipv4_hdr ip_hdr;
59 : : };
60 : :
61 : : #define DUMMY_MBUF_NUM 2
62 : :
63 : : /* first mbuf in the packet, should always be at offset 0 */
64 : : struct dummy_mbuf {
65 : : struct rte_mbuf mb[DUMMY_MBUF_NUM];
66 : : uint8_t buf[DUMMY_MBUF_NUM][RTE_MBUF_DEFAULT_BUF_SIZE];
67 : : };
68 : :
69 : : #define TEST_FILL_1 0xDEADBEEF
70 : :
71 : : #define TEST_MUL_1 21
72 : : #define TEST_MUL_2 -100
73 : :
74 : : #define TEST_SHIFT_1 15
75 : : #define TEST_SHIFT_2 33
76 : :
77 : : #define TEST_SHIFT32_MASK (CHAR_BIT * sizeof(uint32_t) - 1)
78 : : #define TEST_SHIFT64_MASK (CHAR_BIT * sizeof(uint64_t) - 1)
79 : :
80 : : #define TEST_JCC_1 0
81 : : #define TEST_JCC_2 -123
82 : : #define TEST_JCC_3 5678
83 : : #define TEST_JCC_4 TEST_FILL_1
84 : :
85 : : #define TEST_IMM_1 UINT64_MAX
86 : : #define TEST_IMM_2 ((uint64_t)INT64_MIN)
87 : : #define TEST_IMM_3 ((uint64_t)INT64_MAX + INT32_MAX)
88 : : #define TEST_IMM_4 ((uint64_t)UINT32_MAX)
89 : : #define TEST_IMM_5 ((uint64_t)UINT32_MAX + 1)
90 : :
91 : : #define TEST_MEMFROB 0x2a2a2a2a
92 : :
93 : : #define STRING_GEEK 0x6B656567
94 : : #define STRING_WEEK 0x6B656577
95 : :
96 : : #define TEST_NETMASK 0xffffff00
97 : : #define TEST_SUBNET 0xaca80200
98 : :
99 : : uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
100 : : uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
101 : :
102 : : uint32_t ip_src_addr = (172U << 24) | (168U << 16) | (2 << 8) | 1;
103 : : uint32_t ip_dst_addr = (172U << 24) | (168U << 16) | (2 << 8) | 2;
104 : :
105 : : struct bpf_test {
106 : : const char *name;
107 : : size_t arg_sz;
108 : : struct rte_bpf_prm prm;
109 : : void (*prepare)(void *);
110 : : int (*check_result)(uint64_t, const void *);
111 : : uint32_t allow_fail;
112 : : };
113 : :
114 : : /*
115 : : * Compare return value and result data with expected ones.
116 : : * Report a failure if they don't match.
117 : : */
118 : : static int
119 : 40 : cmp_res(const char *func, uint64_t exp_rc, uint64_t ret_rc,
120 : : const void *exp_res, const void *ret_res, size_t res_sz)
121 : : {
122 : : int32_t ret;
123 : :
124 : : ret = 0;
125 [ - + ]: 40 : if (exp_rc != ret_rc) {
126 : : printf("%s@%d: invalid return value, expected: 0x%" PRIx64
127 : : ",result: 0x%" PRIx64 "\n",
128 : : func, __LINE__, exp_rc, ret_rc);
129 : : ret |= -1;
130 : : }
131 : :
132 [ - + ]: 40 : if (memcmp(exp_res, ret_res, res_sz) != 0) {
133 : : printf("%s: invalid value\n", func);
134 : 0 : rte_memdump(stdout, "expected", exp_res, res_sz);
135 : 0 : rte_memdump(stdout, "result", ret_res, res_sz);
136 : : ret |= -1;
137 : : }
138 : :
139 : 40 : return ret;
140 : : }
141 : :
142 : : /* store immediate test-cases */
143 : : static const struct ebpf_insn test_store1_prog[] = {
144 : : {
145 : : .code = (BPF_ST | BPF_MEM | BPF_B),
146 : : .dst_reg = EBPF_REG_1,
147 : : .off = offsetof(struct dummy_offset, u8),
148 : : .imm = TEST_FILL_1,
149 : : },
150 : : {
151 : : .code = (BPF_ST | BPF_MEM | BPF_H),
152 : : .dst_reg = EBPF_REG_1,
153 : : .off = offsetof(struct dummy_offset, u16),
154 : : .imm = TEST_FILL_1,
155 : : },
156 : : {
157 : : .code = (BPF_ST | BPF_MEM | BPF_W),
158 : : .dst_reg = EBPF_REG_1,
159 : : .off = offsetof(struct dummy_offset, u32),
160 : : .imm = TEST_FILL_1,
161 : : },
162 : : {
163 : : .code = (BPF_ST | BPF_MEM | EBPF_DW),
164 : : .dst_reg = EBPF_REG_1,
165 : : .off = offsetof(struct dummy_offset, u64),
166 : : .imm = TEST_FILL_1,
167 : : },
168 : : /* return 1 */
169 : : {
170 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
171 : : .dst_reg = EBPF_REG_0,
172 : : .imm = 1,
173 : : },
174 : : {
175 : : .code = (BPF_JMP | EBPF_EXIT),
176 : : },
177 : : };
178 : :
179 : : static void
180 : 14 : test_store1_prepare(void *arg)
181 : : {
182 : : struct dummy_offset *df;
183 : :
184 : : df = arg;
185 : : memset(df, 0, sizeof(*df));
186 : 14 : }
187 : :
188 : : static int
189 : 4 : test_store1_check(uint64_t rc, const void *arg)
190 : : {
191 : : const struct dummy_offset *dft;
192 : : struct dummy_offset dfe;
193 : :
194 : : dft = arg;
195 : :
196 : : memset(&dfe, 0, sizeof(dfe));
197 : 4 : dfe.u64 = (int32_t)TEST_FILL_1;
198 : 4 : dfe.u32 = dfe.u64;
199 : 4 : dfe.u16 = dfe.u64;
200 : 4 : dfe.u8 = dfe.u64;
201 : :
202 : 4 : return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
203 : : }
204 : :
205 : : /* store register test-cases */
206 : : static const struct ebpf_insn test_store2_prog[] = {
207 : :
208 : : {
209 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
210 : : .dst_reg = EBPF_REG_2,
211 : : .imm = TEST_FILL_1,
212 : : },
213 : : {
214 : : .code = (BPF_STX | BPF_MEM | BPF_B),
215 : : .dst_reg = EBPF_REG_1,
216 : : .src_reg = EBPF_REG_2,
217 : : .off = offsetof(struct dummy_offset, u8),
218 : : },
219 : : {
220 : : .code = (BPF_STX | BPF_MEM | BPF_H),
221 : : .dst_reg = EBPF_REG_1,
222 : : .src_reg = EBPF_REG_2,
223 : : .off = offsetof(struct dummy_offset, u16),
224 : : },
225 : : {
226 : : .code = (BPF_STX | BPF_MEM | BPF_W),
227 : : .dst_reg = EBPF_REG_1,
228 : : .src_reg = EBPF_REG_2,
229 : : .off = offsetof(struct dummy_offset, u32),
230 : : },
231 : : {
232 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
233 : : .dst_reg = EBPF_REG_1,
234 : : .src_reg = EBPF_REG_2,
235 : : .off = offsetof(struct dummy_offset, u64),
236 : : },
237 : : /* return 1 */
238 : : {
239 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
240 : : .dst_reg = EBPF_REG_0,
241 : : .imm = 1,
242 : : },
243 : : {
244 : : .code = (BPF_JMP | EBPF_EXIT),
245 : : },
246 : : };
247 : :
248 : : /* load test-cases */
249 : : static const struct ebpf_insn test_load1_prog[] = {
250 : :
251 : : {
252 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
253 : : .dst_reg = EBPF_REG_2,
254 : : .src_reg = EBPF_REG_1,
255 : : .off = offsetof(struct dummy_offset, u8),
256 : : },
257 : : {
258 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
259 : : .dst_reg = EBPF_REG_3,
260 : : .src_reg = EBPF_REG_1,
261 : : .off = offsetof(struct dummy_offset, u16),
262 : : },
263 : : {
264 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
265 : : .dst_reg = EBPF_REG_4,
266 : : .src_reg = EBPF_REG_1,
267 : : .off = offsetof(struct dummy_offset, u32),
268 : : },
269 : : {
270 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
271 : : .dst_reg = EBPF_REG_0,
272 : : .src_reg = EBPF_REG_1,
273 : : .off = offsetof(struct dummy_offset, u64),
274 : : },
275 : : /* return sum */
276 : : {
277 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
278 : : .dst_reg = EBPF_REG_0,
279 : : .src_reg = EBPF_REG_4,
280 : : },
281 : : {
282 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
283 : : .dst_reg = EBPF_REG_0,
284 : : .src_reg = EBPF_REG_3,
285 : : },
286 : : {
287 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
288 : : .dst_reg = EBPF_REG_0,
289 : : .src_reg = EBPF_REG_2,
290 : : },
291 : : {
292 : : .code = (BPF_JMP | EBPF_EXIT),
293 : : },
294 : : };
295 : :
296 : : static void
297 : 4 : test_load1_prepare(void *arg)
298 : : {
299 : : struct dummy_offset *df;
300 : :
301 : : df = arg;
302 : :
303 : : memset(df, 0, sizeof(*df));
304 : 4 : df->u64 = (int32_t)TEST_FILL_1;
305 : 4 : df->u32 = df->u64;
306 : 4 : df->u16 = df->u64;
307 : 4 : df->u8 = df->u64;
308 : 4 : }
309 : :
310 : : static int
311 : 2 : test_load1_check(uint64_t rc, const void *arg)
312 : : {
313 : : uint64_t v;
314 : : const struct dummy_offset *dft;
315 : :
316 : : dft = arg;
317 : 2 : v = dft->u64;
318 : 2 : v += dft->u32;
319 : 2 : v += dft->u16;
320 : 2 : v += dft->u8;
321 : :
322 : 2 : return cmp_res(__func__, v, rc, dft, dft, sizeof(*dft));
323 : : }
324 : :
325 : : /* load immediate test-cases */
326 : : static const struct ebpf_insn test_ldimm1_prog[] = {
327 : :
328 : : {
329 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
330 : : .dst_reg = EBPF_REG_0,
331 : : .imm = (uint32_t)TEST_IMM_1,
332 : : },
333 : : {
334 : : .imm = TEST_IMM_1 >> 32,
335 : : },
336 : : {
337 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
338 : : .dst_reg = EBPF_REG_3,
339 : : .imm = (uint32_t)TEST_IMM_2,
340 : : },
341 : : {
342 : : .imm = TEST_IMM_2 >> 32,
343 : : },
344 : : {
345 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
346 : : .dst_reg = EBPF_REG_5,
347 : : .imm = (uint32_t)TEST_IMM_3,
348 : : },
349 : : {
350 : : .imm = TEST_IMM_3 >> 32,
351 : : },
352 : : {
353 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
354 : : .dst_reg = EBPF_REG_7,
355 : : .imm = (uint32_t)TEST_IMM_4,
356 : : },
357 : : {
358 : : .imm = TEST_IMM_4 >> 32,
359 : : },
360 : : {
361 : : .code = (BPF_LD | BPF_IMM | EBPF_DW),
362 : : .dst_reg = EBPF_REG_9,
363 : : .imm = (uint32_t)TEST_IMM_5,
364 : : },
365 : : {
366 : : .imm = TEST_IMM_5 >> 32,
367 : : },
368 : : /* return sum */
369 : : {
370 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
371 : : .dst_reg = EBPF_REG_0,
372 : : .src_reg = EBPF_REG_3,
373 : : },
374 : : {
375 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
376 : : .dst_reg = EBPF_REG_0,
377 : : .src_reg = EBPF_REG_5,
378 : : },
379 : : {
380 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
381 : : .dst_reg = EBPF_REG_0,
382 : : .src_reg = EBPF_REG_7,
383 : : },
384 : : {
385 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
386 : : .dst_reg = EBPF_REG_0,
387 : : .src_reg = EBPF_REG_9,
388 : : },
389 : : {
390 : : .code = (BPF_JMP | EBPF_EXIT),
391 : : },
392 : : };
393 : :
394 : : static int
395 : 2 : test_ldimm1_check(uint64_t rc, const void *arg)
396 : : {
397 : : uint64_t v1, v2;
398 : :
399 : : v1 = TEST_IMM_1;
400 : : v2 = TEST_IMM_2;
401 : : v1 += v2;
402 : : v2 = TEST_IMM_3;
403 : : v1 += v2;
404 : : v2 = TEST_IMM_4;
405 : : v1 += v2;
406 : : v2 = TEST_IMM_5;
407 : : v1 += v2;
408 : :
409 : 2 : return cmp_res(__func__, v1, rc, arg, arg, 0);
410 : : }
411 : :
412 : :
413 : : /* alu mul test-cases */
414 : : static const struct ebpf_insn test_mul1_prog[] = {
415 : :
416 : : {
417 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
418 : : .dst_reg = EBPF_REG_2,
419 : : .src_reg = EBPF_REG_1,
420 : : .off = offsetof(struct dummy_vect8, in[0].u32),
421 : : },
422 : : {
423 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
424 : : .dst_reg = EBPF_REG_3,
425 : : .src_reg = EBPF_REG_1,
426 : : .off = offsetof(struct dummy_vect8, in[1].u64),
427 : : },
428 : : {
429 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
430 : : .dst_reg = EBPF_REG_4,
431 : : .src_reg = EBPF_REG_1,
432 : : .off = offsetof(struct dummy_vect8, in[2].u32),
433 : : },
434 : : {
435 : : .code = (BPF_ALU | BPF_MUL | BPF_K),
436 : : .dst_reg = EBPF_REG_2,
437 : : .imm = TEST_MUL_1,
438 : : },
439 : : {
440 : : .code = (EBPF_ALU64 | BPF_MUL | BPF_K),
441 : : .dst_reg = EBPF_REG_3,
442 : : .imm = TEST_MUL_2,
443 : : },
444 : : {
445 : : .code = (BPF_ALU | BPF_MUL | BPF_X),
446 : : .dst_reg = EBPF_REG_4,
447 : : .src_reg = EBPF_REG_2,
448 : : },
449 : : {
450 : : .code = (EBPF_ALU64 | BPF_MUL | BPF_X),
451 : : .dst_reg = EBPF_REG_4,
452 : : .src_reg = EBPF_REG_3,
453 : : },
454 : : {
455 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
456 : : .dst_reg = EBPF_REG_1,
457 : : .src_reg = EBPF_REG_2,
458 : : .off = offsetof(struct dummy_vect8, out[0].u64),
459 : : },
460 : : {
461 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
462 : : .dst_reg = EBPF_REG_1,
463 : : .src_reg = EBPF_REG_3,
464 : : .off = offsetof(struct dummy_vect8, out[1].u64),
465 : : },
466 : : {
467 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
468 : : .dst_reg = EBPF_REG_1,
469 : : .src_reg = EBPF_REG_4,
470 : : .off = offsetof(struct dummy_vect8, out[2].u64),
471 : : },
472 : : /* return 1 */
473 : : {
474 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
475 : : .dst_reg = EBPF_REG_0,
476 : : .imm = 1,
477 : : },
478 : : {
479 : : .code = (BPF_JMP | EBPF_EXIT),
480 : : },
481 : : };
482 : :
483 : : static void
484 : 4 : test_mul1_prepare(void *arg)
485 : : {
486 : : struct dummy_vect8 *dv;
487 : : uint64_t v;
488 : :
489 : : dv = arg;
490 : :
491 : 4 : v = rte_rand();
492 : :
493 : : memset(dv, 0, sizeof(*dv));
494 : 4 : dv->in[0].u32 = v;
495 : 4 : dv->in[1].u64 = v << 12 | v >> 6;
496 : 4 : dv->in[2].u32 = -v;
497 : 4 : }
498 : :
499 : : static int
500 : 2 : test_mul1_check(uint64_t rc, const void *arg)
501 : : {
502 : : uint64_t r2, r3, r4;
503 : : const struct dummy_vect8 *dvt;
504 : : struct dummy_vect8 dve;
505 : :
506 : : dvt = arg;
507 : : memset(&dve, 0, sizeof(dve));
508 : :
509 : 2 : r2 = dvt->in[0].u32;
510 : 2 : r3 = dvt->in[1].u64;
511 : 2 : r4 = dvt->in[2].u32;
512 : :
513 : 2 : r2 = (uint32_t)r2 * TEST_MUL_1;
514 : 2 : r3 *= TEST_MUL_2;
515 : 2 : r4 = (uint32_t)(r4 * r2);
516 : 2 : r4 *= r3;
517 : :
518 : 2 : dve.out[0].u64 = r2;
519 : 2 : dve.out[1].u64 = r3;
520 : 2 : dve.out[2].u64 = r4;
521 : :
522 : 2 : return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
523 : : }
524 : :
525 : : /* alu shift test-cases */
526 : : static const struct ebpf_insn test_shift1_prog[] = {
527 : :
528 : : {
529 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
530 : : .dst_reg = EBPF_REG_2,
531 : : .src_reg = EBPF_REG_1,
532 : : .off = offsetof(struct dummy_vect8, in[0].u32),
533 : : },
534 : : {
535 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
536 : : .dst_reg = EBPF_REG_3,
537 : : .src_reg = EBPF_REG_1,
538 : : .off = offsetof(struct dummy_vect8, in[1].u64),
539 : : },
540 : : {
541 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
542 : : .dst_reg = EBPF_REG_4,
543 : : .src_reg = EBPF_REG_1,
544 : : .off = offsetof(struct dummy_vect8, in[2].u32),
545 : : },
546 : : {
547 : : .code = (BPF_ALU | BPF_LSH | BPF_K),
548 : : .dst_reg = EBPF_REG_2,
549 : : .imm = TEST_SHIFT_1,
550 : : },
551 : : {
552 : : .code = (EBPF_ALU64 | EBPF_ARSH | BPF_K),
553 : : .dst_reg = EBPF_REG_3,
554 : : .imm = TEST_SHIFT_2,
555 : : },
556 : : {
557 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
558 : : .dst_reg = EBPF_REG_1,
559 : : .src_reg = EBPF_REG_2,
560 : : .off = offsetof(struct dummy_vect8, out[0].u64),
561 : : },
562 : : {
563 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
564 : : .dst_reg = EBPF_REG_1,
565 : : .src_reg = EBPF_REG_3,
566 : : .off = offsetof(struct dummy_vect8, out[1].u64),
567 : : },
568 : : {
569 : : .code = (BPF_ALU | BPF_AND | BPF_K),
570 : : .dst_reg = EBPF_REG_4,
571 : : .imm = TEST_SHIFT64_MASK,
572 : : },
573 : : {
574 : : .code = (EBPF_ALU64 | BPF_LSH | BPF_X),
575 : : .dst_reg = EBPF_REG_3,
576 : : .src_reg = EBPF_REG_4,
577 : : },
578 : : {
579 : : .code = (BPF_ALU | BPF_AND | BPF_K),
580 : : .dst_reg = EBPF_REG_4,
581 : : .imm = TEST_SHIFT32_MASK,
582 : : },
583 : : {
584 : : .code = (BPF_ALU | BPF_RSH | BPF_X),
585 : : .dst_reg = EBPF_REG_2,
586 : : .src_reg = EBPF_REG_4,
587 : : },
588 : : {
589 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
590 : : .dst_reg = EBPF_REG_1,
591 : : .src_reg = EBPF_REG_2,
592 : : .off = offsetof(struct dummy_vect8, out[2].u64),
593 : : },
594 : : {
595 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
596 : : .dst_reg = EBPF_REG_1,
597 : : .src_reg = EBPF_REG_3,
598 : : .off = offsetof(struct dummy_vect8, out[3].u64),
599 : : },
600 : : {
601 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
602 : : .dst_reg = EBPF_REG_2,
603 : : .src_reg = EBPF_REG_1,
604 : : .off = offsetof(struct dummy_vect8, in[0].u32),
605 : : },
606 : : {
607 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
608 : : .dst_reg = EBPF_REG_3,
609 : : .src_reg = EBPF_REG_1,
610 : : .off = offsetof(struct dummy_vect8, in[1].u64),
611 : : },
612 : : {
613 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
614 : : .dst_reg = EBPF_REG_4,
615 : : .src_reg = EBPF_REG_1,
616 : : .off = offsetof(struct dummy_vect8, in[2].u32),
617 : : },
618 : : {
619 : : .code = (BPF_ALU | BPF_AND | BPF_K),
620 : : .dst_reg = EBPF_REG_2,
621 : : .imm = TEST_SHIFT64_MASK,
622 : : },
623 : : {
624 : : .code = (EBPF_ALU64 | EBPF_ARSH | BPF_X),
625 : : .dst_reg = EBPF_REG_3,
626 : : .src_reg = EBPF_REG_2,
627 : : },
628 : : {
629 : : .code = (BPF_ALU | BPF_AND | BPF_K),
630 : : .dst_reg = EBPF_REG_2,
631 : : .imm = TEST_SHIFT32_MASK,
632 : : },
633 : : {
634 : : .code = (BPF_ALU | BPF_LSH | BPF_X),
635 : : .dst_reg = EBPF_REG_4,
636 : : .src_reg = EBPF_REG_2,
637 : : },
638 : : {
639 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
640 : : .dst_reg = EBPF_REG_1,
641 : : .src_reg = EBPF_REG_4,
642 : : .off = offsetof(struct dummy_vect8, out[4].u64),
643 : : },
644 : : {
645 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
646 : : .dst_reg = EBPF_REG_1,
647 : : .src_reg = EBPF_REG_3,
648 : : .off = offsetof(struct dummy_vect8, out[5].u64),
649 : : },
650 : : /* return 1 */
651 : : {
652 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
653 : : .dst_reg = EBPF_REG_0,
654 : : .imm = 1,
655 : : },
656 : : {
657 : : .code = (BPF_JMP | EBPF_EXIT),
658 : : },
659 : : };
660 : :
661 : : static void
662 : 2 : test_shift1_prepare(void *arg)
663 : : {
664 : : struct dummy_vect8 *dv;
665 : : uint64_t v;
666 : :
667 : : dv = arg;
668 : :
669 : 2 : v = rte_rand();
670 : :
671 : : memset(dv, 0, sizeof(*dv));
672 : 2 : dv->in[0].u32 = v;
673 : 2 : dv->in[1].u64 = v << 12 | v >> 6;
674 : 2 : dv->in[2].u32 = (-v ^ 5);
675 : 2 : }
676 : :
677 : : static int
678 : 2 : test_shift1_check(uint64_t rc, const void *arg)
679 : : {
680 : : uint64_t r2, r3, r4;
681 : : const struct dummy_vect8 *dvt;
682 : : struct dummy_vect8 dve;
683 : :
684 : : dvt = arg;
685 : : memset(&dve, 0, sizeof(dve));
686 : :
687 : 2 : r2 = dvt->in[0].u32;
688 : 2 : r3 = dvt->in[1].u64;
689 : 2 : r4 = dvt->in[2].u32;
690 : :
691 : 2 : r2 = (uint32_t)r2 << TEST_SHIFT_1;
692 : 2 : r3 = (int64_t)r3 >> TEST_SHIFT_2;
693 : :
694 : 2 : dve.out[0].u64 = r2;
695 : 2 : dve.out[1].u64 = r3;
696 : :
697 : : r4 &= TEST_SHIFT64_MASK;
698 : 2 : r3 <<= r4;
699 : : r4 &= TEST_SHIFT32_MASK;
700 : 2 : r2 = (uint32_t)r2 >> r4;
701 : :
702 : 2 : dve.out[2].u64 = r2;
703 : 2 : dve.out[3].u64 = r3;
704 : :
705 : : r2 = dvt->in[0].u32;
706 : : r3 = dvt->in[1].u64;
707 : : r4 = dvt->in[2].u32;
708 : :
709 : : r2 &= TEST_SHIFT64_MASK;
710 : 2 : r3 = (int64_t)r3 >> r2;
711 : : r2 &= TEST_SHIFT32_MASK;
712 : 2 : r4 = (uint32_t)r4 << r2;
713 : :
714 : 2 : dve.out[4].u64 = r4;
715 : 2 : dve.out[5].u64 = r3;
716 : :
717 : 2 : return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
718 : : }
719 : :
720 : : /* jmp test-cases */
721 : : static const struct ebpf_insn test_jump1_prog[] = {
722 : :
723 : : [0] = {
724 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
725 : : .dst_reg = EBPF_REG_0,
726 : : .imm = 0,
727 : : },
728 : : [1] = {
729 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
730 : : .dst_reg = EBPF_REG_2,
731 : : .src_reg = EBPF_REG_1,
732 : : .off = offsetof(struct dummy_vect8, in[0].u32),
733 : : },
734 : : [2] = {
735 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
736 : : .dst_reg = EBPF_REG_3,
737 : : .src_reg = EBPF_REG_1,
738 : : .off = offsetof(struct dummy_vect8, in[0].u64),
739 : : },
740 : : [3] = {
741 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
742 : : .dst_reg = EBPF_REG_4,
743 : : .src_reg = EBPF_REG_1,
744 : : .off = offsetof(struct dummy_vect8, in[1].u32),
745 : : },
746 : : [4] = {
747 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
748 : : .dst_reg = EBPF_REG_5,
749 : : .src_reg = EBPF_REG_1,
750 : : .off = offsetof(struct dummy_vect8, in[1].u64),
751 : : },
752 : : [5] = {
753 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
754 : : .dst_reg = EBPF_REG_2,
755 : : .imm = TEST_JCC_1,
756 : : .off = 8,
757 : : },
758 : : [6] = {
759 : : .code = (BPF_JMP | EBPF_JSLE | BPF_K),
760 : : .dst_reg = EBPF_REG_3,
761 : : .imm = TEST_JCC_2,
762 : : .off = 9,
763 : : },
764 : : [7] = {
765 : : .code = (BPF_JMP | BPF_JGT | BPF_K),
766 : : .dst_reg = EBPF_REG_4,
767 : : .imm = TEST_JCC_3,
768 : : .off = 10,
769 : : },
770 : : [8] = {
771 : : .code = (BPF_JMP | BPF_JSET | BPF_K),
772 : : .dst_reg = EBPF_REG_5,
773 : : .imm = TEST_JCC_4,
774 : : .off = 11,
775 : : },
776 : : [9] = {
777 : : .code = (BPF_JMP | EBPF_JNE | BPF_X),
778 : : .dst_reg = EBPF_REG_2,
779 : : .src_reg = EBPF_REG_3,
780 : : .off = 12,
781 : : },
782 : : [10] = {
783 : : .code = (BPF_JMP | EBPF_JSGT | BPF_X),
784 : : .dst_reg = EBPF_REG_2,
785 : : .src_reg = EBPF_REG_4,
786 : : .off = 13,
787 : : },
788 : : [11] = {
789 : : .code = (BPF_JMP | EBPF_JLE | BPF_X),
790 : : .dst_reg = EBPF_REG_2,
791 : : .src_reg = EBPF_REG_5,
792 : : .off = 14,
793 : : },
794 : : [12] = {
795 : : .code = (BPF_JMP | BPF_JSET | BPF_X),
796 : : .dst_reg = EBPF_REG_3,
797 : : .src_reg = EBPF_REG_5,
798 : : .off = 15,
799 : : },
800 : : [13] = {
801 : : .code = (BPF_JMP | EBPF_EXIT),
802 : : },
803 : : [14] = {
804 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
805 : : .dst_reg = EBPF_REG_0,
806 : : .imm = 0x1,
807 : : },
808 : : [15] = {
809 : : .code = (BPF_JMP | BPF_JA),
810 : : .off = -10,
811 : : },
812 : : [16] = {
813 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
814 : : .dst_reg = EBPF_REG_0,
815 : : .imm = 0x2,
816 : : },
817 : : [17] = {
818 : : .code = (BPF_JMP | BPF_JA),
819 : : .off = -11,
820 : : },
821 : : [18] = {
822 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
823 : : .dst_reg = EBPF_REG_0,
824 : : .imm = 0x4,
825 : : },
826 : : [19] = {
827 : : .code = (BPF_JMP | BPF_JA),
828 : : .off = -12,
829 : : },
830 : : [20] = {
831 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
832 : : .dst_reg = EBPF_REG_0,
833 : : .imm = 0x8,
834 : : },
835 : : [21] = {
836 : : .code = (BPF_JMP | BPF_JA),
837 : : .off = -13,
838 : : },
839 : : [22] = {
840 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
841 : : .dst_reg = EBPF_REG_0,
842 : : .imm = 0x10,
843 : : },
844 : : [23] = {
845 : : .code = (BPF_JMP | BPF_JA),
846 : : .off = -14,
847 : : },
848 : : [24] = {
849 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
850 : : .dst_reg = EBPF_REG_0,
851 : : .imm = 0x20,
852 : : },
853 : : [25] = {
854 : : .code = (BPF_JMP | BPF_JA),
855 : : .off = -15,
856 : : },
857 : : [26] = {
858 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
859 : : .dst_reg = EBPF_REG_0,
860 : : .imm = 0x40,
861 : : },
862 : : [27] = {
863 : : .code = (BPF_JMP | BPF_JA),
864 : : .off = -16,
865 : : },
866 : : [28] = {
867 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
868 : : .dst_reg = EBPF_REG_0,
869 : : .imm = 0x80,
870 : : },
871 : : [29] = {
872 : : .code = (BPF_JMP | BPF_JA),
873 : : .off = -17,
874 : : },
875 : : };
876 : :
877 : : static void
878 : 4 : test_jump1_prepare(void *arg)
879 : : {
880 : : struct dummy_vect8 *dv;
881 : : uint64_t v1, v2;
882 : :
883 : : dv = arg;
884 : :
885 : 4 : v1 = rte_rand();
886 : 4 : v2 = rte_rand();
887 : :
888 : : memset(dv, 0, sizeof(*dv));
889 : 4 : dv->in[0].u64 = v1;
890 : 4 : dv->in[1].u64 = v2;
891 : 4 : dv->in[0].u32 = (v1 << 12) + (v2 >> 6);
892 : 4 : dv->in[1].u32 = (v2 << 12) - (v1 >> 6);
893 : 4 : }
894 : :
895 : : static int
896 : 2 : test_jump1_check(uint64_t rc, const void *arg)
897 : : {
898 : : uint64_t r2, r3, r4, r5, rv;
899 : : const struct dummy_vect8 *dvt;
900 : :
901 : : dvt = arg;
902 : :
903 : 2 : rv = 0;
904 : 2 : r2 = dvt->in[0].u32;
905 : 2 : r3 = dvt->in[0].u64;
906 : 2 : r4 = dvt->in[1].u32;
907 : 2 : r5 = dvt->in[1].u64;
908 : :
909 [ - + ]: 2 : if (r2 == TEST_JCC_1)
910 : 0 : rv |= 0x1;
911 [ + + ]: 2 : if ((int64_t)r3 <= TEST_JCC_2)
912 : 1 : rv |= 0x2;
913 [ + - ]: 2 : if (r4 > TEST_JCC_3)
914 : 2 : rv |= 0x4;
915 [ + - ]: 2 : if (r5 & TEST_JCC_4)
916 : 2 : rv |= 0x8;
917 [ + - ]: 2 : if (r2 != r3)
918 : 2 : rv |= 0x10;
919 [ + + ]: 2 : if ((int64_t)r2 > (int64_t)r4)
920 : 1 : rv |= 0x20;
921 [ + - ]: 2 : if (r2 <= r5)
922 : 2 : rv |= 0x40;
923 [ + - ]: 2 : if (r3 & r5)
924 : 2 : rv |= 0x80;
925 : :
926 : 2 : return cmp_res(__func__, rv, rc, &rv, &rc, sizeof(rv));
927 : : }
928 : :
929 : : /* Jump test case - check ip4_dest in particular subnet */
930 : : static const struct ebpf_insn test_jump2_prog[] = {
931 : :
932 : : [0] = {
933 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
934 : : .dst_reg = EBPF_REG_2,
935 : : .imm = 0xe,
936 : : },
937 : : [1] = {
938 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
939 : : .dst_reg = EBPF_REG_3,
940 : : .src_reg = EBPF_REG_1,
941 : : .off = 12,
942 : : },
943 : : [2] = {
944 : : .code = (BPF_JMP | EBPF_JNE | BPF_K),
945 : : .dst_reg = EBPF_REG_3,
946 : : .off = 2,
947 : : .imm = 0x81,
948 : : },
949 : : [3] = {
950 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
951 : : .dst_reg = EBPF_REG_2,
952 : : .imm = 0x12,
953 : : },
954 : : [4] = {
955 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
956 : : .dst_reg = EBPF_REG_3,
957 : : .src_reg = EBPF_REG_1,
958 : : .off = 16,
959 : : },
960 : : [5] = {
961 : : .code = (EBPF_ALU64 | BPF_AND | BPF_K),
962 : : .dst_reg = EBPF_REG_3,
963 : : .imm = 0xffff,
964 : : },
965 : : [6] = {
966 : : .code = (BPF_JMP | EBPF_JNE | BPF_K),
967 : : .dst_reg = EBPF_REG_3,
968 : : .off = 9,
969 : : .imm = 0x8,
970 : : },
971 : : [7] = {
972 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
973 : : .dst_reg = EBPF_REG_1,
974 : : .src_reg = EBPF_REG_2,
975 : : },
976 : : [8] = {
977 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
978 : : .dst_reg = EBPF_REG_0,
979 : : .imm = 0,
980 : : },
981 : : [9] = {
982 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
983 : : .dst_reg = EBPF_REG_1,
984 : : .src_reg = EBPF_REG_1,
985 : : .off = 16,
986 : : },
987 : : [10] = {
988 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
989 : : .dst_reg = EBPF_REG_3,
990 : : .imm = TEST_NETMASK,
991 : : },
992 : : [11] = {
993 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
994 : : .dst_reg = EBPF_REG_3,
995 : : .imm = sizeof(uint32_t) * CHAR_BIT,
996 : : },
997 : : [12] = {
998 : : .code = (BPF_ALU | BPF_AND | BPF_X),
999 : : .dst_reg = EBPF_REG_1,
1000 : : .src_reg = EBPF_REG_3,
1001 : : },
1002 : : [13] = {
1003 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1004 : : .dst_reg = EBPF_REG_3,
1005 : : .imm = TEST_SUBNET,
1006 : : },
1007 : : [14] = {
1008 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1009 : : .dst_reg = EBPF_REG_3,
1010 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1011 : : },
1012 : : [15] = {
1013 : : .code = (BPF_JMP | BPF_JEQ | BPF_X),
1014 : : .dst_reg = EBPF_REG_1,
1015 : : .src_reg = EBPF_REG_3,
1016 : : .off = 1,
1017 : : },
1018 : : [16] = {
1019 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1020 : : .dst_reg = EBPF_REG_0,
1021 : : .imm = -1,
1022 : : },
1023 : : [17] = {
1024 : : .code = (BPF_JMP | EBPF_EXIT),
1025 : : },
1026 : : };
1027 : :
1028 : : /* Preparing a vlan packet */
1029 : : static void
1030 [ - + ]: 2 : test_jump2_prepare(void *arg)
1031 : : {
1032 : : struct dummy_net *dn;
1033 : :
1034 : : dn = arg;
1035 : : memset(dn, 0, sizeof(*dn));
1036 : :
1037 : : /*
1038 : : * Initialize ether header.
1039 : : */
1040 : : rte_ether_addr_copy((struct rte_ether_addr *)dst_mac,
1041 : : &dn->eth_hdr.dst_addr);
1042 : : rte_ether_addr_copy((struct rte_ether_addr *)src_mac,
1043 : : &dn->eth_hdr.src_addr);
1044 : 2 : dn->eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
1045 : :
1046 : : /*
1047 : : * Initialize vlan header.
1048 : : */
1049 : 2 : dn->vlan_hdr.eth_proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
1050 : 2 : dn->vlan_hdr.vlan_tci = 32;
1051 : :
1052 : : /*
1053 : : * Initialize IP header.
1054 : : */
1055 : 2 : dn->ip_hdr.version_ihl = 0x45; /*IP_VERSION | IP_HDRLEN*/
1056 : 2 : dn->ip_hdr.time_to_live = 64; /* IP_DEFTTL */
1057 : 2 : dn->ip_hdr.next_proto_id = IPPROTO_TCP;
1058 : 2 : dn->ip_hdr.packet_id = rte_cpu_to_be_16(0x463c);
1059 : 2 : dn->ip_hdr.total_length = rte_cpu_to_be_16(60);
1060 [ - + ]: 2 : dn->ip_hdr.src_addr = rte_cpu_to_be_32(ip_src_addr);
1061 [ - + ]: 2 : dn->ip_hdr.dst_addr = rte_cpu_to_be_32(ip_dst_addr);
1062 : 2 : }
1063 : :
1064 : : static int
1065 : 2 : test_jump2_check(uint64_t rc, const void *arg)
1066 : : {
1067 : : const struct rte_ether_hdr *eth_hdr = arg;
1068 : : const struct rte_ipv4_hdr *ipv4_hdr;
1069 : : const void *next = eth_hdr;
1070 : : uint16_t eth_type;
1071 : : uint64_t v = -1;
1072 : :
1073 [ + - ]: 2 : if (eth_hdr->ether_type == htons(0x8100)) {
1074 : : const struct rte_vlan_hdr *vlan_hdr =
1075 : : (const void *)(eth_hdr + 1);
1076 : 2 : eth_type = vlan_hdr->eth_proto;
1077 : 2 : next = vlan_hdr + 1;
1078 : : } else {
1079 : : eth_type = eth_hdr->ether_type;
1080 : 0 : next = eth_hdr + 1;
1081 : : }
1082 : :
1083 [ + - ]: 2 : if (eth_type == htons(0x0800)) {
1084 : : ipv4_hdr = next;
1085 [ + - ]: 2 : if ((ipv4_hdr->dst_addr & rte_cpu_to_be_32(TEST_NETMASK)) ==
1086 : : rte_cpu_to_be_32(TEST_SUBNET)) {
1087 : : v = 0;
1088 : : }
1089 : : }
1090 : :
1091 : 2 : return cmp_res(__func__, v, rc, arg, arg, sizeof(arg));
1092 : : }
1093 : :
1094 : : /* alu (add, sub, and, or, xor, neg) test-cases */
1095 : : static const struct ebpf_insn test_alu1_prog[] = {
1096 : :
1097 : : {
1098 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1099 : : .dst_reg = EBPF_REG_2,
1100 : : .src_reg = EBPF_REG_1,
1101 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1102 : : },
1103 : : {
1104 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1105 : : .dst_reg = EBPF_REG_3,
1106 : : .src_reg = EBPF_REG_1,
1107 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1108 : : },
1109 : : {
1110 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1111 : : .dst_reg = EBPF_REG_4,
1112 : : .src_reg = EBPF_REG_1,
1113 : : .off = offsetof(struct dummy_vect8, in[1].u32),
1114 : : },
1115 : : {
1116 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1117 : : .dst_reg = EBPF_REG_5,
1118 : : .src_reg = EBPF_REG_1,
1119 : : .off = offsetof(struct dummy_vect8, in[1].u64),
1120 : : },
1121 : : {
1122 : : .code = (BPF_ALU | BPF_AND | BPF_K),
1123 : : .dst_reg = EBPF_REG_2,
1124 : : .imm = TEST_FILL_1,
1125 : : },
1126 : : {
1127 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1128 : : .dst_reg = EBPF_REG_3,
1129 : : .imm = TEST_FILL_1,
1130 : : },
1131 : : {
1132 : : .code = (BPF_ALU | BPF_XOR | BPF_K),
1133 : : .dst_reg = EBPF_REG_4,
1134 : : .imm = TEST_FILL_1,
1135 : : },
1136 : : {
1137 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1138 : : .dst_reg = EBPF_REG_5,
1139 : : .imm = TEST_FILL_1,
1140 : : },
1141 : : {
1142 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1143 : : .dst_reg = EBPF_REG_1,
1144 : : .src_reg = EBPF_REG_2,
1145 : : .off = offsetof(struct dummy_vect8, out[0].u64),
1146 : : },
1147 : : {
1148 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1149 : : .dst_reg = EBPF_REG_1,
1150 : : .src_reg = EBPF_REG_3,
1151 : : .off = offsetof(struct dummy_vect8, out[1].u64),
1152 : : },
1153 : : {
1154 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1155 : : .dst_reg = EBPF_REG_1,
1156 : : .src_reg = EBPF_REG_4,
1157 : : .off = offsetof(struct dummy_vect8, out[2].u64),
1158 : : },
1159 : : {
1160 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1161 : : .dst_reg = EBPF_REG_1,
1162 : : .src_reg = EBPF_REG_5,
1163 : : .off = offsetof(struct dummy_vect8, out[3].u64),
1164 : : },
1165 : : {
1166 : : .code = (BPF_ALU | BPF_OR | BPF_X),
1167 : : .dst_reg = EBPF_REG_2,
1168 : : .src_reg = EBPF_REG_3,
1169 : : },
1170 : : {
1171 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
1172 : : .dst_reg = EBPF_REG_3,
1173 : : .src_reg = EBPF_REG_4,
1174 : : },
1175 : : {
1176 : : .code = (BPF_ALU | BPF_SUB | BPF_X),
1177 : : .dst_reg = EBPF_REG_4,
1178 : : .src_reg = EBPF_REG_5,
1179 : : },
1180 : : {
1181 : : .code = (EBPF_ALU64 | BPF_AND | BPF_X),
1182 : : .dst_reg = EBPF_REG_5,
1183 : : .src_reg = EBPF_REG_2,
1184 : : },
1185 : : {
1186 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1187 : : .dst_reg = EBPF_REG_1,
1188 : : .src_reg = EBPF_REG_2,
1189 : : .off = offsetof(struct dummy_vect8, out[4].u64),
1190 : : },
1191 : : {
1192 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1193 : : .dst_reg = EBPF_REG_1,
1194 : : .src_reg = EBPF_REG_3,
1195 : : .off = offsetof(struct dummy_vect8, out[5].u64),
1196 : : },
1197 : : {
1198 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1199 : : .dst_reg = EBPF_REG_1,
1200 : : .src_reg = EBPF_REG_4,
1201 : : .off = offsetof(struct dummy_vect8, out[6].u64),
1202 : : },
1203 : : {
1204 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1205 : : .dst_reg = EBPF_REG_1,
1206 : : .src_reg = EBPF_REG_5,
1207 : : .off = offsetof(struct dummy_vect8, out[7].u64),
1208 : : },
1209 : : /* return (-r2 + (-r3)) */
1210 : : {
1211 : : .code = (BPF_ALU | BPF_NEG),
1212 : : .dst_reg = EBPF_REG_2,
1213 : : },
1214 : : {
1215 : : .code = (EBPF_ALU64 | BPF_NEG),
1216 : : .dst_reg = EBPF_REG_3,
1217 : : },
1218 : : {
1219 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1220 : : .dst_reg = EBPF_REG_2,
1221 : : .src_reg = EBPF_REG_3,
1222 : : },
1223 : : {
1224 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1225 : : .dst_reg = EBPF_REG_0,
1226 : : .src_reg = EBPF_REG_2,
1227 : : },
1228 : : {
1229 : : .code = (BPF_JMP | EBPF_EXIT),
1230 : : },
1231 : : };
1232 : :
1233 : : static int
1234 : 2 : test_alu1_check(uint64_t rc, const void *arg)
1235 : : {
1236 : : uint64_t r2, r3, r4, r5, rv;
1237 : : const struct dummy_vect8 *dvt;
1238 : : struct dummy_vect8 dve;
1239 : :
1240 : : dvt = arg;
1241 : : memset(&dve, 0, sizeof(dve));
1242 : :
1243 : 2 : r2 = dvt->in[0].u32;
1244 : 2 : r3 = dvt->in[0].u64;
1245 : 2 : r4 = dvt->in[1].u32;
1246 : 2 : r5 = dvt->in[1].u64;
1247 : :
1248 : 2 : r2 = (uint32_t)r2 & TEST_FILL_1;
1249 : 2 : r3 |= (int32_t) TEST_FILL_1;
1250 : 2 : r4 = (uint32_t)r4 ^ TEST_FILL_1;
1251 : 2 : r5 += (int32_t)TEST_FILL_1;
1252 : :
1253 : 2 : dve.out[0].u64 = r2;
1254 : 2 : dve.out[1].u64 = r3;
1255 : 2 : dve.out[2].u64 = r4;
1256 : 2 : dve.out[3].u64 = r5;
1257 : :
1258 : 2 : r2 = (uint32_t)r2 | (uint32_t)r3;
1259 : 2 : r3 ^= r4;
1260 : 2 : r4 = (uint32_t)r4 - (uint32_t)r5;
1261 : 2 : r5 &= r2;
1262 : :
1263 : 2 : dve.out[4].u64 = r2;
1264 : 2 : dve.out[5].u64 = r3;
1265 : 2 : dve.out[6].u64 = r4;
1266 : 2 : dve.out[7].u64 = r5;
1267 : :
1268 : 2 : r2 = -(int32_t)r2;
1269 : : rv = (uint32_t)r2;
1270 : : r3 = -r3;
1271 : : rv += r3;
1272 : :
1273 : 2 : return cmp_res(__func__, rv, rc, dve.out, dvt->out, sizeof(dve.out));
1274 : : }
1275 : :
1276 : : /* endianness conversions (BE->LE/LE->BE) test-cases */
1277 : : static const struct ebpf_insn test_bele1_prog[] = {
1278 : :
1279 : : {
1280 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1281 : : .dst_reg = EBPF_REG_2,
1282 : : .src_reg = EBPF_REG_1,
1283 : : .off = offsetof(struct dummy_vect8, in[0].u16),
1284 : : },
1285 : : {
1286 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1287 : : .dst_reg = EBPF_REG_3,
1288 : : .src_reg = EBPF_REG_1,
1289 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1290 : : },
1291 : : {
1292 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1293 : : .dst_reg = EBPF_REG_4,
1294 : : .src_reg = EBPF_REG_1,
1295 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1296 : : },
1297 : : {
1298 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1299 : : .dst_reg = EBPF_REG_2,
1300 : : .imm = sizeof(uint16_t) * CHAR_BIT,
1301 : : },
1302 : : {
1303 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1304 : : .dst_reg = EBPF_REG_3,
1305 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1306 : : },
1307 : : {
1308 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
1309 : : .dst_reg = EBPF_REG_4,
1310 : : .imm = sizeof(uint64_t) * CHAR_BIT,
1311 : : },
1312 : : {
1313 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1314 : : .dst_reg = EBPF_REG_1,
1315 : : .src_reg = EBPF_REG_2,
1316 : : .off = offsetof(struct dummy_vect8, out[0].u64),
1317 : : },
1318 : : {
1319 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1320 : : .dst_reg = EBPF_REG_1,
1321 : : .src_reg = EBPF_REG_3,
1322 : : .off = offsetof(struct dummy_vect8, out[1].u64),
1323 : : },
1324 : : {
1325 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1326 : : .dst_reg = EBPF_REG_1,
1327 : : .src_reg = EBPF_REG_4,
1328 : : .off = offsetof(struct dummy_vect8, out[2].u64),
1329 : : },
1330 : : {
1331 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1332 : : .dst_reg = EBPF_REG_2,
1333 : : .src_reg = EBPF_REG_1,
1334 : : .off = offsetof(struct dummy_vect8, in[0].u16),
1335 : : },
1336 : : {
1337 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1338 : : .dst_reg = EBPF_REG_3,
1339 : : .src_reg = EBPF_REG_1,
1340 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1341 : : },
1342 : : {
1343 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1344 : : .dst_reg = EBPF_REG_4,
1345 : : .src_reg = EBPF_REG_1,
1346 : : .off = offsetof(struct dummy_vect8, in[0].u64),
1347 : : },
1348 : : {
1349 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1350 : : .dst_reg = EBPF_REG_2,
1351 : : .imm = sizeof(uint16_t) * CHAR_BIT,
1352 : : },
1353 : : {
1354 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1355 : : .dst_reg = EBPF_REG_3,
1356 : : .imm = sizeof(uint32_t) * CHAR_BIT,
1357 : : },
1358 : : {
1359 : : .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
1360 : : .dst_reg = EBPF_REG_4,
1361 : : .imm = sizeof(uint64_t) * CHAR_BIT,
1362 : : },
1363 : : {
1364 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1365 : : .dst_reg = EBPF_REG_1,
1366 : : .src_reg = EBPF_REG_2,
1367 : : .off = offsetof(struct dummy_vect8, out[3].u64),
1368 : : },
1369 : : {
1370 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1371 : : .dst_reg = EBPF_REG_1,
1372 : : .src_reg = EBPF_REG_3,
1373 : : .off = offsetof(struct dummy_vect8, out[4].u64),
1374 : : },
1375 : : {
1376 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1377 : : .dst_reg = EBPF_REG_1,
1378 : : .src_reg = EBPF_REG_4,
1379 : : .off = offsetof(struct dummy_vect8, out[5].u64),
1380 : : },
1381 : : /* return 1 */
1382 : : {
1383 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1384 : : .dst_reg = EBPF_REG_0,
1385 : : .imm = 1,
1386 : : },
1387 : : {
1388 : : .code = (BPF_JMP | EBPF_EXIT),
1389 : : },
1390 : : };
1391 : :
1392 : : static void
1393 : 2 : test_bele1_prepare(void *arg)
1394 : : {
1395 : : struct dummy_vect8 *dv;
1396 : :
1397 : : dv = arg;
1398 : :
1399 : : memset(dv, 0, sizeof(*dv));
1400 : 2 : dv->in[0].u64 = rte_rand();
1401 : 2 : dv->in[0].u32 = dv->in[0].u64;
1402 : 2 : dv->in[0].u16 = dv->in[0].u64;
1403 : 2 : }
1404 : :
1405 : : static int
1406 [ - + ]: 2 : test_bele1_check(uint64_t rc, const void *arg)
1407 : : {
1408 : : uint64_t r2, r3, r4;
1409 : : const struct dummy_vect8 *dvt;
1410 : : struct dummy_vect8 dve;
1411 : :
1412 : : dvt = arg;
1413 : : memset(&dve, 0, sizeof(dve));
1414 : :
1415 : 2 : r2 = dvt->in[0].u16;
1416 : 2 : r3 = dvt->in[0].u32;
1417 : 2 : r4 = dvt->in[0].u64;
1418 : :
1419 [ - + ]: 4 : r2 = rte_cpu_to_be_16(r2);
1420 [ - + ]: 4 : r3 = rte_cpu_to_be_32(r3);
1421 [ - + ]: 2 : r4 = rte_cpu_to_be_64(r4);
1422 : :
1423 : 2 : dve.out[0].u64 = r2;
1424 : 2 : dve.out[1].u64 = r3;
1425 : 2 : dve.out[2].u64 = r4;
1426 : :
1427 : : r2 = dvt->in[0].u16;
1428 : : r3 = dvt->in[0].u32;
1429 : : r4 = dvt->in[0].u64;
1430 : :
1431 : : r2 = rte_cpu_to_le_16(r2);
1432 : : r3 = rte_cpu_to_le_32(r3);
1433 : : r4 = rte_cpu_to_le_64(r4);
1434 : :
1435 : 2 : dve.out[3].u64 = r2;
1436 : 2 : dve.out[4].u64 = r3;
1437 : 2 : dve.out[5].u64 = r4;
1438 : :
1439 : 2 : return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
1440 : : }
1441 : :
1442 : : /* atomic add test-cases */
1443 : : static const struct ebpf_insn test_xadd1_prog[] = {
1444 : :
1445 : : {
1446 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1447 : : .dst_reg = EBPF_REG_2,
1448 : : .imm = 1,
1449 : : },
1450 : : {
1451 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1452 : : .dst_reg = EBPF_REG_1,
1453 : : .src_reg = EBPF_REG_2,
1454 : : .off = offsetof(struct dummy_offset, u32),
1455 : : },
1456 : : {
1457 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1458 : : .dst_reg = EBPF_REG_1,
1459 : : .src_reg = EBPF_REG_2,
1460 : : .off = offsetof(struct dummy_offset, u64),
1461 : : },
1462 : : {
1463 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1464 : : .dst_reg = EBPF_REG_3,
1465 : : .imm = -1,
1466 : : },
1467 : : {
1468 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1469 : : .dst_reg = EBPF_REG_1,
1470 : : .src_reg = EBPF_REG_3,
1471 : : .off = offsetof(struct dummy_offset, u32),
1472 : : },
1473 : : {
1474 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1475 : : .dst_reg = EBPF_REG_1,
1476 : : .src_reg = EBPF_REG_3,
1477 : : .off = offsetof(struct dummy_offset, u64),
1478 : : },
1479 : : {
1480 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1481 : : .dst_reg = EBPF_REG_4,
1482 : : .imm = TEST_FILL_1,
1483 : : },
1484 : : {
1485 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1486 : : .dst_reg = EBPF_REG_1,
1487 : : .src_reg = EBPF_REG_4,
1488 : : .off = offsetof(struct dummy_offset, u32),
1489 : : },
1490 : : {
1491 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1492 : : .dst_reg = EBPF_REG_1,
1493 : : .src_reg = EBPF_REG_4,
1494 : : .off = offsetof(struct dummy_offset, u64),
1495 : : },
1496 : : {
1497 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1498 : : .dst_reg = EBPF_REG_5,
1499 : : .imm = TEST_MUL_1,
1500 : : },
1501 : : {
1502 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1503 : : .dst_reg = EBPF_REG_1,
1504 : : .src_reg = EBPF_REG_5,
1505 : : .off = offsetof(struct dummy_offset, u32),
1506 : : },
1507 : : {
1508 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1509 : : .dst_reg = EBPF_REG_1,
1510 : : .src_reg = EBPF_REG_5,
1511 : : .off = offsetof(struct dummy_offset, u64),
1512 : : },
1513 : : {
1514 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1515 : : .dst_reg = EBPF_REG_6,
1516 : : .imm = TEST_MUL_2,
1517 : : },
1518 : : {
1519 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1520 : : .dst_reg = EBPF_REG_1,
1521 : : .src_reg = EBPF_REG_6,
1522 : : .off = offsetof(struct dummy_offset, u32),
1523 : : },
1524 : : {
1525 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1526 : : .dst_reg = EBPF_REG_1,
1527 : : .src_reg = EBPF_REG_6,
1528 : : .off = offsetof(struct dummy_offset, u64),
1529 : : },
1530 : : {
1531 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1532 : : .dst_reg = EBPF_REG_7,
1533 : : .imm = TEST_JCC_2,
1534 : : },
1535 : : {
1536 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1537 : : .dst_reg = EBPF_REG_1,
1538 : : .src_reg = EBPF_REG_7,
1539 : : .off = offsetof(struct dummy_offset, u32),
1540 : : },
1541 : : {
1542 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1543 : : .dst_reg = EBPF_REG_1,
1544 : : .src_reg = EBPF_REG_7,
1545 : : .off = offsetof(struct dummy_offset, u64),
1546 : : },
1547 : : {
1548 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
1549 : : .dst_reg = EBPF_REG_8,
1550 : : .imm = TEST_JCC_3,
1551 : : },
1552 : : {
1553 : : .code = (BPF_STX | EBPF_XADD | BPF_W),
1554 : : .dst_reg = EBPF_REG_1,
1555 : : .src_reg = EBPF_REG_8,
1556 : : .off = offsetof(struct dummy_offset, u32),
1557 : : },
1558 : : {
1559 : : .code = (BPF_STX | EBPF_XADD | EBPF_DW),
1560 : : .dst_reg = EBPF_REG_1,
1561 : : .src_reg = EBPF_REG_8,
1562 : : .off = offsetof(struct dummy_offset, u64),
1563 : : },
1564 : : /* return 1 */
1565 : : {
1566 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1567 : : .dst_reg = EBPF_REG_0,
1568 : : .imm = 1,
1569 : : },
1570 : : {
1571 : : .code = (BPF_JMP | EBPF_EXIT),
1572 : : },
1573 : : };
1574 : :
1575 : : static int
1576 : 2 : test_xadd1_check(uint64_t rc, const void *arg)
1577 : : {
1578 : : uint64_t rv;
1579 : : const struct dummy_offset *dft;
1580 : : struct dummy_offset dfe;
1581 : :
1582 : : dft = arg;
1583 : : memset(&dfe, 0, sizeof(dfe));
1584 : :
1585 : : rv = 1;
1586 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1587 : : rte_memory_order_relaxed);
1588 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1589 : : rte_memory_order_relaxed);
1590 : :
1591 : : rv = -1;
1592 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1593 : : rte_memory_order_relaxed);
1594 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1595 : : rte_memory_order_relaxed);
1596 : :
1597 : : rv = (int32_t)TEST_FILL_1;
1598 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1599 : : rte_memory_order_relaxed);
1600 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1601 : : rte_memory_order_relaxed);
1602 : :
1603 : : rv = TEST_MUL_1;
1604 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1605 : : rte_memory_order_relaxed);
1606 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1607 : : rte_memory_order_relaxed);
1608 : :
1609 : : rv = TEST_MUL_2;
1610 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1611 : : rte_memory_order_relaxed);
1612 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1613 : : rte_memory_order_relaxed);
1614 : :
1615 : : rv = TEST_JCC_2;
1616 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1617 : : rte_memory_order_relaxed);
1618 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1619 : : rte_memory_order_relaxed);
1620 : :
1621 : : rv = TEST_JCC_3;
1622 : 2 : rte_atomic_fetch_add_explicit((uint32_t __rte_atomic *)&dfe.u32, rv,
1623 : : rte_memory_order_relaxed);
1624 : 2 : rte_atomic_fetch_add_explicit((uint64_t __rte_atomic *)&dfe.u64, rv,
1625 : : rte_memory_order_relaxed);
1626 : :
1627 : 2 : return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
1628 : : }
1629 : :
1630 : : /* alu div test-cases */
1631 : : static const struct ebpf_insn test_div1_prog[] = {
1632 : :
1633 : : {
1634 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1635 : : .dst_reg = EBPF_REG_2,
1636 : : .src_reg = EBPF_REG_1,
1637 : : .off = offsetof(struct dummy_vect8, in[0].u32),
1638 : : },
1639 : : {
1640 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1641 : : .dst_reg = EBPF_REG_3,
1642 : : .src_reg = EBPF_REG_1,
1643 : : .off = offsetof(struct dummy_vect8, in[1].u64),
1644 : : },
1645 : : {
1646 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1647 : : .dst_reg = EBPF_REG_4,
1648 : : .src_reg = EBPF_REG_1,
1649 : : .off = offsetof(struct dummy_vect8, in[2].u32),
1650 : : },
1651 : : {
1652 : : .code = (BPF_ALU | BPF_DIV | BPF_K),
1653 : : .dst_reg = EBPF_REG_2,
1654 : : .imm = TEST_MUL_1,
1655 : : },
1656 : : {
1657 : : .code = (EBPF_ALU64 | BPF_MOD | BPF_K),
1658 : : .dst_reg = EBPF_REG_3,
1659 : : .imm = TEST_MUL_2,
1660 : : },
1661 : : {
1662 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1663 : : .dst_reg = EBPF_REG_2,
1664 : : .imm = 1,
1665 : : },
1666 : : {
1667 : : .code = (EBPF_ALU64 | BPF_OR | BPF_K),
1668 : : .dst_reg = EBPF_REG_3,
1669 : : .imm = 1,
1670 : : },
1671 : : {
1672 : : .code = (BPF_ALU | BPF_MOD | BPF_X),
1673 : : .dst_reg = EBPF_REG_4,
1674 : : .src_reg = EBPF_REG_2,
1675 : : },
1676 : : {
1677 : : .code = (EBPF_ALU64 | BPF_DIV | BPF_X),
1678 : : .dst_reg = EBPF_REG_4,
1679 : : .src_reg = EBPF_REG_3,
1680 : : },
1681 : : {
1682 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1683 : : .dst_reg = EBPF_REG_1,
1684 : : .src_reg = EBPF_REG_2,
1685 : : .off = offsetof(struct dummy_vect8, out[0].u64),
1686 : : },
1687 : : {
1688 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1689 : : .dst_reg = EBPF_REG_1,
1690 : : .src_reg = EBPF_REG_3,
1691 : : .off = offsetof(struct dummy_vect8, out[1].u64),
1692 : : },
1693 : : {
1694 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1695 : : .dst_reg = EBPF_REG_1,
1696 : : .src_reg = EBPF_REG_4,
1697 : : .off = offsetof(struct dummy_vect8, out[2].u64),
1698 : : },
1699 : : /* check that we can handle division by zero gracefully. */
1700 : : {
1701 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1702 : : .dst_reg = EBPF_REG_2,
1703 : : .src_reg = EBPF_REG_1,
1704 : : .off = offsetof(struct dummy_vect8, in[3].u32),
1705 : : },
1706 : : {
1707 : : .code = (BPF_ALU | BPF_DIV | BPF_X),
1708 : : .dst_reg = EBPF_REG_4,
1709 : : .src_reg = EBPF_REG_2,
1710 : : },
1711 : : /* return 1 */
1712 : : {
1713 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
1714 : : .dst_reg = EBPF_REG_0,
1715 : : .imm = 1,
1716 : : },
1717 : : {
1718 : : .code = (BPF_JMP | EBPF_EXIT),
1719 : : },
1720 : : };
1721 : :
1722 : : static int
1723 : 2 : test_div1_check(uint64_t rc, const void *arg)
1724 : : {
1725 : : uint64_t r2, r3, r4;
1726 : : const struct dummy_vect8 *dvt;
1727 : : struct dummy_vect8 dve;
1728 : :
1729 : : dvt = arg;
1730 : : memset(&dve, 0, sizeof(dve));
1731 : :
1732 : 2 : r2 = dvt->in[0].u32;
1733 : 2 : r3 = dvt->in[1].u64;
1734 : 2 : r4 = dvt->in[2].u32;
1735 : :
1736 : 2 : r2 = (uint32_t)r2 / TEST_MUL_1;
1737 : 2 : r3 %= TEST_MUL_2;
1738 : 2 : r2 |= 1;
1739 : 2 : r3 |= 1;
1740 : 2 : r4 = (uint32_t)(r4 % r2);
1741 : 2 : r4 /= r3;
1742 : :
1743 : 2 : dve.out[0].u64 = r2;
1744 : 2 : dve.out[1].u64 = r3;
1745 : 2 : dve.out[2].u64 = r4;
1746 : :
1747 : : /*
1748 : : * in the test prog we attempted to divide by zero.
1749 : : * so return value should return 0.
1750 : : */
1751 : 2 : return cmp_res(__func__, 0, rc, dve.out, dvt->out, sizeof(dve.out));
1752 : : }
1753 : :
1754 : : /* call test-cases */
1755 : : static const struct ebpf_insn test_call1_prog[] = {
1756 : :
1757 : : {
1758 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1759 : : .dst_reg = EBPF_REG_2,
1760 : : .src_reg = EBPF_REG_1,
1761 : : .off = offsetof(struct dummy_offset, u32),
1762 : : },
1763 : : {
1764 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1765 : : .dst_reg = EBPF_REG_3,
1766 : : .src_reg = EBPF_REG_1,
1767 : : .off = offsetof(struct dummy_offset, u64),
1768 : : },
1769 : : {
1770 : : .code = (BPF_STX | BPF_MEM | BPF_W),
1771 : : .dst_reg = EBPF_REG_10,
1772 : : .src_reg = EBPF_REG_2,
1773 : : .off = -4,
1774 : : },
1775 : : {
1776 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
1777 : : .dst_reg = EBPF_REG_10,
1778 : : .src_reg = EBPF_REG_3,
1779 : : .off = -16,
1780 : : },
1781 : : {
1782 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1783 : : .dst_reg = EBPF_REG_2,
1784 : : .src_reg = EBPF_REG_10,
1785 : : },
1786 : : {
1787 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
1788 : : .dst_reg = EBPF_REG_2,
1789 : : .imm = 4,
1790 : : },
1791 : : {
1792 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1793 : : .dst_reg = EBPF_REG_3,
1794 : : .src_reg = EBPF_REG_10,
1795 : : },
1796 : : {
1797 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
1798 : : .dst_reg = EBPF_REG_3,
1799 : : .imm = 16,
1800 : : },
1801 : : {
1802 : : .code = (BPF_JMP | EBPF_CALL),
1803 : : .imm = 0,
1804 : : },
1805 : : {
1806 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1807 : : .dst_reg = EBPF_REG_2,
1808 : : .src_reg = EBPF_REG_10,
1809 : : .off = -4,
1810 : : },
1811 : : {
1812 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1813 : : .dst_reg = EBPF_REG_0,
1814 : : .src_reg = EBPF_REG_10,
1815 : : .off = -16
1816 : : },
1817 : : {
1818 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1819 : : .dst_reg = EBPF_REG_0,
1820 : : .src_reg = EBPF_REG_2,
1821 : : },
1822 : : {
1823 : : .code = (BPF_JMP | EBPF_EXIT),
1824 : : },
1825 : : };
1826 : :
1827 : : static void
1828 : 2 : dummy_func1(const void *p, uint32_t *v32, uint64_t *v64)
1829 : : {
1830 : : const struct dummy_offset *dv;
1831 : :
1832 : : dv = p;
1833 : :
1834 : 4 : v32[0] += dv->u16;
1835 : 4 : v64[0] += dv->u8;
1836 : 2 : }
1837 : :
1838 : : static int
1839 : 2 : test_call1_check(uint64_t rc, const void *arg)
1840 : : {
1841 : : uint32_t v32;
1842 : : uint64_t v64;
1843 : : const struct dummy_offset *dv;
1844 : :
1845 : : dv = arg;
1846 : :
1847 : 2 : v32 = dv->u32;
1848 : 2 : v64 = dv->u64;
1849 : : dummy_func1(arg, &v32, &v64);
1850 : 2 : v64 += v32;
1851 : :
1852 : 2 : return cmp_res(__func__, v64, rc, dv, dv, sizeof(*dv));
1853 : : }
1854 : :
1855 : : static const struct rte_bpf_xsym test_call1_xsym[] = {
1856 : : {
1857 : : .name = RTE_STR(dummy_func1),
1858 : : .type = RTE_BPF_XTYPE_FUNC,
1859 : : .func = {
1860 : : .val = (void *)dummy_func1,
1861 : : .nb_args = 3,
1862 : : .args = {
1863 : : [0] = {
1864 : : .type = RTE_BPF_ARG_PTR,
1865 : : .size = sizeof(struct dummy_offset),
1866 : : },
1867 : : [1] = {
1868 : : .type = RTE_BPF_ARG_PTR,
1869 : : .size = sizeof(uint32_t),
1870 : : },
1871 : : [2] = {
1872 : : .type = RTE_BPF_ARG_PTR,
1873 : : .size = sizeof(uint64_t),
1874 : : },
1875 : : },
1876 : : },
1877 : : },
1878 : : };
1879 : :
1880 : : static const struct ebpf_insn test_call2_prog[] = {
1881 : :
1882 : : {
1883 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1884 : : .dst_reg = EBPF_REG_1,
1885 : : .src_reg = EBPF_REG_10,
1886 : : },
1887 : : {
1888 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1889 : : .dst_reg = EBPF_REG_1,
1890 : : .imm = -(int32_t)sizeof(struct dummy_offset),
1891 : : },
1892 : : {
1893 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
1894 : : .dst_reg = EBPF_REG_2,
1895 : : .src_reg = EBPF_REG_10,
1896 : : },
1897 : : {
1898 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
1899 : : .dst_reg = EBPF_REG_2,
1900 : : .imm = -2 * (int32_t)sizeof(struct dummy_offset),
1901 : : },
1902 : : {
1903 : : .code = (BPF_JMP | EBPF_CALL),
1904 : : .imm = 0,
1905 : : },
1906 : : {
1907 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
1908 : : .dst_reg = EBPF_REG_1,
1909 : : .src_reg = EBPF_REG_10,
1910 : : .off = -(int32_t)(sizeof(struct dummy_offset) -
1911 : : offsetof(struct dummy_offset, u64)),
1912 : : },
1913 : : {
1914 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
1915 : : .dst_reg = EBPF_REG_0,
1916 : : .src_reg = EBPF_REG_10,
1917 : : .off = -(int32_t)(sizeof(struct dummy_offset) -
1918 : : offsetof(struct dummy_offset, u32)),
1919 : : },
1920 : : {
1921 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1922 : : .dst_reg = EBPF_REG_0,
1923 : : .src_reg = EBPF_REG_1,
1924 : : },
1925 : : {
1926 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
1927 : : .dst_reg = EBPF_REG_1,
1928 : : .src_reg = EBPF_REG_10,
1929 : : .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
1930 : : offsetof(struct dummy_offset, u16)),
1931 : : },
1932 : : {
1933 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1934 : : .dst_reg = EBPF_REG_0,
1935 : : .src_reg = EBPF_REG_1,
1936 : : },
1937 : : {
1938 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
1939 : : .dst_reg = EBPF_REG_1,
1940 : : .src_reg = EBPF_REG_10,
1941 : : .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
1942 : : offsetof(struct dummy_offset, u8)),
1943 : : },
1944 : : {
1945 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
1946 : : .dst_reg = EBPF_REG_0,
1947 : : .src_reg = EBPF_REG_1,
1948 : : },
1949 : : {
1950 : : .code = (BPF_JMP | EBPF_EXIT),
1951 : : },
1952 : :
1953 : : };
1954 : :
1955 : : static void
1956 : 2 : dummy_func2(struct dummy_offset *a, struct dummy_offset *b)
1957 : : {
1958 : : uint64_t v;
1959 : :
1960 : : v = 0;
1961 : 2 : a->u64 = v++;
1962 : 2 : a->u32 = v++;
1963 : 2 : a->u16 = v++;
1964 : 2 : a->u8 = v++;
1965 : 2 : b->u64 = v++;
1966 : 2 : b->u32 = v++;
1967 : 2 : b->u16 = v++;
1968 : 2 : b->u8 = v++;
1969 : 2 : }
1970 : :
1971 : : static int
1972 : 2 : test_call2_check(uint64_t rc, const void *arg)
1973 : : {
1974 : : uint64_t v;
1975 : : struct dummy_offset a, b;
1976 : :
1977 : : RTE_SET_USED(arg);
1978 : :
1979 : : dummy_func2(&a, &b);
1980 : : v = a.u64 + a.u32 + b.u16 + b.u8;
1981 : :
1982 : 2 : return cmp_res(__func__, v, rc, arg, arg, 0);
1983 : : }
1984 : :
1985 : : static const struct rte_bpf_xsym test_call2_xsym[] = {
1986 : : {
1987 : : .name = RTE_STR(dummy_func2),
1988 : : .type = RTE_BPF_XTYPE_FUNC,
1989 : : .func = {
1990 : : .val = (void *)dummy_func2,
1991 : : .nb_args = 2,
1992 : : .args = {
1993 : : [0] = {
1994 : : .type = RTE_BPF_ARG_PTR,
1995 : : .size = sizeof(struct dummy_offset),
1996 : : },
1997 : : [1] = {
1998 : : .type = RTE_BPF_ARG_PTR,
1999 : : .size = sizeof(struct dummy_offset),
2000 : : },
2001 : : },
2002 : : },
2003 : : },
2004 : : };
2005 : :
2006 : : static const struct ebpf_insn test_call3_prog[] = {
2007 : :
2008 : : {
2009 : : .code = (BPF_JMP | EBPF_CALL),
2010 : : .imm = 0,
2011 : : },
2012 : : {
2013 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2014 : : .dst_reg = EBPF_REG_2,
2015 : : .src_reg = EBPF_REG_0,
2016 : : .off = offsetof(struct dummy_offset, u8),
2017 : : },
2018 : : {
2019 : : .code = (BPF_LDX | BPF_MEM | BPF_H),
2020 : : .dst_reg = EBPF_REG_3,
2021 : : .src_reg = EBPF_REG_0,
2022 : : .off = offsetof(struct dummy_offset, u16),
2023 : : },
2024 : : {
2025 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
2026 : : .dst_reg = EBPF_REG_4,
2027 : : .src_reg = EBPF_REG_0,
2028 : : .off = offsetof(struct dummy_offset, u32),
2029 : : },
2030 : : {
2031 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2032 : : .dst_reg = EBPF_REG_0,
2033 : : .src_reg = EBPF_REG_0,
2034 : : .off = offsetof(struct dummy_offset, u64),
2035 : : },
2036 : : /* return sum */
2037 : : {
2038 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2039 : : .dst_reg = EBPF_REG_0,
2040 : : .src_reg = EBPF_REG_4,
2041 : : },
2042 : : {
2043 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2044 : : .dst_reg = EBPF_REG_0,
2045 : : .src_reg = EBPF_REG_3,
2046 : : },
2047 : : {
2048 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2049 : : .dst_reg = EBPF_REG_0,
2050 : : .src_reg = EBPF_REG_2,
2051 : : },
2052 : : {
2053 : : .code = (BPF_JMP | EBPF_EXIT),
2054 : : },
2055 : : };
2056 : :
2057 : : static const struct dummy_offset *
2058 : 2 : dummy_func3(const struct dummy_vect8 *p)
2059 : : {
2060 : 2 : return &p->in[RTE_DIM(p->in) - 1];
2061 : : }
2062 : :
2063 : : static void
2064 : 2 : test_call3_prepare(void *arg)
2065 : : {
2066 : : struct dummy_vect8 *pv;
2067 : : struct dummy_offset *df;
2068 : :
2069 : : pv = arg;
2070 : : df = (struct dummy_offset *)(uintptr_t)dummy_func3(pv);
2071 : :
2072 : : memset(pv, 0, sizeof(*pv));
2073 : 2 : df->u64 = (int32_t)TEST_FILL_1;
2074 : 2 : df->u32 = df->u64;
2075 : 2 : df->u16 = df->u64;
2076 : 2 : df->u8 = df->u64;
2077 : 2 : }
2078 : :
2079 : : static int
2080 : 2 : test_call3_check(uint64_t rc, const void *arg)
2081 : : {
2082 : : uint64_t v;
2083 : : const struct dummy_vect8 *pv;
2084 : : const struct dummy_offset *dft;
2085 : :
2086 : : pv = arg;
2087 : : dft = dummy_func3(pv);
2088 : :
2089 : 2 : v = dft->u64;
2090 : 2 : v += dft->u32;
2091 : 2 : v += dft->u16;
2092 : 2 : v += dft->u8;
2093 : :
2094 : 2 : return cmp_res(__func__, v, rc, pv, pv, sizeof(*pv));
2095 : : }
2096 : :
2097 : : static const struct rte_bpf_xsym test_call3_xsym[] = {
2098 : : {
2099 : : .name = RTE_STR(dummy_func3),
2100 : : .type = RTE_BPF_XTYPE_FUNC,
2101 : : .func = {
2102 : : .val = (void *)dummy_func3,
2103 : : .nb_args = 1,
2104 : : .args = {
2105 : : [0] = {
2106 : : .type = RTE_BPF_ARG_PTR,
2107 : : .size = sizeof(struct dummy_vect8),
2108 : : },
2109 : : },
2110 : : .ret = {
2111 : : .type = RTE_BPF_ARG_PTR,
2112 : : .size = sizeof(struct dummy_offset),
2113 : : },
2114 : : },
2115 : : },
2116 : : };
2117 : :
2118 : : /* Test for stack corruption in multiple function calls */
2119 : : static const struct ebpf_insn test_call4_prog[] = {
2120 : : {
2121 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2122 : : .dst_reg = EBPF_REG_10,
2123 : : .off = -4,
2124 : : .imm = 1,
2125 : : },
2126 : : {
2127 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2128 : : .dst_reg = EBPF_REG_10,
2129 : : .off = -3,
2130 : : .imm = 2,
2131 : : },
2132 : : {
2133 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2134 : : .dst_reg = EBPF_REG_10,
2135 : : .off = -2,
2136 : : .imm = 3,
2137 : : },
2138 : : {
2139 : : .code = (BPF_ST | BPF_MEM | BPF_B),
2140 : : .dst_reg = EBPF_REG_10,
2141 : : .off = -1,
2142 : : .imm = 4,
2143 : : },
2144 : : {
2145 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2146 : : .dst_reg = EBPF_REG_1,
2147 : : .src_reg = EBPF_REG_10,
2148 : : },
2149 : : {
2150 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2151 : : .dst_reg = EBPF_REG_2,
2152 : : .imm = 4,
2153 : : },
2154 : : {
2155 : : .code = (EBPF_ALU64 | BPF_SUB | BPF_X),
2156 : : .dst_reg = EBPF_REG_1,
2157 : : .src_reg = EBPF_REG_2,
2158 : : },
2159 : : {
2160 : : .code = (BPF_JMP | EBPF_CALL),
2161 : : .imm = 0,
2162 : : },
2163 : : {
2164 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2165 : : .dst_reg = EBPF_REG_1,
2166 : : .src_reg = EBPF_REG_10,
2167 : : .off = -4,
2168 : : },
2169 : : {
2170 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2171 : : .dst_reg = EBPF_REG_2,
2172 : : .src_reg = EBPF_REG_10,
2173 : : .off = -3,
2174 : : },
2175 : : {
2176 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2177 : : .dst_reg = EBPF_REG_3,
2178 : : .src_reg = EBPF_REG_10,
2179 : : .off = -2,
2180 : : },
2181 : : {
2182 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2183 : : .dst_reg = EBPF_REG_4,
2184 : : .src_reg = EBPF_REG_10,
2185 : : .off = -1,
2186 : : },
2187 : : {
2188 : : .code = (BPF_JMP | EBPF_CALL),
2189 : : .imm = 1,
2190 : : },
2191 : : {
2192 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_K),
2193 : : .dst_reg = EBPF_REG_0,
2194 : : .imm = TEST_MEMFROB,
2195 : : },
2196 : : {
2197 : : .code = (BPF_JMP | EBPF_EXIT),
2198 : : },
2199 : : };
2200 : :
2201 : : /* Gathering the bytes together */
2202 : : static uint32_t
2203 : 2 : dummy_func4_1(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
2204 : : {
2205 : 4 : return (a << 24) | (b << 16) | (c << 8) | (d << 0);
2206 : : }
2207 : :
2208 : : /* Implementation of memfrob */
2209 : : static uint32_t
2210 : 2 : dummy_func4_0(uint32_t *s, uint8_t n)
2211 : : {
2212 : : char *p = (char *) s;
2213 [ + + + + ]: 20 : while (n-- > 0)
2214 : 16 : *p++ ^= 42;
2215 : 2 : return *s;
2216 : : }
2217 : :
2218 : :
2219 : : static int
2220 : 2 : test_call4_check(uint64_t rc, const void *arg)
2221 : : {
2222 : 2 : uint8_t a[4] = {1, 2, 3, 4};
2223 : : uint32_t s, v = 0;
2224 : :
2225 : : RTE_SET_USED(arg);
2226 : :
2227 : : s = dummy_func4_0((uint32_t *)a, 4);
2228 : :
2229 : 2 : s = dummy_func4_1(a[0], a[1], a[2], a[3]);
2230 : :
2231 : 2 : v = s ^ TEST_MEMFROB;
2232 : :
2233 : 2 : return cmp_res(__func__, v, rc, &v, &rc, sizeof(v));
2234 : : }
2235 : :
2236 : : static const struct rte_bpf_xsym test_call4_xsym[] = {
2237 : : [0] = {
2238 : : .name = RTE_STR(dummy_func4_0),
2239 : : .type = RTE_BPF_XTYPE_FUNC,
2240 : : .func = {
2241 : : .val = (void *)dummy_func4_0,
2242 : : .nb_args = 2,
2243 : : .args = {
2244 : : [0] = {
2245 : : .type = RTE_BPF_ARG_PTR,
2246 : : .size = 4 * sizeof(uint8_t),
2247 : : },
2248 : : [1] = {
2249 : : .type = RTE_BPF_ARG_RAW,
2250 : : .size = sizeof(uint8_t),
2251 : : },
2252 : : },
2253 : : .ret = {
2254 : : .type = RTE_BPF_ARG_RAW,
2255 : : .size = sizeof(uint32_t),
2256 : : },
2257 : : },
2258 : : },
2259 : : [1] = {
2260 : : .name = RTE_STR(dummy_func4_1),
2261 : : .type = RTE_BPF_XTYPE_FUNC,
2262 : : .func = {
2263 : : .val = (void *)dummy_func4_1,
2264 : : .nb_args = 4,
2265 : : .args = {
2266 : : [0] = {
2267 : : .type = RTE_BPF_ARG_RAW,
2268 : : .size = sizeof(uint8_t),
2269 : : },
2270 : : [1] = {
2271 : : .type = RTE_BPF_ARG_RAW,
2272 : : .size = sizeof(uint8_t),
2273 : : },
2274 : : [2] = {
2275 : : .type = RTE_BPF_ARG_RAW,
2276 : : .size = sizeof(uint8_t),
2277 : : },
2278 : : [3] = {
2279 : : .type = RTE_BPF_ARG_RAW,
2280 : : .size = sizeof(uint8_t),
2281 : : },
2282 : : },
2283 : : .ret = {
2284 : : .type = RTE_BPF_ARG_RAW,
2285 : : .size = sizeof(uint32_t),
2286 : : },
2287 : : },
2288 : : },
2289 : : };
2290 : :
2291 : : /* string compare test case */
2292 : : static const struct ebpf_insn test_call5_prog[] = {
2293 : :
2294 : : [0] = {
2295 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2296 : : .dst_reg = EBPF_REG_1,
2297 : : .imm = STRING_GEEK,
2298 : : },
2299 : : [1] = {
2300 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2301 : : .dst_reg = EBPF_REG_10,
2302 : : .src_reg = EBPF_REG_1,
2303 : : .off = -8,
2304 : : },
2305 : : [2] = {
2306 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2307 : : .dst_reg = EBPF_REG_6,
2308 : : .imm = 0,
2309 : : },
2310 : : [3] = {
2311 : : .code = (BPF_STX | BPF_MEM | BPF_B),
2312 : : .dst_reg = EBPF_REG_10,
2313 : : .src_reg = EBPF_REG_6,
2314 : : .off = -4,
2315 : : },
2316 : : [4] = {
2317 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2318 : : .dst_reg = EBPF_REG_10,
2319 : : .src_reg = EBPF_REG_6,
2320 : : .off = -12,
2321 : : },
2322 : : [5] = {
2323 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2324 : : .dst_reg = EBPF_REG_1,
2325 : : .imm = STRING_WEEK,
2326 : : },
2327 : : [6] = {
2328 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2329 : : .dst_reg = EBPF_REG_10,
2330 : : .src_reg = EBPF_REG_1,
2331 : : .off = -16,
2332 : : },
2333 : : [7] = {
2334 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2335 : : .dst_reg = EBPF_REG_1,
2336 : : .src_reg = EBPF_REG_10,
2337 : : },
2338 : : [8] = {
2339 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2340 : : .dst_reg = EBPF_REG_1,
2341 : : .imm = -8,
2342 : : },
2343 : : [9] = {
2344 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2345 : : .dst_reg = EBPF_REG_2,
2346 : : .src_reg = EBPF_REG_1,
2347 : : },
2348 : : [10] = {
2349 : : .code = (BPF_JMP | EBPF_CALL),
2350 : : .imm = 0,
2351 : : },
2352 : : [11] = {
2353 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2354 : : .dst_reg = EBPF_REG_1,
2355 : : .src_reg = EBPF_REG_0,
2356 : : },
2357 : : [12] = {
2358 : : .code = (BPF_ALU | EBPF_MOV | BPF_K),
2359 : : .dst_reg = EBPF_REG_0,
2360 : : .imm = -1,
2361 : : },
2362 : : [13] = {
2363 : : .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
2364 : : .dst_reg = EBPF_REG_1,
2365 : : .imm = 0x20,
2366 : : },
2367 : : [14] = {
2368 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2369 : : .dst_reg = EBPF_REG_1,
2370 : : .imm = 0x20,
2371 : : },
2372 : : [15] = {
2373 : : .code = (BPF_JMP | EBPF_JNE | BPF_K),
2374 : : .dst_reg = EBPF_REG_1,
2375 : : .off = 11,
2376 : : .imm = 0,
2377 : : },
2378 : : [16] = {
2379 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2380 : : .dst_reg = EBPF_REG_1,
2381 : : .src_reg = EBPF_REG_10,
2382 : : },
2383 : : [17] = {
2384 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2385 : : .dst_reg = EBPF_REG_1,
2386 : : .imm = -8,
2387 : : },
2388 : : [18] = {
2389 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2390 : : .dst_reg = EBPF_REG_2,
2391 : : .src_reg = EBPF_REG_10,
2392 : : },
2393 : : [19] = {
2394 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
2395 : : .dst_reg = EBPF_REG_2,
2396 : : .imm = -16,
2397 : : },
2398 : : [20] = {
2399 : : .code = (BPF_JMP | EBPF_CALL),
2400 : : .imm = 0,
2401 : : },
2402 : : [21] = {
2403 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2404 : : .dst_reg = EBPF_REG_1,
2405 : : .src_reg = EBPF_REG_0,
2406 : : },
2407 : : [22] = {
2408 : : .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
2409 : : .dst_reg = EBPF_REG_1,
2410 : : .imm = 0x20,
2411 : : },
2412 : : [23] = {
2413 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2414 : : .dst_reg = EBPF_REG_1,
2415 : : .imm = 0x20,
2416 : : },
2417 : : [24] = {
2418 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2419 : : .dst_reg = EBPF_REG_0,
2420 : : .src_reg = EBPF_REG_1,
2421 : : },
2422 : : [25] = {
2423 : : .code = (BPF_JMP | BPF_JEQ | BPF_X),
2424 : : .dst_reg = EBPF_REG_1,
2425 : : .src_reg = EBPF_REG_6,
2426 : : .off = 1,
2427 : : },
2428 : : [26] = {
2429 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
2430 : : .dst_reg = EBPF_REG_0,
2431 : : .imm = 0,
2432 : : },
2433 : : [27] = {
2434 : : .code = (BPF_JMP | EBPF_EXIT),
2435 : : },
2436 : : };
2437 : :
2438 : : /* String comparison implementation, return 0 if equal else difference */
2439 : : static uint32_t
2440 : 4 : dummy_func5(const char *s1, const char *s2)
2441 : : {
2442 [ + + + + : 22 : while (*s1 && (*s1 == *s2)) {
+ + ]
2443 : 8 : s1++;
2444 : 8 : s2++;
2445 : : }
2446 : 4 : return *(const unsigned char *)s1 - *(const unsigned char *)s2;
2447 : : }
2448 : :
2449 : : static int
2450 : 2 : test_call5_check(uint64_t rc, const void *arg)
2451 : : {
2452 : 2 : char a[] = "geek";
2453 : : char b[] = "week";
2454 : : uint32_t v;
2455 : :
2456 : : RTE_SET_USED(arg);
2457 : :
2458 : 2 : v = dummy_func5(a, a);
2459 : : if (v != 0) {
2460 : : v = -1;
2461 : : goto fail;
2462 : : }
2463 : :
2464 : : v = dummy_func5(a, b);
2465 : : if (v == 0)
2466 : : goto fail;
2467 : :
2468 : : v = 0;
2469 : :
2470 : : fail:
2471 : 2 : return cmp_res(__func__, v, rc, &v, &rc, sizeof(v));
2472 : : }
2473 : :
2474 : : static const struct rte_bpf_xsym test_call5_xsym[] = {
2475 : : [0] = {
2476 : : .name = RTE_STR(dummy_func5),
2477 : : .type = RTE_BPF_XTYPE_FUNC,
2478 : : .func = {
2479 : : .val = (void *)dummy_func5,
2480 : : .nb_args = 2,
2481 : : .args = {
2482 : : [0] = {
2483 : : .type = RTE_BPF_ARG_PTR,
2484 : : .size = sizeof(char),
2485 : : },
2486 : : [1] = {
2487 : : .type = RTE_BPF_ARG_PTR,
2488 : : .size = sizeof(char),
2489 : : },
2490 : : },
2491 : : .ret = {
2492 : : .type = RTE_BPF_ARG_RAW,
2493 : : .size = sizeof(uint32_t),
2494 : : },
2495 : : },
2496 : : },
2497 : : };
2498 : :
2499 : : /* load mbuf (BPF_ABS/BPF_IND) test-cases */
2500 : : static const struct ebpf_insn test_ld_mbuf1_prog[] = {
2501 : :
2502 : : /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
2503 : : {
2504 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2505 : : .dst_reg = EBPF_REG_6,
2506 : : .src_reg = EBPF_REG_1,
2507 : : },
2508 : : /* load IPv4 version and IHL */
2509 : : {
2510 : : .code = (BPF_LD | BPF_ABS | BPF_B),
2511 : : .imm = offsetof(struct rte_ipv4_hdr, version_ihl),
2512 : : },
2513 : : /* check IP version */
2514 : : {
2515 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2516 : : .dst_reg = EBPF_REG_2,
2517 : : .src_reg = EBPF_REG_0,
2518 : : },
2519 : : {
2520 : : .code = (BPF_ALU | BPF_AND | BPF_K),
2521 : : .dst_reg = EBPF_REG_2,
2522 : : .imm = 0xf0,
2523 : : },
2524 : : {
2525 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
2526 : : .dst_reg = EBPF_REG_2,
2527 : : .imm = IPVERSION << 4,
2528 : : .off = 2,
2529 : : },
2530 : : /* invalid IP version, return 0 */
2531 : : {
2532 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
2533 : : .dst_reg = EBPF_REG_0,
2534 : : .src_reg = EBPF_REG_0,
2535 : : },
2536 : : {
2537 : : .code = (BPF_JMP | EBPF_EXIT),
2538 : : },
2539 : : /* load 3-rd byte of IP data */
2540 : : {
2541 : : .code = (BPF_ALU | BPF_AND | BPF_K),
2542 : : .dst_reg = EBPF_REG_0,
2543 : : .imm = RTE_IPV4_HDR_IHL_MASK,
2544 : : },
2545 : : {
2546 : : .code = (BPF_ALU | BPF_LSH | BPF_K),
2547 : : .dst_reg = EBPF_REG_0,
2548 : : .imm = 2,
2549 : : },
2550 : : {
2551 : : .code = (BPF_LD | BPF_IND | BPF_B),
2552 : : .src_reg = EBPF_REG_0,
2553 : : .imm = 3,
2554 : : },
2555 : : {
2556 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2557 : : .dst_reg = EBPF_REG_7,
2558 : : .src_reg = EBPF_REG_0,
2559 : : },
2560 : : /* load IPv4 src addr */
2561 : : {
2562 : : .code = (BPF_LD | BPF_ABS | BPF_W),
2563 : : .imm = offsetof(struct rte_ipv4_hdr, src_addr),
2564 : : },
2565 : : {
2566 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2567 : : .dst_reg = EBPF_REG_7,
2568 : : .src_reg = EBPF_REG_0,
2569 : : },
2570 : : /* load IPv4 total length */
2571 : : {
2572 : : .code = (BPF_LD | BPF_ABS | BPF_H),
2573 : : .imm = offsetof(struct rte_ipv4_hdr, total_length),
2574 : : },
2575 : : {
2576 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2577 : : .dst_reg = EBPF_REG_8,
2578 : : .src_reg = EBPF_REG_0,
2579 : : },
2580 : : /* load last 4 bytes of IP data */
2581 : : {
2582 : : .code = (BPF_LD | BPF_IND | BPF_W),
2583 : : .src_reg = EBPF_REG_8,
2584 : : .imm = -(int32_t)sizeof(uint32_t),
2585 : : },
2586 : : {
2587 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2588 : : .dst_reg = EBPF_REG_7,
2589 : : .src_reg = EBPF_REG_0,
2590 : : },
2591 : : /* load 2 bytes from the middle of IP data */
2592 : : {
2593 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2594 : : .dst_reg = EBPF_REG_8,
2595 : : .imm = 1,
2596 : : },
2597 : : {
2598 : : .code = (BPF_LD | BPF_IND | BPF_H),
2599 : : .src_reg = EBPF_REG_8,
2600 : : },
2601 : : {
2602 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2603 : : .dst_reg = EBPF_REG_0,
2604 : : .src_reg = EBPF_REG_7,
2605 : : },
2606 : : {
2607 : : .code = (BPF_JMP | EBPF_EXIT),
2608 : : },
2609 : : };
2610 : :
2611 : : static void
2612 : 13 : dummy_mbuf_prep(struct rte_mbuf *mb, uint8_t buf[], uint32_t buf_len,
2613 : : uint32_t data_len)
2614 : : {
2615 : : uint32_t i;
2616 : : uint8_t *db;
2617 : :
2618 : 13 : mb->buf_addr = buf;
2619 [ + - ]: 13 : rte_mbuf_iova_set(mb, (uintptr_t)buf);
2620 [ + - ]: 13 : mb->buf_len = buf_len;
2621 : : rte_mbuf_refcnt_set(mb, 1);
2622 : :
2623 : : /* set pool pointer to dummy value, test doesn't use it */
2624 [ + - ]: 13 : mb->pool = (void *)buf;
2625 : :
2626 : : rte_pktmbuf_reset(mb);
2627 [ + - ]: 13 : db = (uint8_t *)rte_pktmbuf_append(mb, data_len);
2628 : :
2629 [ + + ]: 2513 : for (i = 0; i != data_len; i++)
2630 : 2500 : db[i] = i;
2631 : 13 : }
2632 : :
2633 : : static void
2634 : 6 : test_ld_mbuf1_prepare(void *arg)
2635 : : {
2636 : : struct dummy_mbuf *dm;
2637 : : struct rte_ipv4_hdr *ph;
2638 : :
2639 : : const uint32_t plen = 400;
2640 : 6 : const struct rte_ipv4_hdr iph = {
2641 : : .version_ihl = RTE_IPV4_VHL_DEF,
2642 : : .total_length = rte_cpu_to_be_16(plen),
2643 : : .time_to_live = IPDEFTTL,
2644 : : .next_proto_id = IPPROTO_RAW,
2645 : : .src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK),
2646 : : .dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST),
2647 : : };
2648 : :
2649 : : dm = arg;
2650 : : memset(dm, 0, sizeof(*dm));
2651 : :
2652 : 6 : dummy_mbuf_prep(&dm->mb[0], dm->buf[0], sizeof(dm->buf[0]),
2653 : : plen / 2 + 1);
2654 : 6 : dummy_mbuf_prep(&dm->mb[1], dm->buf[1], sizeof(dm->buf[0]),
2655 : : plen / 2 - 1);
2656 : :
2657 : : rte_pktmbuf_chain(&dm->mb[0], &dm->mb[1]);
2658 : :
2659 : 6 : ph = rte_pktmbuf_mtod(dm->mb, typeof(ph));
2660 : : memcpy(ph, &iph, sizeof(iph));
2661 : 6 : }
2662 : :
2663 : : static uint64_t
2664 [ + - ]: 4 : test_ld_mbuf1(const struct rte_mbuf *pkt)
2665 : : {
2666 : : uint64_t n, v;
2667 : : const uint8_t *p8;
2668 : : const uint16_t *p16;
2669 : : const uint32_t *p32;
2670 : : struct dummy_offset dof;
2671 : :
2672 : : /* load IPv4 version and IHL */
2673 : : p8 = rte_pktmbuf_read(pkt,
2674 : : offsetof(struct rte_ipv4_hdr, version_ihl), sizeof(*p8),
2675 : : &dof);
2676 [ + - ]: 4 : if (p8 == NULL)
2677 : : return 0;
2678 : :
2679 : : /* check IP version */
2680 [ + - ]: 4 : if ((p8[0] & 0xf0) != IPVERSION << 4)
2681 : : return 0;
2682 : :
2683 : 4 : n = (p8[0] & RTE_IPV4_HDR_IHL_MASK) * RTE_IPV4_IHL_MULTIPLIER;
2684 : :
2685 : : /* load 3-rd byte of IP data */
2686 [ + - ]: 4 : p8 = rte_pktmbuf_read(pkt, n + 3, sizeof(*p8), &dof);
2687 [ + - ]: 4 : if (p8 == NULL)
2688 : : return 0;
2689 : :
2690 [ + - ]: 4 : v = p8[0];
2691 : :
2692 : : /* load IPv4 src addr */
2693 : : p32 = rte_pktmbuf_read(pkt,
2694 : : offsetof(struct rte_ipv4_hdr, src_addr), sizeof(*p32),
2695 : : &dof);
2696 [ + - ]: 4 : if (p32 == NULL)
2697 : : return 0;
2698 : :
2699 [ - + + - ]: 8 : v += rte_be_to_cpu_32(p32[0]);
2700 : :
2701 : : /* load IPv4 total length */
2702 : : p16 = rte_pktmbuf_read(pkt,
2703 : : offsetof(struct rte_ipv4_hdr, total_length), sizeof(*p16),
2704 : : &dof);
2705 [ + - ]: 4 : if (p16 == NULL)
2706 : : return 0;
2707 : :
2708 [ - + ]: 8 : n = rte_be_to_cpu_16(p16[0]);
2709 : :
2710 : : /* load last 4 bytes of IP data */
2711 [ - + ]: 4 : p32 = rte_pktmbuf_read(pkt, n - sizeof(*p32), sizeof(*p32), &dof);
2712 [ + - ]: 4 : if (p32 == NULL)
2713 : : return 0;
2714 : :
2715 [ - + ]: 4 : v += rte_be_to_cpu_32(p32[0]);
2716 : :
2717 : : /* load 2 bytes from the middle of IP data */
2718 [ - + ]: 4 : p16 = rte_pktmbuf_read(pkt, n / 2, sizeof(*p16), &dof);
2719 [ + - ]: 4 : if (p16 == NULL)
2720 : : return 0;
2721 : :
2722 [ - + ]: 4 : v += rte_be_to_cpu_16(p16[0]);
2723 : 4 : return v;
2724 : : }
2725 : :
2726 : : static int
2727 : 4 : test_ld_mbuf1_check(uint64_t rc, const void *arg)
2728 : : {
2729 : : const struct dummy_mbuf *dm;
2730 : : uint64_t v;
2731 : :
2732 : : dm = arg;
2733 : 4 : v = test_ld_mbuf1(dm->mb);
2734 : 4 : return cmp_res(__func__, v, rc, arg, arg, 0);
2735 : : }
2736 : :
2737 : : /*
2738 : : * same as ld_mbuf1, but then truncate the mbuf by 1B,
2739 : : * so load of last 4B fail.
2740 : : */
2741 : : static void
2742 : 2 : test_ld_mbuf2_prepare(void *arg)
2743 : : {
2744 : : struct dummy_mbuf *dm;
2745 : :
2746 : 2 : test_ld_mbuf1_prepare(arg);
2747 : : dm = arg;
2748 : 2 : rte_pktmbuf_trim(dm->mb, 1);
2749 : 2 : }
2750 : :
2751 : : static int
2752 : 2 : test_ld_mbuf2_check(uint64_t rc, const void *arg)
2753 : : {
2754 : 2 : return cmp_res(__func__, 0, rc, arg, arg, 0);
2755 : : }
2756 : :
2757 : : /* same as test_ld_mbuf1, but now store intermediate results on the stack */
2758 : : static const struct ebpf_insn test_ld_mbuf3_prog[] = {
2759 : :
2760 : : /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
2761 : : {
2762 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2763 : : .dst_reg = EBPF_REG_6,
2764 : : .src_reg = EBPF_REG_1,
2765 : : },
2766 : : /* load IPv4 version and IHL */
2767 : : {
2768 : : .code = (BPF_LD | BPF_ABS | BPF_B),
2769 : : .imm = offsetof(struct rte_ipv4_hdr, version_ihl),
2770 : : },
2771 : : /* check IP version */
2772 : : {
2773 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2774 : : .dst_reg = EBPF_REG_2,
2775 : : .src_reg = EBPF_REG_0,
2776 : : },
2777 : : {
2778 : : .code = (BPF_ALU | BPF_AND | BPF_K),
2779 : : .dst_reg = EBPF_REG_2,
2780 : : .imm = 0xf0,
2781 : : },
2782 : : {
2783 : : .code = (BPF_JMP | BPF_JEQ | BPF_K),
2784 : : .dst_reg = EBPF_REG_2,
2785 : : .imm = IPVERSION << 4,
2786 : : .off = 2,
2787 : : },
2788 : : /* invalid IP version, return 0 */
2789 : : {
2790 : : .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
2791 : : .dst_reg = EBPF_REG_0,
2792 : : .src_reg = EBPF_REG_0,
2793 : : },
2794 : : {
2795 : : .code = (BPF_JMP | EBPF_EXIT),
2796 : : },
2797 : : /* load 3-rd byte of IP data */
2798 : : {
2799 : : .code = (BPF_ALU | BPF_AND | BPF_K),
2800 : : .dst_reg = EBPF_REG_0,
2801 : : .imm = RTE_IPV4_HDR_IHL_MASK,
2802 : : },
2803 : : {
2804 : : .code = (BPF_ALU | BPF_LSH | BPF_K),
2805 : : .dst_reg = EBPF_REG_0,
2806 : : .imm = 2,
2807 : : },
2808 : : {
2809 : : .code = (BPF_LD | BPF_IND | BPF_B),
2810 : : .src_reg = EBPF_REG_0,
2811 : : .imm = 3,
2812 : : },
2813 : : {
2814 : : .code = (BPF_STX | BPF_MEM | BPF_B),
2815 : : .dst_reg = EBPF_REG_10,
2816 : : .src_reg = EBPF_REG_0,
2817 : : .off = (int16_t)(offsetof(struct dummy_offset, u8) -
2818 : : sizeof(struct dummy_offset)),
2819 : : },
2820 : : /* load IPv4 src addr */
2821 : : {
2822 : : .code = (BPF_LD | BPF_ABS | BPF_W),
2823 : : .imm = offsetof(struct rte_ipv4_hdr, src_addr),
2824 : : },
2825 : : {
2826 : : .code = (BPF_STX | BPF_MEM | BPF_W),
2827 : : .dst_reg = EBPF_REG_10,
2828 : : .src_reg = EBPF_REG_0,
2829 : : .off = (int16_t)(offsetof(struct dummy_offset, u32) -
2830 : : sizeof(struct dummy_offset)),
2831 : : },
2832 : : /* load IPv4 total length */
2833 : : {
2834 : : .code = (BPF_LD | BPF_ABS | BPF_H),
2835 : : .imm = offsetof(struct rte_ipv4_hdr, total_length),
2836 : : },
2837 : : {
2838 : : .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
2839 : : .dst_reg = EBPF_REG_8,
2840 : : .src_reg = EBPF_REG_0,
2841 : : },
2842 : : /* load last 4 bytes of IP data */
2843 : : {
2844 : : .code = (BPF_LD | BPF_IND | BPF_W),
2845 : : .src_reg = EBPF_REG_8,
2846 : : .imm = -(int32_t)sizeof(uint32_t),
2847 : : },
2848 : : {
2849 : : .code = (BPF_STX | BPF_MEM | EBPF_DW),
2850 : : .dst_reg = EBPF_REG_10,
2851 : : .src_reg = EBPF_REG_0,
2852 : : .off = (int16_t)(offsetof(struct dummy_offset, u64) -
2853 : : sizeof(struct dummy_offset)),
2854 : : },
2855 : : /* load 2 bytes from the middle of IP data */
2856 : : {
2857 : : .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
2858 : : .dst_reg = EBPF_REG_8,
2859 : : .imm = 1,
2860 : : },
2861 : : {
2862 : : .code = (BPF_LD | BPF_IND | BPF_H),
2863 : : .src_reg = EBPF_REG_8,
2864 : : },
2865 : : {
2866 : : .code = (BPF_LDX | BPF_MEM | EBPF_DW),
2867 : : .dst_reg = EBPF_REG_1,
2868 : : .src_reg = EBPF_REG_10,
2869 : : .off = (int16_t)(offsetof(struct dummy_offset, u64) -
2870 : : sizeof(struct dummy_offset)),
2871 : : },
2872 : : {
2873 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2874 : : .dst_reg = EBPF_REG_0,
2875 : : .src_reg = EBPF_REG_1,
2876 : : },
2877 : : {
2878 : : .code = (BPF_LDX | BPF_MEM | BPF_W),
2879 : : .dst_reg = EBPF_REG_1,
2880 : : .src_reg = EBPF_REG_10,
2881 : : .off = (int16_t)(offsetof(struct dummy_offset, u32) -
2882 : : sizeof(struct dummy_offset)),
2883 : : },
2884 : : {
2885 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2886 : : .dst_reg = EBPF_REG_0,
2887 : : .src_reg = EBPF_REG_1,
2888 : : },
2889 : : {
2890 : : .code = (BPF_LDX | BPF_MEM | BPF_B),
2891 : : .dst_reg = EBPF_REG_1,
2892 : : .src_reg = EBPF_REG_10,
2893 : : .off = (int16_t)(offsetof(struct dummy_offset, u8) -
2894 : : sizeof(struct dummy_offset)),
2895 : : },
2896 : : {
2897 : : .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
2898 : : .dst_reg = EBPF_REG_0,
2899 : : .src_reg = EBPF_REG_1,
2900 : : },
2901 : : {
2902 : : .code = (BPF_JMP | EBPF_EXIT),
2903 : : },
2904 : : };
2905 : :
2906 : : /* all bpf test cases */
2907 : : static const struct bpf_test tests[] = {
2908 : : {
2909 : : .name = "test_store1",
2910 : : .arg_sz = sizeof(struct dummy_offset),
2911 : : .prm = {
2912 : : .ins = test_store1_prog,
2913 : : .nb_ins = RTE_DIM(test_store1_prog),
2914 : : .prog_arg = {
2915 : : .type = RTE_BPF_ARG_PTR,
2916 : : .size = sizeof(struct dummy_offset),
2917 : : },
2918 : : },
2919 : : .prepare = test_store1_prepare,
2920 : : .check_result = test_store1_check,
2921 : : },
2922 : : {
2923 : : .name = "test_store2",
2924 : : .arg_sz = sizeof(struct dummy_offset),
2925 : : .prm = {
2926 : : .ins = test_store2_prog,
2927 : : .nb_ins = RTE_DIM(test_store2_prog),
2928 : : .prog_arg = {
2929 : : .type = RTE_BPF_ARG_PTR,
2930 : : .size = sizeof(struct dummy_offset),
2931 : : },
2932 : : },
2933 : : .prepare = test_store1_prepare,
2934 : : .check_result = test_store1_check,
2935 : : },
2936 : : {
2937 : : .name = "test_load1",
2938 : : .arg_sz = sizeof(struct dummy_offset),
2939 : : .prm = {
2940 : : .ins = test_load1_prog,
2941 : : .nb_ins = RTE_DIM(test_load1_prog),
2942 : : .prog_arg = {
2943 : : .type = RTE_BPF_ARG_PTR,
2944 : : .size = sizeof(struct dummy_offset),
2945 : : },
2946 : : },
2947 : : .prepare = test_load1_prepare,
2948 : : .check_result = test_load1_check,
2949 : : },
2950 : : {
2951 : : .name = "test_ldimm1",
2952 : : .arg_sz = sizeof(struct dummy_offset),
2953 : : .prm = {
2954 : : .ins = test_ldimm1_prog,
2955 : : .nb_ins = RTE_DIM(test_ldimm1_prog),
2956 : : .prog_arg = {
2957 : : .type = RTE_BPF_ARG_PTR,
2958 : : .size = sizeof(struct dummy_offset),
2959 : : },
2960 : : },
2961 : : .prepare = test_store1_prepare,
2962 : : .check_result = test_ldimm1_check,
2963 : : },
2964 : : {
2965 : : .name = "test_mul1",
2966 : : .arg_sz = sizeof(struct dummy_vect8),
2967 : : .prm = {
2968 : : .ins = test_mul1_prog,
2969 : : .nb_ins = RTE_DIM(test_mul1_prog),
2970 : : .prog_arg = {
2971 : : .type = RTE_BPF_ARG_PTR,
2972 : : .size = sizeof(struct dummy_vect8),
2973 : : },
2974 : : },
2975 : : .prepare = test_mul1_prepare,
2976 : : .check_result = test_mul1_check,
2977 : : },
2978 : : {
2979 : : .name = "test_shift1",
2980 : : .arg_sz = sizeof(struct dummy_vect8),
2981 : : .prm = {
2982 : : .ins = test_shift1_prog,
2983 : : .nb_ins = RTE_DIM(test_shift1_prog),
2984 : : .prog_arg = {
2985 : : .type = RTE_BPF_ARG_PTR,
2986 : : .size = sizeof(struct dummy_vect8),
2987 : : },
2988 : : },
2989 : : .prepare = test_shift1_prepare,
2990 : : .check_result = test_shift1_check,
2991 : : },
2992 : : {
2993 : : .name = "test_jump1",
2994 : : .arg_sz = sizeof(struct dummy_vect8),
2995 : : .prm = {
2996 : : .ins = test_jump1_prog,
2997 : : .nb_ins = RTE_DIM(test_jump1_prog),
2998 : : .prog_arg = {
2999 : : .type = RTE_BPF_ARG_PTR,
3000 : : .size = sizeof(struct dummy_vect8),
3001 : : },
3002 : : },
3003 : : .prepare = test_jump1_prepare,
3004 : : .check_result = test_jump1_check,
3005 : : },
3006 : : {
3007 : : .name = "test_jump2",
3008 : : .arg_sz = sizeof(struct dummy_net),
3009 : : .prm = {
3010 : : .ins = test_jump2_prog,
3011 : : .nb_ins = RTE_DIM(test_jump2_prog),
3012 : : .prog_arg = {
3013 : : .type = RTE_BPF_ARG_PTR,
3014 : : .size = sizeof(struct dummy_net),
3015 : : },
3016 : : },
3017 : : .prepare = test_jump2_prepare,
3018 : : .check_result = test_jump2_check,
3019 : : },
3020 : : {
3021 : : .name = "test_alu1",
3022 : : .arg_sz = sizeof(struct dummy_vect8),
3023 : : .prm = {
3024 : : .ins = test_alu1_prog,
3025 : : .nb_ins = RTE_DIM(test_alu1_prog),
3026 : : .prog_arg = {
3027 : : .type = RTE_BPF_ARG_PTR,
3028 : : .size = sizeof(struct dummy_vect8),
3029 : : },
3030 : : },
3031 : : .prepare = test_jump1_prepare,
3032 : : .check_result = test_alu1_check,
3033 : : },
3034 : : {
3035 : : .name = "test_bele1",
3036 : : .arg_sz = sizeof(struct dummy_vect8),
3037 : : .prm = {
3038 : : .ins = test_bele1_prog,
3039 : : .nb_ins = RTE_DIM(test_bele1_prog),
3040 : : .prog_arg = {
3041 : : .type = RTE_BPF_ARG_PTR,
3042 : : .size = sizeof(struct dummy_vect8),
3043 : : },
3044 : : },
3045 : : .prepare = test_bele1_prepare,
3046 : : .check_result = test_bele1_check,
3047 : : },
3048 : : {
3049 : : .name = "test_xadd1",
3050 : : .arg_sz = sizeof(struct dummy_offset),
3051 : : .prm = {
3052 : : .ins = test_xadd1_prog,
3053 : : .nb_ins = RTE_DIM(test_xadd1_prog),
3054 : : .prog_arg = {
3055 : : .type = RTE_BPF_ARG_PTR,
3056 : : .size = sizeof(struct dummy_offset),
3057 : : },
3058 : : },
3059 : : .prepare = test_store1_prepare,
3060 : : .check_result = test_xadd1_check,
3061 : : },
3062 : : {
3063 : : .name = "test_div1",
3064 : : .arg_sz = sizeof(struct dummy_vect8),
3065 : : .prm = {
3066 : : .ins = test_div1_prog,
3067 : : .nb_ins = RTE_DIM(test_div1_prog),
3068 : : .prog_arg = {
3069 : : .type = RTE_BPF_ARG_PTR,
3070 : : .size = sizeof(struct dummy_vect8),
3071 : : },
3072 : : },
3073 : : .prepare = test_mul1_prepare,
3074 : : .check_result = test_div1_check,
3075 : : },
3076 : : {
3077 : : .name = "test_call1",
3078 : : .arg_sz = sizeof(struct dummy_offset),
3079 : : .prm = {
3080 : : .ins = test_call1_prog,
3081 : : .nb_ins = RTE_DIM(test_call1_prog),
3082 : : .prog_arg = {
3083 : : .type = RTE_BPF_ARG_PTR,
3084 : : .size = sizeof(struct dummy_offset),
3085 : : },
3086 : : .xsym = test_call1_xsym,
3087 : : .nb_xsym = RTE_DIM(test_call1_xsym),
3088 : : },
3089 : : .prepare = test_load1_prepare,
3090 : : .check_result = test_call1_check,
3091 : : /* for now don't support function calls on 32 bit platform */
3092 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3093 : : },
3094 : : {
3095 : : .name = "test_call2",
3096 : : .arg_sz = sizeof(struct dummy_offset),
3097 : : .prm = {
3098 : : .ins = test_call2_prog,
3099 : : .nb_ins = RTE_DIM(test_call2_prog),
3100 : : .prog_arg = {
3101 : : .type = RTE_BPF_ARG_PTR,
3102 : : .size = sizeof(struct dummy_offset),
3103 : : },
3104 : : .xsym = test_call2_xsym,
3105 : : .nb_xsym = RTE_DIM(test_call2_xsym),
3106 : : },
3107 : : .prepare = test_store1_prepare,
3108 : : .check_result = test_call2_check,
3109 : : /* for now don't support function calls on 32 bit platform */
3110 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3111 : : },
3112 : : {
3113 : : .name = "test_call3",
3114 : : .arg_sz = sizeof(struct dummy_vect8),
3115 : : .prm = {
3116 : : .ins = test_call3_prog,
3117 : : .nb_ins = RTE_DIM(test_call3_prog),
3118 : : .prog_arg = {
3119 : : .type = RTE_BPF_ARG_PTR,
3120 : : .size = sizeof(struct dummy_vect8),
3121 : : },
3122 : : .xsym = test_call3_xsym,
3123 : : .nb_xsym = RTE_DIM(test_call3_xsym),
3124 : : },
3125 : : .prepare = test_call3_prepare,
3126 : : .check_result = test_call3_check,
3127 : : /* for now don't support function calls on 32 bit platform */
3128 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3129 : : },
3130 : : {
3131 : : .name = "test_call4",
3132 : : .arg_sz = sizeof(struct dummy_offset),
3133 : : .prm = {
3134 : : .ins = test_call4_prog,
3135 : : .nb_ins = RTE_DIM(test_call4_prog),
3136 : : .prog_arg = {
3137 : : .type = RTE_BPF_ARG_PTR,
3138 : : .size = 2 * sizeof(struct dummy_offset),
3139 : : },
3140 : : .xsym = test_call4_xsym,
3141 : : .nb_xsym = RTE_DIM(test_call4_xsym),
3142 : : },
3143 : : .prepare = test_store1_prepare,
3144 : : .check_result = test_call4_check,
3145 : : /* for now don't support function calls on 32 bit platform */
3146 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3147 : : },
3148 : : {
3149 : : .name = "test_call5",
3150 : : .arg_sz = sizeof(struct dummy_offset),
3151 : : .prm = {
3152 : : .ins = test_call5_prog,
3153 : : .nb_ins = RTE_DIM(test_call5_prog),
3154 : : .prog_arg = {
3155 : : .type = RTE_BPF_ARG_PTR,
3156 : : .size = sizeof(struct dummy_offset),
3157 : : },
3158 : : .xsym = test_call5_xsym,
3159 : : .nb_xsym = RTE_DIM(test_call5_xsym),
3160 : : },
3161 : : .prepare = test_store1_prepare,
3162 : : .check_result = test_call5_check,
3163 : : /* for now don't support function calls on 32 bit platform */
3164 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3165 : : },
3166 : : {
3167 : : .name = "test_ld_mbuf1",
3168 : : .arg_sz = sizeof(struct dummy_mbuf),
3169 : : .prm = {
3170 : : .ins = test_ld_mbuf1_prog,
3171 : : .nb_ins = RTE_DIM(test_ld_mbuf1_prog),
3172 : : .prog_arg = {
3173 : : .type = RTE_BPF_ARG_PTR_MBUF,
3174 : : .buf_size = sizeof(struct dummy_mbuf),
3175 : : },
3176 : : },
3177 : : .prepare = test_ld_mbuf1_prepare,
3178 : : .check_result = test_ld_mbuf1_check,
3179 : : /* mbuf as input argument is not supported on 32 bit platform */
3180 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3181 : : },
3182 : : {
3183 : : .name = "test_ld_mbuf2",
3184 : : .arg_sz = sizeof(struct dummy_mbuf),
3185 : : .prm = {
3186 : : .ins = test_ld_mbuf1_prog,
3187 : : .nb_ins = RTE_DIM(test_ld_mbuf1_prog),
3188 : : .prog_arg = {
3189 : : .type = RTE_BPF_ARG_PTR_MBUF,
3190 : : .buf_size = sizeof(struct dummy_mbuf),
3191 : : },
3192 : : },
3193 : : .prepare = test_ld_mbuf2_prepare,
3194 : : .check_result = test_ld_mbuf2_check,
3195 : : /* mbuf as input argument is not supported on 32 bit platform */
3196 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3197 : : },
3198 : : {
3199 : : .name = "test_ld_mbuf3",
3200 : : .arg_sz = sizeof(struct dummy_mbuf),
3201 : : .prm = {
3202 : : .ins = test_ld_mbuf3_prog,
3203 : : .nb_ins = RTE_DIM(test_ld_mbuf3_prog),
3204 : : .prog_arg = {
3205 : : .type = RTE_BPF_ARG_PTR_MBUF,
3206 : : .buf_size = sizeof(struct dummy_mbuf),
3207 : : },
3208 : : },
3209 : : .prepare = test_ld_mbuf1_prepare,
3210 : : .check_result = test_ld_mbuf1_check,
3211 : : /* mbuf as input argument is not supported on 32 bit platform */
3212 : : .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
3213 : : },
3214 : : };
3215 : :
3216 : : static int
3217 : 20 : run_test(const struct bpf_test *tst)
3218 : 20 : {
3219 : : int32_t ret, rv;
3220 : : int64_t rc;
3221 : : struct rte_bpf *bpf;
3222 : : struct rte_bpf_jit jit;
3223 : 20 : uint8_t tbuf[tst->arg_sz];
3224 : :
3225 : 20 : printf("%s(%s) start\n", __func__, tst->name);
3226 : :
3227 : 20 : bpf = rte_bpf_load(&tst->prm);
3228 [ - + ]: 20 : if (bpf == NULL) {
3229 : 0 : printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
3230 : : __func__, __LINE__, rte_errno, strerror(rte_errno));
3231 : 0 : return -1;
3232 : : }
3233 : :
3234 : 20 : tst->prepare(tbuf);
3235 : 20 : rc = rte_bpf_exec(bpf, tbuf);
3236 : 20 : ret = tst->check_result(rc, tbuf);
3237 [ - + ]: 20 : if (ret != 0) {
3238 : 0 : printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
3239 : 0 : __func__, __LINE__, tst->name, ret, strerror(ret));
3240 : : }
3241 : :
3242 : : /* repeat the same test with jit, when possible */
3243 : 20 : rte_bpf_get_jit(bpf, &jit);
3244 [ + - ]: 20 : if (jit.func != NULL) {
3245 : :
3246 : 20 : tst->prepare(tbuf);
3247 : 20 : rc = jit.func(tbuf);
3248 : 20 : rv = tst->check_result(rc, tbuf);
3249 : 20 : ret |= rv;
3250 [ - + ]: 20 : if (rv != 0) {
3251 : 0 : printf("%s@%d: check_result(%s) failed, "
3252 : : "error: %d(%s);\n",
3253 : 0 : __func__, __LINE__, tst->name,
3254 : : rv, strerror(rv));
3255 : : }
3256 : : }
3257 : :
3258 : 20 : rte_bpf_destroy(bpf);
3259 : 20 : return ret;
3260 : :
3261 : : }
3262 : :
3263 : : static int
3264 : 1 : test_bpf(void)
3265 : : {
3266 : : int32_t rc, rv;
3267 : : uint32_t i;
3268 : :
3269 : : rc = 0;
3270 [ + + ]: 21 : for (i = 0; i != RTE_DIM(tests); i++) {
3271 : 20 : rv = run_test(tests + i);
3272 [ + - ]: 20 : if (tests[i].allow_fail == 0)
3273 : 20 : rc |= rv;
3274 : : }
3275 : :
3276 : 1 : return rc;
3277 : : }
3278 : :
3279 : : #endif /* !RTE_LIB_BPF */
3280 : :
3281 : 254 : REGISTER_FAST_TEST(bpf_autotest, true, true, test_bpf);
3282 : :
3283 : : #ifdef TEST_BPF_ELF_LOAD
3284 : :
3285 : : /*
3286 : : * Helper function to write BPF object data to temporary file.
3287 : : * Returns temp file path on success, NULL on failure.
3288 : : * Caller must free the returned path and unlink the file.
3289 : : */
3290 : : static char *
3291 : : create_temp_bpf_file(const uint8_t *data, size_t size, const char *name)
3292 : : {
3293 : : char *tmpfile = NULL;
3294 : : int fd;
3295 : : ssize_t written;
3296 : :
3297 : : if (asprintf(&tmpfile, "/tmp/dpdk_bpf_%s_XXXXXX.o", name) < 0) {
3298 : : printf("%s@%d: asprintf failed: %s\n",
3299 : : __func__, __LINE__, strerror(errno));
3300 : : return NULL;
3301 : : }
3302 : :
3303 : : /* Create and open temp file */
3304 : : fd = mkstemps(tmpfile, strlen(".o"));
3305 : : if (fd < 0) {
3306 : : printf("%s@%d: mkstemps(%s) failed: %s\n",
3307 : : __func__, __LINE__, tmpfile, strerror(errno));
3308 : : free(tmpfile);
3309 : : return NULL;
3310 : : }
3311 : :
3312 : : /* Write BPF object data */
3313 : : written = write(fd, data, size);
3314 : : close(fd);
3315 : :
3316 : : if (written != (ssize_t)size) {
3317 : : printf("%s@%d: write failed: %s\n",
3318 : : __func__, __LINE__, strerror(errno));
3319 : : unlink(tmpfile);
3320 : : free(tmpfile);
3321 : : return NULL;
3322 : : }
3323 : :
3324 : : return tmpfile;
3325 : : }
3326 : :
3327 : : #include "test_bpf_load.h"
3328 : :
3329 : : /*
3330 : : * Test loading BPF program from an object file.
3331 : : * This test uses same arguments as previous test_call1 example.
3332 : : */
3333 : : static int
3334 : : test_bpf_elf_load(void)
3335 : : {
3336 : : static const char test_section[] = "call1";
3337 : : uint8_t tbuf[sizeof(struct dummy_vect8)];
3338 : : const struct rte_bpf_xsym xsym[] = {
3339 : : {
3340 : : .name = RTE_STR(dummy_func1),
3341 : : .type = RTE_BPF_XTYPE_FUNC,
3342 : : .func = {
3343 : : .val = (void *)dummy_func1,
3344 : : .nb_args = 3,
3345 : : .args = {
3346 : : [0] = {
3347 : : .type = RTE_BPF_ARG_PTR,
3348 : : .size = sizeof(struct dummy_offset),
3349 : : },
3350 : : [1] = {
3351 : : .type = RTE_BPF_ARG_PTR,
3352 : : .size = sizeof(uint32_t),
3353 : : },
3354 : : [2] = {
3355 : : .type = RTE_BPF_ARG_PTR,
3356 : : .size = sizeof(uint64_t),
3357 : : },
3358 : : },
3359 : : },
3360 : : },
3361 : : };
3362 : : int ret;
3363 : :
3364 : : /* Create temp file from embedded BPF object */
3365 : : char *tmpfile = create_temp_bpf_file(app_test_bpf_load_o,
3366 : : app_test_bpf_load_o_len,
3367 : : "load");
3368 : : if (tmpfile == NULL)
3369 : : return -1;
3370 : :
3371 : : /* Try to load BPF program from temp file */
3372 : : const struct rte_bpf_prm prm = {
3373 : : .xsym = xsym,
3374 : : .nb_xsym = RTE_DIM(xsym),
3375 : : .prog_arg = {
3376 : : .type = RTE_BPF_ARG_PTR,
3377 : : .size = sizeof(tbuf),
3378 : : },
3379 : : };
3380 : :
3381 : : struct rte_bpf *bpf = rte_bpf_elf_load(&prm, tmpfile, test_section);
3382 : : unlink(tmpfile);
3383 : : free(tmpfile);
3384 : :
3385 : : /* If libelf support is not available */
3386 : : if (bpf == NULL && rte_errno == ENOTSUP)
3387 : : return TEST_SKIPPED;
3388 : :
3389 : : TEST_ASSERT(bpf != NULL, "failed to load BPF %d:%s", rte_errno, strerror(rte_errno));
3390 : :
3391 : : /* Prepare test data */
3392 : : struct dummy_vect8 *dv = (struct dummy_vect8 *)tbuf;
3393 : :
3394 : : memset(dv, 0, sizeof(*dv));
3395 : : dv->in[0].u64 = (int32_t)TEST_FILL_1;
3396 : : dv->in[0].u32 = dv->in[0].u64;
3397 : : dv->in[0].u16 = dv->in[0].u64;
3398 : : dv->in[0].u8 = dv->in[0].u64;
3399 : :
3400 : : /* Execute loaded BPF program */
3401 : : uint64_t rc = rte_bpf_exec(bpf, tbuf);
3402 : : ret = test_call1_check(rc, tbuf);
3403 : : TEST_ASSERT(ret == 0, "test_call1_check failed: %d", ret);
3404 : :
3405 : : /* Test JIT if available */
3406 : : struct rte_bpf_jit jit;
3407 : : ret = rte_bpf_get_jit(bpf, &jit);
3408 : : TEST_ASSERT(ret == 0, "rte_bpf_get_jit failed: %d", ret);
3409 : :
3410 : : if (jit.func != NULL) {
3411 : : memset(dv, 0, sizeof(*dv));
3412 : : dv->in[0].u64 = (int32_t)TEST_FILL_1;
3413 : : dv->in[0].u32 = dv->in[0].u64;
3414 : : dv->in[0].u16 = dv->in[0].u64;
3415 : : dv->in[0].u8 = dv->in[0].u64;
3416 : :
3417 : : rc = jit.func(tbuf);
3418 : : ret = test_call1_check(rc, tbuf);
3419 : : TEST_ASSERT(ret == 0, "jit test_call1_check failed: %d", ret);
3420 : : }
3421 : :
3422 : : rte_bpf_destroy(bpf);
3423 : :
3424 : : printf("%s: ELF load test passed\n", __func__);
3425 : : return TEST_SUCCESS;
3426 : : }
3427 : :
3428 : : #include <rte_ethdev.h>
3429 : : #include <rte_bpf_ethdev.h>
3430 : : #include <rte_bus_vdev.h>
3431 : :
3432 : : #include "test_bpf_filter.h"
3433 : :
3434 : : #define BPF_TEST_BURST 128
3435 : : #define BPF_TEST_POOLSIZE 256 /* at least 2x burst */
3436 : : #define BPF_TEST_PKT_LEN 64 /* Ether + IP + TCP */
3437 : :
3438 : : static int null_vdev_setup(const char *name, uint16_t *port, struct rte_mempool *pool)
3439 : : {
3440 : : int ret;
3441 : :
3442 : : /* Make a null device */
3443 : : ret = rte_vdev_init(name, NULL);
3444 : : TEST_ASSERT(ret == 0, "rte_vdev_init(%s) failed: %d", name, ret);
3445 : :
3446 : : ret = rte_eth_dev_get_port_by_name(name, port);
3447 : : TEST_ASSERT(ret == 0, "failed to get port id for %s: %d", name, ret);
3448 : :
3449 : : struct rte_eth_conf conf = { };
3450 : : ret = rte_eth_dev_configure(*port, 1, 1, &conf);
3451 : : TEST_ASSERT(ret == 0, "failed to configure port %u: %d", *port, ret);
3452 : :
3453 : : struct rte_eth_txconf txconf = { };
3454 : : ret = rte_eth_tx_queue_setup(*port, 0, BPF_TEST_BURST, SOCKET_ID_ANY, &txconf);
3455 : : TEST_ASSERT(ret == 0, "failed to setup tx queue port %u: %d", *port, ret);
3456 : :
3457 : : struct rte_eth_rxconf rxconf = { };
3458 : : ret = rte_eth_rx_queue_setup(*port, 0, BPF_TEST_BURST, SOCKET_ID_ANY,
3459 : : &rxconf, pool);
3460 : : TEST_ASSERT(ret == 0, "failed to setup rx queue port %u: %d", *port, ret);
3461 : :
3462 : : ret = rte_eth_dev_start(*port);
3463 : : TEST_ASSERT(ret == 0, "failed to start port %u: %d", *port, ret);
3464 : :
3465 : : return 0;
3466 : : }
3467 : :
3468 : : static unsigned int
3469 : : setup_mbufs(struct rte_mbuf *burst[], unsigned int n)
3470 : : {
3471 : : struct rte_ether_hdr eh = {
3472 : : .ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4),
3473 : : };
3474 : : const struct rte_ipv4_hdr iph = {
3475 : : .version_ihl = RTE_IPV4_VHL_DEF,
3476 : : .total_length = rte_cpu_to_be_16(BPF_TEST_PKT_LEN - sizeof(eh)),
3477 : : .time_to_live = IPDEFTTL,
3478 : : .src_addr = rte_cpu_to_be_32(ip_src_addr),
3479 : : .dst_addr = rte_cpu_to_be_32(ip_dst_addr),
3480 : : };
3481 : : unsigned int tcp_count = 0;
3482 : :
3483 : : rte_eth_random_addr(eh.dst_addr.addr_bytes);
3484 : :
3485 : : for (unsigned int i = 0; i < n; i++) {
3486 : : struct rte_mbuf *mb = burst[i];
3487 : :
3488 : : /* Setup Ethernet header */
3489 : : *rte_pktmbuf_mtod(mb, struct rte_ether_hdr *) = eh;
3490 : :
3491 : : /* Setup IP header */
3492 : : struct rte_ipv4_hdr *ip
3493 : : = rte_pktmbuf_mtod_offset(mb, struct rte_ipv4_hdr *, sizeof(eh));
3494 : : *ip = iph;
3495 : :
3496 : : if (rte_rand() & 1) {
3497 : : struct rte_udp_hdr *udp
3498 : : = rte_pktmbuf_mtod_offset(mb, struct rte_udp_hdr *,
3499 : : sizeof(eh) + sizeof(iph));
3500 : :
3501 : : ip->next_proto_id = IPPROTO_UDP;
3502 : : *udp = (struct rte_udp_hdr) {
3503 : : .src_port = rte_cpu_to_be_16(9), /* discard */
3504 : : .dst_port = rte_cpu_to_be_16(9), /* discard */
3505 : : .dgram_len = BPF_TEST_PKT_LEN - sizeof(eh) - sizeof(iph),
3506 : : };
3507 : :
3508 : : } else {
3509 : : struct rte_tcp_hdr *tcp
3510 : : = rte_pktmbuf_mtod_offset(mb, struct rte_tcp_hdr *,
3511 : : sizeof(eh) + sizeof(iph));
3512 : :
3513 : : ip->next_proto_id = IPPROTO_TCP;
3514 : : *tcp = (struct rte_tcp_hdr) {
3515 : : .src_port = rte_cpu_to_be_16(9), /* discard */
3516 : : .dst_port = rte_cpu_to_be_16(9), /* discard */
3517 : : .tcp_flags = RTE_TCP_RST_FLAG,
3518 : : };
3519 : : ++tcp_count;
3520 : : }
3521 : : }
3522 : :
3523 : : return tcp_count;
3524 : : }
3525 : :
3526 : : static int bpf_tx_test(uint16_t port, const char *tmpfile, struct rte_mempool *pool,
3527 : : const char *section, uint32_t flags)
3528 : : {
3529 : : const struct rte_bpf_prm prm = {
3530 : : .prog_arg = {
3531 : : .type = RTE_BPF_ARG_PTR,
3532 : : .size = sizeof(struct rte_mbuf),
3533 : : },
3534 : : };
3535 : : int ret;
3536 : :
3537 : : /* Try to load BPF TX program from temp file */
3538 : : ret = rte_bpf_eth_tx_elf_load(port, 0, &prm, tmpfile, section, flags);
3539 : : if (ret != 0) {
3540 : : printf("%s@%d: failed to load BPF filter from file=%s error=%d:(%s)\n",
3541 : : __func__, __LINE__, tmpfile, rte_errno, rte_strerror(rte_errno));
3542 : : return ret;
3543 : : }
3544 : :
3545 : : struct rte_mbuf *pkts[BPF_TEST_BURST] = { };
3546 : : ret = rte_pktmbuf_alloc_bulk(pool, pkts, BPF_TEST_BURST);
3547 : : TEST_ASSERT(ret == 0, "failed to allocate mbufs");
3548 : :
3549 : : uint16_t expect = setup_mbufs(pkts, BPF_TEST_BURST);
3550 : :
3551 : : uint16_t sent = rte_eth_tx_burst(port, 0, pkts, BPF_TEST_BURST);
3552 : : TEST_ASSERT_EQUAL(sent, expect, "rte_eth_tx_burst returned: %u expected %u",
3553 : : sent, expect);
3554 : :
3555 : : /* The unsent packets should be dropped */
3556 : : rte_pktmbuf_free_bulk(pkts + sent, BPF_TEST_BURST - sent);
3557 : :
3558 : : /* Pool should have same number of packets avail */
3559 : : unsigned int avail = rte_mempool_avail_count(pool);
3560 : : TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE,
3561 : : "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE);
3562 : :
3563 : : rte_bpf_eth_tx_unload(port, 0);
3564 : : return TEST_SUCCESS;
3565 : : }
3566 : :
3567 : : /* Test loading a transmit filter which only allows IPv4 packets */
3568 : : static int
3569 : : test_bpf_elf_tx_load(void)
3570 : : {
3571 : : static const char null_dev[] = "net_null_bpf0";
3572 : : char *tmpfile = NULL;
3573 : : struct rte_mempool *mb_pool = NULL;
3574 : : uint16_t port = UINT16_MAX;
3575 : : int ret;
3576 : :
3577 : : printf("%s start\n", __func__);
3578 : :
3579 : : /* Make a pool for packets */
3580 : : mb_pool = rte_pktmbuf_pool_create("bpf_tx_test_pool", BPF_TEST_POOLSIZE,
3581 : : 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
3582 : : SOCKET_ID_ANY);
3583 : :
3584 : : ret = null_vdev_setup(null_dev, &port, mb_pool);
3585 : : if (ret != 0)
3586 : : goto fail;
3587 : :
3588 : : /* Create temp file from embedded BPF object */
3589 : : tmpfile = create_temp_bpf_file(app_test_bpf_filter_o, app_test_bpf_filter_o_len, "tx");
3590 : : if (tmpfile == NULL)
3591 : : goto fail;
3592 : :
3593 : : /* Do test with VM */
3594 : : ret = bpf_tx_test(port, tmpfile, mb_pool, "filter", 0);
3595 : : if (ret != 0)
3596 : : goto fail;
3597 : :
3598 : : /* Repeat with JIT */
3599 : : ret = bpf_tx_test(port, tmpfile, mb_pool, "filter", RTE_BPF_ETH_F_JIT);
3600 : : if (ret == 0)
3601 : : printf("%s: TX ELF load test passed\n", __func__);
3602 : :
3603 : : fail:
3604 : : if (tmpfile) {
3605 : : unlink(tmpfile);
3606 : : free(tmpfile);
3607 : : }
3608 : :
3609 : : if (port != UINT16_MAX)
3610 : : rte_vdev_uninit(null_dev);
3611 : :
3612 : : rte_mempool_free(mb_pool);
3613 : :
3614 : : if (ret == 0)
3615 : : return TEST_SUCCESS;
3616 : : else if (ret == -ENOTSUP)
3617 : : return TEST_SKIPPED;
3618 : : else
3619 : : return TEST_FAILED;
3620 : : }
3621 : :
3622 : : /* Test loading a receive filter */
3623 : : static int bpf_rx_test(uint16_t port, const char *tmpfile, struct rte_mempool *pool,
3624 : : const char *section, uint32_t flags, uint16_t expected)
3625 : : {
3626 : : struct rte_mbuf *pkts[BPF_TEST_BURST];
3627 : : const struct rte_bpf_prm prm = {
3628 : : .prog_arg = {
3629 : : .type = RTE_BPF_ARG_PTR,
3630 : : .size = sizeof(struct rte_mbuf),
3631 : : },
3632 : : };
3633 : : int ret;
3634 : :
3635 : : /* Load BPF program to drop all packets */
3636 : : ret = rte_bpf_eth_rx_elf_load(port, 0, &prm, tmpfile, section, flags);
3637 : : if (ret != 0) {
3638 : : printf("%s@%d: failed to load BPF filter from file=%s error=%d:(%s)\n",
3639 : : __func__, __LINE__, tmpfile, rte_errno, rte_strerror(rte_errno));
3640 : : return ret;
3641 : : }
3642 : :
3643 : : uint16_t rcvd = rte_eth_rx_burst(port, 0, pkts, BPF_TEST_BURST);
3644 : : TEST_ASSERT_EQUAL(rcvd, expected,
3645 : : "rte_eth_rx_burst returned: %u expect: %u", rcvd, expected);
3646 : :
3647 : : /* Drop the received packets */
3648 : : rte_pktmbuf_free_bulk(pkts, rcvd);
3649 : :
3650 : : rte_bpf_eth_rx_unload(port, 0);
3651 : :
3652 : : /* Pool should now be full */
3653 : : unsigned int avail = rte_mempool_avail_count(pool);
3654 : : TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE,
3655 : : "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE);
3656 : :
3657 : : return TEST_SUCCESS;
3658 : : }
3659 : :
3660 : : /* Test loading a receive filters, first with drop all and then with allow all packets */
3661 : : static int
3662 : : test_bpf_elf_rx_load(void)
3663 : : {
3664 : : static const char null_dev[] = "net_null_bpf0";
3665 : : struct rte_mempool *pool = NULL;
3666 : : char *tmpfile = NULL;
3667 : : uint16_t port;
3668 : : int ret;
3669 : :
3670 : : printf("%s start\n", __func__);
3671 : :
3672 : : /* Make a pool for packets */
3673 : : pool = rte_pktmbuf_pool_create("bpf_rx_test_pool", 2 * BPF_TEST_BURST,
3674 : : 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
3675 : : SOCKET_ID_ANY);
3676 : : TEST_ASSERT(pool != NULL, "failed to create mempool");
3677 : :
3678 : : ret = null_vdev_setup(null_dev, &port, pool);
3679 : : if (ret != 0)
3680 : : goto fail;
3681 : :
3682 : : /* Create temp file from embedded BPF object */
3683 : : tmpfile = create_temp_bpf_file(app_test_bpf_filter_o, app_test_bpf_filter_o_len, "rx");
3684 : : if (tmpfile == NULL)
3685 : : goto fail;
3686 : :
3687 : : /* Do test with VM */
3688 : : ret = bpf_rx_test(port, tmpfile, pool, "drop", 0, 0);
3689 : : if (ret != 0)
3690 : : goto fail;
3691 : :
3692 : : /* Repeat with JIT */
3693 : : ret = bpf_rx_test(port, tmpfile, pool, "drop", RTE_BPF_ETH_F_JIT, 0);
3694 : : if (ret != 0)
3695 : : goto fail;
3696 : :
3697 : : /* Repeat with allow all */
3698 : : ret = bpf_rx_test(port, tmpfile, pool, "allow", 0, BPF_TEST_BURST);
3699 : : if (ret != 0)
3700 : : goto fail;
3701 : :
3702 : : /* Repeat with JIT */
3703 : : ret = bpf_rx_test(port, tmpfile, pool, "allow", RTE_BPF_ETH_F_JIT, BPF_TEST_BURST);
3704 : : if (ret != 0)
3705 : : goto fail;
3706 : :
3707 : : printf("%s: RX ELF load test passed\n", __func__);
3708 : :
3709 : : /* The filter should free the mbufs */
3710 : : unsigned int avail = rte_mempool_avail_count(pool);
3711 : : TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE,
3712 : : "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE);
3713 : :
3714 : : fail:
3715 : : if (tmpfile) {
3716 : : unlink(tmpfile);
3717 : : free(tmpfile);
3718 : : }
3719 : :
3720 : : if (port != UINT16_MAX)
3721 : : rte_vdev_uninit(null_dev);
3722 : :
3723 : : rte_mempool_free(pool);
3724 : :
3725 : : return ret == 0 ? TEST_SUCCESS : TEST_FAILED;
3726 : : }
3727 : :
3728 : :
3729 : : static int
3730 : : test_bpf_elf(void)
3731 : : {
3732 : : int ret;
3733 : :
3734 : : ret = test_bpf_elf_load();
3735 : : if (ret == TEST_SUCCESS)
3736 : : ret = test_bpf_elf_tx_load();
3737 : : if (ret == TEST_SUCCESS)
3738 : : ret = test_bpf_elf_rx_load();
3739 : :
3740 : : return ret;
3741 : : }
3742 : :
3743 : : #else
3744 : :
3745 : : static int
3746 : 1 : test_bpf_elf(void)
3747 : : {
3748 : : printf("BPF compile not supported, skipping test\n");
3749 : 1 : return TEST_SKIPPED;
3750 : : }
3751 : :
3752 : : #endif /* !TEST_BPF_ELF_LOAD */
3753 : :
3754 : 254 : REGISTER_FAST_TEST(bpf_elf_autotest, true, true, test_bpf_elf);
3755 : :
3756 : : #ifndef RTE_HAS_LIBPCAP
3757 : :
3758 : : static int
3759 : : test_bpf_convert(void)
3760 : : {
3761 : : printf("BPF convert RTE_HAS_LIBPCAP is undefined, skipping test\n");
3762 : : return TEST_SKIPPED;
3763 : : }
3764 : :
3765 : : #else
3766 : : #include <pcap/pcap.h>
3767 : :
3768 : : static void
3769 : 0 : test_bpf_dump(struct bpf_program *cbf, const struct rte_bpf_prm *prm)
3770 : : {
3771 : 0 : printf("cBPF program (%u insns)\n", cbf->bf_len);
3772 : 0 : bpf_dump(cbf, 1);
3773 : :
3774 [ # # ]: 0 : if (prm != NULL) {
3775 : 0 : printf("\neBPF program (%u insns)\n", prm->nb_ins);
3776 : 0 : rte_bpf_dump(stdout, prm->ins, prm->nb_ins);
3777 : : }
3778 : 0 : }
3779 : :
3780 : : static int
3781 : 2 : test_bpf_match(pcap_t *pcap, const char *str,
3782 : : struct rte_mbuf *mb)
3783 : : {
3784 : : struct bpf_program fcode;
3785 : : struct rte_bpf_prm *prm = NULL;
3786 : : struct rte_bpf *bpf = NULL;
3787 : : int ret = -1;
3788 : : uint64_t rc;
3789 : :
3790 [ - + ]: 2 : if (pcap_compile(pcap, &fcode, str, 1, PCAP_NETMASK_UNKNOWN)) {
3791 : 0 : printf("%s@%d: pcap_compile(\"%s\") failed: %s;\n",
3792 : : __func__, __LINE__, str, pcap_geterr(pcap));
3793 : 0 : return -1;
3794 : : }
3795 : :
3796 : 2 : prm = rte_bpf_convert(&fcode);
3797 [ - + ]: 2 : if (prm == NULL) {
3798 : 0 : printf("%s@%d: bpf_convert('%s') failed,, error=%d(%s);\n",
3799 : : __func__, __LINE__, str, rte_errno, strerror(rte_errno));
3800 : 0 : goto error;
3801 : : }
3802 : :
3803 : 2 : bpf = rte_bpf_load(prm);
3804 [ - + ]: 2 : if (bpf == NULL) {
3805 : 0 : printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
3806 : : __func__, __LINE__, rte_errno, strerror(rte_errno));
3807 : 0 : goto error;
3808 : : }
3809 : :
3810 : 2 : rc = rte_bpf_exec(bpf, mb);
3811 : : /* The return code from bpf capture filter is non-zero if matched */
3812 : 2 : ret = (rc == 0);
3813 : 2 : error:
3814 [ + - ]: 2 : if (bpf)
3815 : 2 : rte_bpf_destroy(bpf);
3816 : 2 : rte_free(prm);
3817 : 2 : pcap_freecode(&fcode);
3818 : 2 : return ret;
3819 : : }
3820 : :
3821 : : /* Basic sanity test can we match a IP packet */
3822 : : static int
3823 : 1 : test_bpf_filter_sanity(pcap_t *pcap)
3824 : : {
3825 : : const uint32_t plen = 100;
3826 : : struct rte_mbuf mb, *m;
3827 : : uint8_t tbuf[RTE_MBUF_DEFAULT_BUF_SIZE];
3828 : : struct {
3829 : : struct rte_ether_hdr eth_hdr;
3830 : : struct rte_ipv4_hdr ip_hdr;
3831 : : } *hdr;
3832 : :
3833 : : memset(&mb, 0, sizeof(mb));
3834 : 1 : dummy_mbuf_prep(&mb, tbuf, sizeof(tbuf), plen);
3835 : : m = &mb;
3836 : :
3837 : 1 : hdr = rte_pktmbuf_mtod(m, typeof(hdr));
3838 : 1 : hdr->eth_hdr = (struct rte_ether_hdr) {
3839 : : .dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
3840 : : .ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4),
3841 : : };
3842 : 1 : hdr->ip_hdr = (struct rte_ipv4_hdr) {
3843 : : .version_ihl = RTE_IPV4_VHL_DEF,
3844 : : .total_length = rte_cpu_to_be_16(plen),
3845 : : .time_to_live = IPDEFTTL,
3846 : : .next_proto_id = IPPROTO_RAW,
3847 : : .src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK),
3848 : : .dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST),
3849 : : };
3850 : :
3851 [ - + ]: 1 : if (test_bpf_match(pcap, "ip", m) != 0) {
3852 : : printf("%s@%d: filter \"ip\" doesn't match test data\n",
3853 : : __func__, __LINE__);
3854 : 0 : return -1;
3855 : : }
3856 [ - + ]: 1 : if (test_bpf_match(pcap, "not ip", m) == 0) {
3857 : : printf("%s@%d: filter \"not ip\" does match test data\n",
3858 : : __func__, __LINE__);
3859 : 0 : return -1;
3860 : : }
3861 : :
3862 : : return 0;
3863 : : }
3864 : :
3865 : : /*
3866 : : * Some sample pcap filter strings from
3867 : : * https://wiki.wireshark.org/CaptureFilters
3868 : : */
3869 : : static const char * const sample_filters[] = {
3870 : : "host 172.18.5.4",
3871 : : "net 192.168.0.0/24",
3872 : : "src net 192.168.0.0/24",
3873 : : "src net 192.168.0.0 mask 255.255.255.0",
3874 : : "dst net 192.168.0.0/24",
3875 : : "dst net 192.168.0.0 mask 255.255.255.0",
3876 : : "port 53",
3877 : : "host 192.0.2.1 and not (port 80 or port 25)",
3878 : : "host 2001:4b98:db0::8 and not port 80 and not port 25",
3879 : : "port not 53 and not arp",
3880 : : "(tcp[0:2] > 1500 and tcp[0:2] < 1550) or (tcp[2:2] > 1500 and tcp[2:2] < 1550)",
3881 : : "ether proto 0x888e",
3882 : : "ether[0] & 1 = 0 and ip[16] >= 224",
3883 : : "icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply",
3884 : : "tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net 127.0.0.1",
3885 : : "not ether dst 01:80:c2:00:00:0e",
3886 : : "not broadcast and not multicast",
3887 : : "dst host ff02::1",
3888 : : "port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420",
3889 : : /* Worms */
3890 : : "dst port 135 and tcp port 135 and ip[2:2]==48",
3891 : : "icmp[icmptype]==icmp-echo and ip[2:2]==92 and icmp[8:4]==0xAAAAAAAA",
3892 : : "dst port 135 or dst port 445 or dst port 1433"
3893 : : " and tcp[tcpflags] & (tcp-syn) != 0"
3894 : : " and tcp[tcpflags] & (tcp-ack) = 0 and src net 192.168.0.0/24",
3895 : : "tcp src port 443 and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4] = 0x18)"
3896 : : " and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4 + 1] = 0x03)"
3897 : : " and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4 + 2] < 0x04)"
3898 : : " and ((ip[2:2] - 4 * (ip[0] & 0x0F) - 4 * ((tcp[12] & 0xF0) >> 4) > 69))",
3899 : : /* Other */
3900 : : "len = 128",
3901 : : "host 1::1 or host 1::1 or host 1::1 or host 1::1 or host 1::1 or host 1::1",
3902 : : ("host 1::1 or host 1::2 or host 1::3 or host 1::4 or host 1::5 "
3903 : : "or host 192.0.2.1 or host 192.0.2.100 or host 192.0.2.200"),
3904 : : };
3905 : :
3906 : : static int
3907 : 26 : test_bpf_filter(pcap_t *pcap, const char *s)
3908 : : {
3909 : : struct bpf_program fcode;
3910 : : struct rte_bpf_prm *prm = NULL;
3911 : : struct rte_bpf *bpf = NULL;
3912 : :
3913 [ - + ]: 26 : if (pcap_compile(pcap, &fcode, s, 1, PCAP_NETMASK_UNKNOWN)) {
3914 : 0 : printf("%s@%d: pcap_compile('%s') failed: %s;\n",
3915 : : __func__, __LINE__, s, pcap_geterr(pcap));
3916 : 0 : return -1;
3917 : : }
3918 : :
3919 : 26 : prm = rte_bpf_convert(&fcode);
3920 [ - + ]: 26 : if (prm == NULL) {
3921 : 0 : printf("%s@%d: bpf_convert('%s') failed,, error=%d(%s);\n",
3922 : : __func__, __LINE__, s, rte_errno, strerror(rte_errno));
3923 : 0 : goto error;
3924 : : }
3925 : :
3926 : : printf("bpf convert for \"%s\" produced:\n", s);
3927 : 26 : rte_bpf_dump(stdout, prm->ins, prm->nb_ins);
3928 : :
3929 : 26 : bpf = rte_bpf_load(prm);
3930 [ + - ]: 26 : if (bpf == NULL) {
3931 : 0 : printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
3932 : : __func__, __LINE__, rte_errno, strerror(rte_errno));
3933 : 0 : goto error;
3934 : : }
3935 : :
3936 : 26 : error:
3937 [ + - ]: 26 : if (bpf)
3938 : 26 : rte_bpf_destroy(bpf);
3939 : : else {
3940 : : printf("%s \"%s\"\n", __func__, s);
3941 : 0 : test_bpf_dump(&fcode, prm);
3942 : : }
3943 : :
3944 : 26 : rte_free(prm);
3945 : 26 : pcap_freecode(&fcode);
3946 [ + - ]: 26 : return (bpf == NULL) ? -1 : 0;
3947 : : }
3948 : :
3949 : : static int
3950 : 1 : test_bpf_convert(void)
3951 : : {
3952 : : unsigned int i;
3953 : : pcap_t *pcap;
3954 : : int rc;
3955 : :
3956 : 1 : pcap = pcap_open_dead(DLT_EN10MB, 262144);
3957 [ - + ]: 1 : if (!pcap) {
3958 : : printf("pcap_open_dead failed\n");
3959 : 0 : return -1;
3960 : : }
3961 : :
3962 : 1 : rc = test_bpf_filter_sanity(pcap);
3963 [ + + ]: 27 : for (i = 0; i < RTE_DIM(sample_filters); i++)
3964 : 26 : rc |= test_bpf_filter(pcap, sample_filters[i]);
3965 : :
3966 : 1 : pcap_close(pcap);
3967 : 1 : return rc;
3968 : : }
3969 : :
3970 : : #endif /* RTE_HAS_LIBPCAP */
3971 : :
3972 : 254 : REGISTER_FAST_TEST(bpf_convert_autotest, true, true, test_bpf_convert);
|