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