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 results 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 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1573 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 1574 1575 rv = -1; 1576 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1577 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 1578 1579 rv = (int32_t)TEST_FILL_1; 1580 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1581 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 1582 1583 rv = TEST_MUL_1; 1584 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1585 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 1586 1587 rv = TEST_MUL_2; 1588 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1589 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 1590 1591 rv = TEST_JCC_2; 1592 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1593 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 1594 1595 rv = TEST_JCC_3; 1596 __atomic_fetch_add(&dfe.u32, rv, __ATOMIC_RELAXED); 1597 __atomic_fetch_add(&dfe.u64, rv, __ATOMIC_RELAXED); 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 comparison implementation, 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 truncate 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 192.0.2.1 and not (port 80 or port 25)", 3363 "host 2001:4b98:db0::8 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