1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <rte_string_fns.h> 6 #include <rte_acl.h> 7 #include <getopt.h> 8 #include <string.h> 9 10 #include <rte_cycles.h> 11 #include <rte_per_lcore.h> 12 #include <rte_lcore.h> 13 #include <rte_ip.h> 14 15 #define PRINT_USAGE_START "%s [EAL options] --\n" 16 17 #define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1 18 19 #define APP_NAME "TESTACL" 20 21 #define GET_CB_FIELD(in, fd, base, lim, dlm) do { \ 22 unsigned long val; \ 23 char *end_fld; \ 24 errno = 0; \ 25 val = strtoul((in), &end_fld, (base)); \ 26 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \ 27 return -EINVAL; \ 28 (fd) = (typeof(fd))val; \ 29 (in) = end_fld + 1; \ 30 } while (0) 31 32 #define OPT_RULE_FILE "rulesf" 33 #define OPT_TRACE_FILE "tracef" 34 #define OPT_RULE_NUM "rulenum" 35 #define OPT_TRACE_NUM "tracenum" 36 #define OPT_TRACE_STEP "tracestep" 37 #define OPT_SEARCH_ALG "alg" 38 #define OPT_BLD_CATEGORIES "bldcat" 39 #define OPT_RUN_CATEGORIES "runcat" 40 #define OPT_MAX_SIZE "maxsize" 41 #define OPT_ITER_NUM "iter" 42 #define OPT_VERBOSE "verbose" 43 #define OPT_IPV6 "ipv6" 44 45 #define TRACE_DEFAULT_NUM 0x10000 46 #define TRACE_STEP_MAX 0x1000 47 #define TRACE_STEP_DEF 0x100 48 49 #define RULE_NUM 0x10000 50 51 #define COMMENT_LEAD_CHAR '#' 52 53 enum { 54 DUMP_NONE, 55 DUMP_SEARCH, 56 DUMP_PKT, 57 DUMP_MAX 58 }; 59 60 enum { 61 IPV6_FRMT_NONE, 62 IPV6_FRMT_U32, 63 IPV6_FRMT_U64, 64 }; 65 66 struct acl_alg { 67 const char *name; 68 enum rte_acl_classify_alg alg; 69 }; 70 71 static const struct acl_alg acl_alg[] = { 72 { 73 .name = "scalar", 74 .alg = RTE_ACL_CLASSIFY_SCALAR, 75 }, 76 { 77 .name = "sse", 78 .alg = RTE_ACL_CLASSIFY_SSE, 79 }, 80 { 81 .name = "avx2", 82 .alg = RTE_ACL_CLASSIFY_AVX2, 83 }, 84 { 85 .name = "neon", 86 .alg = RTE_ACL_CLASSIFY_NEON, 87 }, 88 { 89 .name = "altivec", 90 .alg = RTE_ACL_CLASSIFY_ALTIVEC, 91 }, 92 { 93 .name = "avx512x16", 94 .alg = RTE_ACL_CLASSIFY_AVX512X16, 95 }, 96 { 97 .name = "avx512x32", 98 .alg = RTE_ACL_CLASSIFY_AVX512X32, 99 }, 100 }; 101 102 static struct { 103 const char *prgname; 104 const char *rule_file; 105 const char *trace_file; 106 size_t max_size; 107 uint32_t bld_categories; 108 uint32_t run_categories; 109 uint32_t nb_rules; 110 uint32_t nb_traces; 111 uint32_t trace_step; 112 uint32_t trace_sz; 113 uint32_t iter_num; 114 uint32_t verbose; 115 uint32_t ipv6; 116 struct acl_alg alg; 117 uint32_t used_traces; 118 void *traces; 119 struct rte_acl_ctx *acx; 120 } config = { 121 .bld_categories = 3, 122 .run_categories = 1, 123 .nb_rules = RULE_NUM, 124 .nb_traces = TRACE_DEFAULT_NUM, 125 .trace_step = TRACE_STEP_DEF, 126 .iter_num = 1, 127 .verbose = DUMP_MAX, 128 .alg = { 129 .name = "default", 130 .alg = RTE_ACL_CLASSIFY_DEFAULT, 131 }, 132 .ipv6 = IPV6_FRMT_NONE, 133 }; 134 135 static struct rte_acl_param prm = { 136 .name = APP_NAME, 137 .socket_id = SOCKET_ID_ANY, 138 }; 139 140 /* 141 * Rule and trace formats definitions. 142 */ 143 144 struct ipv4_5tuple { 145 uint8_t proto; 146 uint32_t ip_src; 147 uint32_t ip_dst; 148 uint16_t port_src; 149 uint16_t port_dst; 150 }; 151 152 enum { 153 PROTO_FIELD_IPV4, 154 SRC_FIELD_IPV4, 155 DST_FIELD_IPV4, 156 SRCP_FIELD_IPV4, 157 DSTP_FIELD_IPV4, 158 NUM_FIELDS_IPV4 159 }; 160 161 /* 162 * That effectively defines order of IPV4VLAN classifications: 163 * - PROTO 164 * - VLAN (TAG and DOMAIN) 165 * - SRC IP ADDRESS 166 * - DST IP ADDRESS 167 * - PORTS (SRC and DST) 168 */ 169 enum { 170 RTE_ACL_IPV4VLAN_PROTO, 171 RTE_ACL_IPV4VLAN_VLAN, 172 RTE_ACL_IPV4VLAN_SRC, 173 RTE_ACL_IPV4VLAN_DST, 174 RTE_ACL_IPV4VLAN_PORTS, 175 RTE_ACL_IPV4VLAN_NUM 176 }; 177 178 struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { 179 { 180 .type = RTE_ACL_FIELD_TYPE_BITMASK, 181 .size = sizeof(uint8_t), 182 .field_index = PROTO_FIELD_IPV4, 183 .input_index = RTE_ACL_IPV4VLAN_PROTO, 184 .offset = offsetof(struct ipv4_5tuple, proto), 185 }, 186 { 187 .type = RTE_ACL_FIELD_TYPE_MASK, 188 .size = sizeof(uint32_t), 189 .field_index = SRC_FIELD_IPV4, 190 .input_index = RTE_ACL_IPV4VLAN_SRC, 191 .offset = offsetof(struct ipv4_5tuple, ip_src), 192 }, 193 { 194 .type = RTE_ACL_FIELD_TYPE_MASK, 195 .size = sizeof(uint32_t), 196 .field_index = DST_FIELD_IPV4, 197 .input_index = RTE_ACL_IPV4VLAN_DST, 198 .offset = offsetof(struct ipv4_5tuple, ip_dst), 199 }, 200 { 201 .type = RTE_ACL_FIELD_TYPE_RANGE, 202 .size = sizeof(uint16_t), 203 .field_index = SRCP_FIELD_IPV4, 204 .input_index = RTE_ACL_IPV4VLAN_PORTS, 205 .offset = offsetof(struct ipv4_5tuple, port_src), 206 }, 207 { 208 .type = RTE_ACL_FIELD_TYPE_RANGE, 209 .size = sizeof(uint16_t), 210 .field_index = DSTP_FIELD_IPV4, 211 .input_index = RTE_ACL_IPV4VLAN_PORTS, 212 .offset = offsetof(struct ipv4_5tuple, port_dst), 213 }, 214 }; 215 216 #define IPV6_ADDR_LEN 16 217 #define IPV6_ADDR_U16 (IPV6_ADDR_LEN / sizeof(uint16_t)) 218 #define IPV6_ADDR_U32 (IPV6_ADDR_LEN / sizeof(uint32_t)) 219 #define IPV6_ADDR_U64 (IPV6_ADDR_LEN / sizeof(uint64_t)) 220 221 struct ipv6_5tuple { 222 uint8_t proto; 223 uint32_t ip_src[IPV6_ADDR_U32]; 224 uint32_t ip_dst[IPV6_ADDR_U32]; 225 uint16_t port_src; 226 uint16_t port_dst; 227 }; 228 229 /* treat IPV6 address as uint32_t[4] (default mode) */ 230 enum { 231 PROTO_FIELD_IPV6, 232 SRC1_FIELD_IPV6, 233 SRC2_FIELD_IPV6, 234 SRC3_FIELD_IPV6, 235 SRC4_FIELD_IPV6, 236 DST1_FIELD_IPV6, 237 DST2_FIELD_IPV6, 238 DST3_FIELD_IPV6, 239 DST4_FIELD_IPV6, 240 SRCP_FIELD_IPV6, 241 DSTP_FIELD_IPV6, 242 NUM_FIELDS_IPV6 243 }; 244 245 /* treat IPV6 address as uint64_t[2] (default mode) */ 246 enum { 247 PROTO_FIELD_IPV6_U64, 248 SRC1_FIELD_IPV6_U64, 249 SRC2_FIELD_IPV6_U64, 250 DST1_FIELD_IPV6_U64, 251 DST2_FIELD_IPV6_U64, 252 SRCP_FIELD_IPV6_U64, 253 DSTP_FIELD_IPV6_U64, 254 NUM_FIELDS_IPV6_U64 255 }; 256 257 enum { 258 PROTO_INDEX_IPV6_U64 = PROTO_FIELD_IPV6_U64, 259 SRC1_INDEX_IPV6_U64 = SRC1_FIELD_IPV6_U64, 260 SRC2_INDEX_IPV6_U64 = SRC2_FIELD_IPV6_U64 + 1, 261 DST1_INDEX_IPV6_U64 = DST1_FIELD_IPV6_U64 + 2, 262 DST2_INDEX_IPV6_U64 = DST2_FIELD_IPV6_U64 + 3, 263 PRT_INDEX_IPV6_U64 = SRCP_FIELD_IPV6 + 4, 264 }; 265 266 struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = { 267 { 268 .type = RTE_ACL_FIELD_TYPE_BITMASK, 269 .size = sizeof(uint8_t), 270 .field_index = PROTO_FIELD_IPV6, 271 .input_index = PROTO_FIELD_IPV6, 272 .offset = offsetof(struct ipv6_5tuple, proto), 273 }, 274 { 275 .type = RTE_ACL_FIELD_TYPE_MASK, 276 .size = sizeof(uint32_t), 277 .field_index = SRC1_FIELD_IPV6, 278 .input_index = SRC1_FIELD_IPV6, 279 .offset = offsetof(struct ipv6_5tuple, ip_src[0]), 280 }, 281 { 282 .type = RTE_ACL_FIELD_TYPE_MASK, 283 .size = sizeof(uint32_t), 284 .field_index = SRC2_FIELD_IPV6, 285 .input_index = SRC2_FIELD_IPV6, 286 .offset = offsetof(struct ipv6_5tuple, ip_src[1]), 287 }, 288 { 289 .type = RTE_ACL_FIELD_TYPE_MASK, 290 .size = sizeof(uint32_t), 291 .field_index = SRC3_FIELD_IPV6, 292 .input_index = SRC3_FIELD_IPV6, 293 .offset = offsetof(struct ipv6_5tuple, ip_src[2]), 294 }, 295 { 296 .type = RTE_ACL_FIELD_TYPE_MASK, 297 .size = sizeof(uint32_t), 298 .field_index = SRC4_FIELD_IPV6, 299 .input_index = SRC4_FIELD_IPV6, 300 .offset = offsetof(struct ipv6_5tuple, ip_src[3]), 301 }, 302 { 303 .type = RTE_ACL_FIELD_TYPE_MASK, 304 .size = sizeof(uint32_t), 305 .field_index = DST1_FIELD_IPV6, 306 .input_index = DST1_FIELD_IPV6, 307 .offset = offsetof(struct ipv6_5tuple, ip_dst[0]), 308 }, 309 { 310 .type = RTE_ACL_FIELD_TYPE_MASK, 311 .size = sizeof(uint32_t), 312 .field_index = DST2_FIELD_IPV6, 313 .input_index = DST2_FIELD_IPV6, 314 .offset = offsetof(struct ipv6_5tuple, ip_dst[1]), 315 }, 316 { 317 .type = RTE_ACL_FIELD_TYPE_MASK, 318 .size = sizeof(uint32_t), 319 .field_index = DST3_FIELD_IPV6, 320 .input_index = DST3_FIELD_IPV6, 321 .offset = offsetof(struct ipv6_5tuple, ip_dst[2]), 322 }, 323 { 324 .type = RTE_ACL_FIELD_TYPE_MASK, 325 .size = sizeof(uint32_t), 326 .field_index = DST4_FIELD_IPV6, 327 .input_index = DST4_FIELD_IPV6, 328 .offset = offsetof(struct ipv6_5tuple, ip_dst[3]), 329 }, 330 { 331 .type = RTE_ACL_FIELD_TYPE_RANGE, 332 .size = sizeof(uint16_t), 333 .field_index = SRCP_FIELD_IPV6, 334 .input_index = SRCP_FIELD_IPV6, 335 .offset = offsetof(struct ipv6_5tuple, port_src), 336 }, 337 { 338 .type = RTE_ACL_FIELD_TYPE_RANGE, 339 .size = sizeof(uint16_t), 340 .field_index = DSTP_FIELD_IPV6, 341 .input_index = SRCP_FIELD_IPV6, 342 .offset = offsetof(struct ipv6_5tuple, port_dst), 343 }, 344 }; 345 346 struct rte_acl_field_def ipv6_u64_defs[NUM_FIELDS_IPV6_U64] = { 347 { 348 .type = RTE_ACL_FIELD_TYPE_BITMASK, 349 .size = sizeof(uint8_t), 350 .field_index = PROTO_FIELD_IPV6_U64, 351 .input_index = PROTO_FIELD_IPV6_U64, 352 .offset = offsetof(struct ipv6_5tuple, proto), 353 }, 354 { 355 .type = RTE_ACL_FIELD_TYPE_MASK, 356 .size = sizeof(uint64_t), 357 .field_index = SRC1_FIELD_IPV6_U64, 358 .input_index = SRC1_INDEX_IPV6_U64, 359 .offset = offsetof(struct ipv6_5tuple, ip_src[0]), 360 }, 361 { 362 .type = RTE_ACL_FIELD_TYPE_MASK, 363 .size = sizeof(uint64_t), 364 .field_index = SRC2_FIELD_IPV6_U64, 365 .input_index = SRC2_INDEX_IPV6_U64, 366 .offset = offsetof(struct ipv6_5tuple, ip_src[2]), 367 }, 368 { 369 .type = RTE_ACL_FIELD_TYPE_MASK, 370 .size = sizeof(uint64_t), 371 .field_index = DST1_FIELD_IPV6_U64, 372 .input_index = DST1_INDEX_IPV6_U64, 373 .offset = offsetof(struct ipv6_5tuple, ip_dst[0]), 374 }, 375 { 376 .type = RTE_ACL_FIELD_TYPE_MASK, 377 .size = sizeof(uint64_t), 378 .field_index = DST2_FIELD_IPV6_U64, 379 .input_index = DST2_INDEX_IPV6_U64, 380 .offset = offsetof(struct ipv6_5tuple, ip_dst[2]), 381 }, 382 { 383 .type = RTE_ACL_FIELD_TYPE_RANGE, 384 .size = sizeof(uint16_t), 385 .field_index = SRCP_FIELD_IPV6_U64, 386 .input_index = PRT_INDEX_IPV6_U64, 387 .offset = offsetof(struct ipv6_5tuple, port_src), 388 }, 389 { 390 .type = RTE_ACL_FIELD_TYPE_RANGE, 391 .size = sizeof(uint16_t), 392 .field_index = DSTP_FIELD_IPV6_U64, 393 .input_index = PRT_INDEX_IPV6_U64, 394 .offset = offsetof(struct ipv6_5tuple, port_dst), 395 }, 396 }; 397 398 enum { 399 CB_FLD_SRC_ADDR, 400 CB_FLD_DST_ADDR, 401 CB_FLD_SRC_PORT_LOW, 402 CB_FLD_SRC_PORT_DLM, 403 CB_FLD_SRC_PORT_HIGH, 404 CB_FLD_DST_PORT_LOW, 405 CB_FLD_DST_PORT_DLM, 406 CB_FLD_DST_PORT_HIGH, 407 CB_FLD_PROTO, 408 CB_FLD_NUM, 409 }; 410 411 enum { 412 CB_TRC_SRC_ADDR, 413 CB_TRC_DST_ADDR, 414 CB_TRC_SRC_PORT, 415 CB_TRC_DST_PORT, 416 CB_TRC_PROTO, 417 CB_TRC_NUM, 418 }; 419 420 RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS); 421 422 static const char cb_port_delim[] = ":"; 423 424 static char line[LINE_MAX]; 425 426 #define dump_verbose(lvl, fh, fmt, ...) do { \ 427 if ((lvl) <= (int32_t)config.verbose) \ 428 fprintf(fh, fmt, ##__VA_ARGS__); \ 429 } while (0) 430 431 432 /* 433 * Parse ClassBench input trace (test vectors and expected results) file. 434 * Expected format: 435 * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \ 436 * <src_port> <space> <dst_port> <space> <proto> 437 */ 438 static int 439 parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v) 440 { 441 int i; 442 char *s, *sp, *in[CB_TRC_NUM]; 443 static const char *dlm = " \t\n"; 444 445 s = str; 446 for (i = 0; i != RTE_DIM(in); i++) { 447 in[i] = strtok_r(s, dlm, &sp); 448 if (in[i] == NULL) 449 return -EINVAL; 450 s = NULL; 451 } 452 453 GET_CB_FIELD(in[CB_TRC_SRC_ADDR], v->ip_src, 0, UINT32_MAX, 0); 454 GET_CB_FIELD(in[CB_TRC_DST_ADDR], v->ip_dst, 0, UINT32_MAX, 0); 455 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0); 456 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0); 457 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0); 458 459 /* convert to network byte order. */ 460 v->ip_src = rte_cpu_to_be_32(v->ip_src); 461 v->ip_dst = rte_cpu_to_be_32(v->ip_dst); 462 v->port_src = rte_cpu_to_be_16(v->port_src); 463 v->port_dst = rte_cpu_to_be_16(v->port_dst); 464 465 return 0; 466 } 467 468 static int 469 parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32]) 470 { 471 if (inet_pton(AF_INET6, in, v) != 1) 472 return -EINVAL; 473 474 return 0; 475 } 476 477 /* 478 * Parse ClassBench input trace (test vectors and expected results) file. 479 * Expected format: 480 * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \ 481 * <src_port> <space> <dst_port> <space> <proto> 482 */ 483 static int 484 parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v) 485 { 486 int32_t i, rc; 487 char *s, *sp, *in[CB_TRC_NUM]; 488 static const char *dlm = " \t\n"; 489 490 s = str; 491 for (i = 0; i != RTE_DIM(in); i++) { 492 in[i] = strtok_r(s, dlm, &sp); 493 if (in[i] == NULL) 494 return -EINVAL; 495 s = NULL; 496 } 497 498 /* get ip6 src address. */ 499 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src); 500 if (rc != 0) 501 return rc; 502 503 /* get ip6 dst address. */ 504 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst); 505 if (rc != 0) 506 return rc; 507 508 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0); 509 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0); 510 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0); 511 512 /* convert to network byte order. */ 513 v->port_src = rte_cpu_to_be_16(v->port_src); 514 v->port_dst = rte_cpu_to_be_16(v->port_dst); 515 516 return 0; 517 } 518 519 /* Bypass comment and empty lines */ 520 static int 521 skip_line(const char *buf) 522 { 523 uint32_t i; 524 525 for (i = 0; isspace(buf[i]) != 0; i++) 526 ; 527 528 if (buf[i] == 0 || buf[i] == COMMENT_LEAD_CHAR) 529 return 1; 530 531 return 0; 532 } 533 534 static void 535 tracef_init(void) 536 { 537 static const char name[] = APP_NAME; 538 FILE *f; 539 size_t sz; 540 uint32_t i, k, n; 541 struct ipv4_5tuple *v; 542 struct ipv6_5tuple *w; 543 544 sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v)); 545 config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE, 546 SOCKET_ID_ANY); 547 if (config.traces == NULL) 548 rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for " 549 "requested %u number of trace records\n", 550 sz, config.nb_traces); 551 552 f = fopen(config.trace_file, "r"); 553 if (f == NULL) 554 rte_exit(-EINVAL, "failed to open file: %s\n", 555 config.trace_file); 556 557 v = config.traces; 558 w = config.traces; 559 k = 0; 560 n = 0; 561 for (i = 0; n != config.nb_traces; i++) { 562 563 if (fgets(line, sizeof(line), f) == NULL) 564 break; 565 566 if (skip_line(line) != 0) { 567 k++; 568 continue; 569 } 570 571 n = i - k; 572 573 if (config.ipv6) { 574 if (parse_cb_ipv6_trace(line, w + n) != 0) 575 rte_exit(EXIT_FAILURE, 576 "%s: failed to parse ipv6 trace " 577 "record at line %u\n", 578 config.trace_file, i + 1); 579 } else { 580 if (parse_cb_ipv4_trace(line, v + n) != 0) 581 rte_exit(EXIT_FAILURE, 582 "%s: failed to parse ipv4 trace " 583 "record at line %u\n", 584 config.trace_file, i + 1); 585 } 586 } 587 588 config.used_traces = i - k; 589 fclose(f); 590 } 591 592 static int 593 parse_ipv6_u32_net(char *in, struct rte_acl_field field[IPV6_ADDR_U32]) 594 { 595 char *sa, *sm, *sv; 596 uint32_t i, m, v[IPV6_ADDR_U32]; 597 598 const char *dlm = "/"; 599 const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT; 600 601 /* get address. */ 602 sv = NULL; 603 sa = strtok_r(in, dlm, &sv); 604 if (sa == NULL) 605 return -EINVAL; 606 sm = strtok_r(NULL, dlm, &sv); 607 if (sm == NULL) 608 return -EINVAL; 609 610 if (inet_pton(AF_INET6, sa, v) != 1) 611 return -EINVAL; 612 613 v[0] = rte_be_to_cpu_32(v[0]); 614 v[1] = rte_be_to_cpu_32(v[1]); 615 v[2] = rte_be_to_cpu_32(v[2]); 616 v[3] = rte_be_to_cpu_32(v[3]); 617 618 /* get mask. */ 619 GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0); 620 621 /* put all together. */ 622 for (i = 0; i != RTE_DIM(v); i++) { 623 if (m >= (i + 1) * nbu32) 624 field[i].mask_range.u32 = nbu32; 625 else 626 field[i].mask_range.u32 = m > (i * nbu32) ? 627 m - (i * nbu32) : 0; 628 629 field[i].value.u32 = v[i]; 630 } 631 632 return 0; 633 } 634 635 static int 636 parse_ipv6_u64_net(char *in, struct rte_acl_field field[IPV6_ADDR_U64]) 637 { 638 char *sa, *sm, *sv; 639 uint32_t i, m; 640 uint64_t v[IPV6_ADDR_U64]; 641 642 const char *dlm = "/"; 643 const uint32_t nbu64 = sizeof(uint64_t) * CHAR_BIT; 644 645 /* get address. */ 646 sv = NULL; 647 sa = strtok_r(in, dlm, &sv); 648 if (sa == NULL) 649 return -EINVAL; 650 sm = strtok_r(NULL, dlm, &sv); 651 if (sm == NULL) 652 return -EINVAL; 653 654 if (inet_pton(AF_INET6, sa, v) != 1) 655 return -EINVAL; 656 657 v[0] = rte_be_to_cpu_64(v[0]); 658 v[1] = rte_be_to_cpu_64(v[1]); 659 660 /* get mask. */ 661 GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0); 662 663 /* put all together. */ 664 for (i = 0; i != RTE_DIM(v); i++) { 665 if (m >= (i + 1) * nbu64) 666 field[i].mask_range.u32 = nbu64; 667 else 668 field[i].mask_range.u32 = m > (i * nbu64) ? 669 m - (i * nbu64) : 0; 670 671 field[i].value.u64 = v[i]; 672 } 673 674 return 0; 675 } 676 677 static int 678 parse_cb_ipv6_rule(char *str, struct acl_rule *v, int frmt) 679 { 680 int i, rc; 681 uint32_t fidx; 682 const uint32_t *field_map; 683 char *s, *sp, *in[CB_FLD_NUM]; 684 int (*parse_ipv6_net)(char *s, struct rte_acl_field f[]); 685 686 static const char *dlm = " \t\n"; 687 688 static const uint32_t field_map_u32[CB_FLD_NUM] = { 689 [CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6, 690 [CB_FLD_DST_ADDR] = DST1_FIELD_IPV6, 691 [CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6, 692 [CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6, 693 [CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6, 694 [CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6, 695 [CB_FLD_PROTO] = PROTO_FIELD_IPV6, 696 }; 697 698 static const uint32_t field_map_u64[CB_FLD_NUM] = { 699 [CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6_U64, 700 [CB_FLD_DST_ADDR] = DST1_FIELD_IPV6_U64, 701 [CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6_U64, 702 [CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6_U64, 703 [CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6_U64, 704 [CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6_U64, 705 [CB_FLD_PROTO] = PROTO_FIELD_IPV6_U64, 706 }; 707 708 if (frmt == IPV6_FRMT_U32) { 709 field_map = field_map_u32; 710 parse_ipv6_net = parse_ipv6_u32_net; 711 } else if (frmt == IPV6_FRMT_U64) { 712 field_map = field_map_u64; 713 parse_ipv6_net = parse_ipv6_u64_net; 714 } else 715 return -ENOTSUP; 716 717 /* 718 * Skip leading '@' 719 */ 720 if (strchr(str, '@') != str) 721 return -EINVAL; 722 723 s = str + 1; 724 725 for (i = 0; i != RTE_DIM(in); i++) { 726 in[i] = strtok_r(s, dlm, &sp); 727 if (in[i] == NULL) 728 return -EINVAL; 729 s = NULL; 730 } 731 732 fidx = CB_FLD_SRC_ADDR; 733 rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]); 734 if (rc != 0) { 735 RTE_LOG(ERR, TESTACL, 736 "failed to read source address/mask: %s\n", in[fidx]); 737 return rc; 738 } 739 740 fidx = CB_FLD_DST_ADDR; 741 rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]); 742 if (rc != 0) { 743 RTE_LOG(ERR, TESTACL, 744 "failed to read destination address/mask: %s\n", 745 in[fidx]); 746 return rc; 747 } 748 749 /* source port. */ 750 fidx = CB_FLD_SRC_PORT_LOW; 751 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16, 752 0, UINT16_MAX, 0); 753 754 fidx = CB_FLD_SRC_PORT_HIGH; 755 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16, 756 0, UINT16_MAX, 0); 757 758 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, 759 sizeof(cb_port_delim)) != 0) 760 return -EINVAL; 761 762 /* destination port. */ 763 fidx = CB_FLD_DST_PORT_LOW; 764 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16, 765 0, UINT16_MAX, 0); 766 767 fidx = CB_FLD_DST_PORT_HIGH; 768 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16, 769 0, UINT16_MAX, 0); 770 771 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, 772 sizeof(cb_port_delim)) != 0) 773 return -EINVAL; 774 775 fidx = CB_FLD_PROTO; 776 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u8, 777 0, UINT8_MAX, '/'); 778 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u8, 779 0, UINT8_MAX, 0); 780 781 return 0; 782 } 783 784 static int 785 parse_cb_ipv6_u32_rule(char *str, struct acl_rule *v) 786 { 787 return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U32); 788 } 789 790 static int 791 parse_cb_ipv6_u64_rule(char *str, struct acl_rule *v) 792 { 793 return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U64); 794 } 795 796 static int 797 parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len) 798 { 799 char *sa, *sm, *sv; 800 uint32_t m, v; 801 802 const char *dlm = "/"; 803 804 sv = NULL; 805 sa = strtok_r(in, dlm, &sv); 806 if (sa == NULL) 807 return -EINVAL; 808 sm = strtok_r(NULL, dlm, &sv); 809 if (sm == NULL) 810 return -EINVAL; 811 812 if (inet_pton(AF_INET, sa, &v) != 1) 813 return -EINVAL; 814 815 addr[0] = rte_be_to_cpu_32(v); 816 817 GET_CB_FIELD(sm, m, 0, sizeof(uint32_t) * CHAR_BIT, 0); 818 mask_len[0] = m; 819 820 return 0; 821 } 822 /* 823 * Parse ClassBench rules file. 824 * Expected format: 825 * '@'<src_ipv4_addr>'/'<masklen> <space> \ 826 * <dst_ipv4_addr>'/'<masklen> <space> \ 827 * <src_port_low> <space> ":" <src_port_high> <space> \ 828 * <dst_port_low> <space> ":" <dst_port_high> <space> \ 829 * <proto>'/'<mask> 830 */ 831 static int 832 parse_cb_ipv4_rule(char *str, struct acl_rule *v) 833 { 834 int i, rc; 835 char *s, *sp, *in[CB_FLD_NUM]; 836 static const char *dlm = " \t\n"; 837 838 /* 839 * Skip leading '@' 840 */ 841 if (strchr(str, '@') != str) 842 return -EINVAL; 843 844 s = str + 1; 845 846 for (i = 0; i != RTE_DIM(in); i++) { 847 in[i] = strtok_r(s, dlm, &sp); 848 if (in[i] == NULL) 849 return -EINVAL; 850 s = NULL; 851 } 852 853 rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], 854 &v->field[SRC_FIELD_IPV4].value.u32, 855 &v->field[SRC_FIELD_IPV4].mask_range.u32); 856 if (rc != 0) { 857 RTE_LOG(ERR, TESTACL, 858 "failed to read source address/mask: %s\n", 859 in[CB_FLD_SRC_ADDR]); 860 return rc; 861 } 862 863 rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], 864 &v->field[DST_FIELD_IPV4].value.u32, 865 &v->field[DST_FIELD_IPV4].mask_range.u32); 866 if (rc != 0) { 867 RTE_LOG(ERR, TESTACL, 868 "failed to read destination address/mask: %s\n", 869 in[CB_FLD_DST_ADDR]); 870 return rc; 871 } 872 873 /* source port. */ 874 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW], 875 v->field[SRCP_FIELD_IPV4].value.u16, 876 0, UINT16_MAX, 0); 877 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH], 878 v->field[SRCP_FIELD_IPV4].mask_range.u16, 879 0, UINT16_MAX, 0); 880 881 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, 882 sizeof(cb_port_delim)) != 0) 883 return -EINVAL; 884 885 /* destination port. */ 886 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW], 887 v->field[DSTP_FIELD_IPV4].value.u16, 888 0, UINT16_MAX, 0); 889 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH], 890 v->field[DSTP_FIELD_IPV4].mask_range.u16, 891 0, UINT16_MAX, 0); 892 893 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, 894 sizeof(cb_port_delim)) != 0) 895 return -EINVAL; 896 897 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8, 898 0, UINT8_MAX, '/'); 899 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8, 900 0, UINT8_MAX, 0); 901 902 return 0; 903 } 904 905 typedef int (*parse_5tuple)(char *text, struct acl_rule *rule); 906 907 static int 908 add_cb_rules(FILE *f, struct rte_acl_ctx *ctx) 909 { 910 int rc; 911 uint32_t i, k, n; 912 struct acl_rule v; 913 parse_5tuple parser; 914 915 static const parse_5tuple parser_func[] = { 916 [IPV6_FRMT_NONE] = parse_cb_ipv4_rule, 917 [IPV6_FRMT_U32] = parse_cb_ipv6_u32_rule, 918 [IPV6_FRMT_U64] = parse_cb_ipv6_u64_rule, 919 }; 920 921 memset(&v, 0, sizeof(v)); 922 parser = parser_func[config.ipv6]; 923 924 k = 0; 925 for (i = 1; fgets(line, sizeof(line), f) != NULL; i++) { 926 927 if (skip_line(line) != 0) { 928 k++; 929 continue; 930 } 931 932 n = i - k; 933 rc = parser(line, &v); 934 if (rc != 0) { 935 RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule" 936 " failed, error code: %d (%s)\n", 937 i, rc, strerror(-rc)); 938 return rc; 939 } 940 941 v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES, 942 typeof(v.data.category_mask)); 943 v.data.priority = RTE_ACL_MAX_PRIORITY - n; 944 v.data.userdata = n; 945 946 rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1); 947 if (rc != 0) { 948 RTE_LOG(ERR, TESTACL, "line %u: failed to add rules " 949 "into ACL context, error code: %d (%s)\n", 950 i, rc, strerror(-rc)); 951 return rc; 952 } 953 } 954 955 return 0; 956 } 957 958 static void 959 acx_init(void) 960 { 961 int ret; 962 FILE *f; 963 struct rte_acl_config cfg; 964 965 memset(&cfg, 0, sizeof(cfg)); 966 967 /* setup ACL build config. */ 968 if (config.ipv6 == IPV6_FRMT_U32) { 969 cfg.num_fields = RTE_DIM(ipv6_defs); 970 memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs)); 971 } else if (config.ipv6 == IPV6_FRMT_U64) { 972 cfg.num_fields = RTE_DIM(ipv6_u64_defs); 973 memcpy(&cfg.defs, ipv6_u64_defs, sizeof(ipv6_u64_defs)); 974 } else { 975 cfg.num_fields = RTE_DIM(ipv4_defs); 976 memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs)); 977 } 978 cfg.num_categories = config.bld_categories; 979 cfg.max_size = config.max_size; 980 981 /* setup ACL creation parameters. */ 982 prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields); 983 prm.max_rule_num = config.nb_rules; 984 985 config.acx = rte_acl_create(&prm); 986 if (config.acx == NULL) 987 rte_exit(rte_errno, "failed to create ACL context\n"); 988 989 /* set default classify method for this context. */ 990 if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) { 991 ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg); 992 if (ret != 0) 993 rte_exit(ret, "failed to setup %s method " 994 "for ACL context\n", config.alg.name); 995 } 996 997 /* add ACL rules. */ 998 f = fopen(config.rule_file, "r"); 999 if (f == NULL) 1000 rte_exit(-EINVAL, "failed to open file %s\n", 1001 config.rule_file); 1002 1003 ret = add_cb_rules(f, config.acx); 1004 if (ret != 0) 1005 rte_exit(ret, "failed to add rules into ACL context\n"); 1006 1007 fclose(f); 1008 1009 /* perform build. */ 1010 ret = rte_acl_build(config.acx, &cfg); 1011 1012 dump_verbose(DUMP_NONE, stdout, 1013 "rte_acl_build(%u) finished with %d\n", 1014 config.bld_categories, ret); 1015 1016 rte_acl_dump(config.acx); 1017 1018 if (ret != 0) 1019 rte_exit(ret, "failed to build search context\n"); 1020 } 1021 1022 static uint32_t 1023 search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg) 1024 { 1025 int ret; 1026 uint32_t i, j, k, n, r; 1027 const uint8_t *data[step], *v; 1028 uint32_t results[step * categories]; 1029 1030 v = config.traces; 1031 for (i = 0; i != config.used_traces; i += n) { 1032 1033 n = RTE_MIN(step, config.used_traces - i); 1034 1035 for (j = 0; j != n; j++) { 1036 data[j] = v; 1037 v += config.trace_sz; 1038 } 1039 1040 ret = rte_acl_classify(config.acx, data, results, 1041 n, categories); 1042 1043 if (ret != 0) 1044 rte_exit(ret, "classify for ipv%c_5tuples returns %d\n", 1045 config.ipv6 ? '6' : '4', ret); 1046 1047 for (r = 0, j = 0; j != n; j++) { 1048 for (k = 0; k != categories; k++, r++) { 1049 dump_verbose(DUMP_PKT, stdout, 1050 "ipv%c_5tuple: %u, category: %u, " 1051 "result: %u\n", 1052 config.ipv6 ? '6' : '4', 1053 i + j + 1, k, results[r] - 1); 1054 } 1055 1056 } 1057 } 1058 1059 dump_verbose(DUMP_SEARCH, stdout, 1060 "%s(%u, %u, %s) returns %u\n", __func__, 1061 categories, step, alg, i); 1062 return i; 1063 } 1064 1065 static int 1066 search_ip5tuples(__rte_unused void *arg) 1067 { 1068 uint64_t pkt, start, tm; 1069 uint32_t i, lcore; 1070 long double st; 1071 1072 lcore = rte_lcore_id(); 1073 start = rte_rdtsc_precise(); 1074 pkt = 0; 1075 1076 for (i = 0; i != config.iter_num; i++) { 1077 pkt += search_ip5tuples_once(config.run_categories, 1078 config.trace_step, config.alg.name); 1079 } 1080 1081 tm = rte_rdtsc_precise() - start; 1082 1083 st = (long double)tm / rte_get_timer_hz(); 1084 dump_verbose(DUMP_NONE, stdout, 1085 "%s @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %" 1086 PRIu32 " categories, %" PRIu64 " cycles (%.2Lf sec), " 1087 "%.2Lf cycles/pkt, %.2Lf pkt/sec\n", 1088 __func__, lcore, i, pkt, 1089 config.run_categories, tm, st, 1090 (pkt == 0) ? 0 : (long double)tm / pkt, pkt / st); 1091 1092 return 0; 1093 } 1094 1095 static unsigned long 1096 get_ulong_opt(const char *opt, const char *name, size_t min, size_t max) 1097 { 1098 unsigned long val; 1099 char *end; 1100 1101 errno = 0; 1102 val = strtoul(opt, &end, 0); 1103 if (errno != 0 || end[0] != 0 || val > max || val < min) 1104 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n", 1105 opt, name); 1106 return val; 1107 } 1108 1109 static void 1110 get_alg_opt(const char *opt, const char *name) 1111 { 1112 uint32_t i; 1113 1114 for (i = 0; i != RTE_DIM(acl_alg); i++) { 1115 if (strcmp(opt, acl_alg[i].name) == 0) { 1116 config.alg = acl_alg[i]; 1117 return; 1118 } 1119 } 1120 1121 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n", 1122 opt, name); 1123 } 1124 1125 static void 1126 get_ipv6_opt(const char *opt, const char *name) 1127 { 1128 uint32_t i; 1129 1130 static const struct { 1131 const char *name; 1132 uint32_t val; 1133 } ipv6_opt[] = { 1134 { 1135 .name = "4B", 1136 .val = IPV6_FRMT_U32, 1137 }, 1138 { 1139 .name = "8B", 1140 .val = IPV6_FRMT_U64, 1141 }, 1142 }; 1143 1144 for (i = 0; i != RTE_DIM(ipv6_opt); i++) { 1145 if (strcmp(opt, ipv6_opt[i].name) == 0) { 1146 config.ipv6 = ipv6_opt[i].val; 1147 return; 1148 } 1149 } 1150 1151 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n", 1152 opt, name); 1153 } 1154 1155 1156 static void 1157 print_usage(const char *prgname) 1158 { 1159 uint32_t i, n, rc; 1160 char buf[PATH_MAX]; 1161 1162 n = 0; 1163 buf[0] = 0; 1164 1165 for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) { 1166 rc = snprintf(buf + n, sizeof(buf) - n, "%s|", 1167 acl_alg[i].name); 1168 if (rc > sizeof(buf) - n) 1169 break; 1170 n += rc; 1171 } 1172 1173 strlcpy(buf + n, acl_alg[i].name, sizeof(buf) - n); 1174 1175 fprintf(stdout, 1176 PRINT_USAGE_START 1177 "--" OPT_RULE_FILE "=<rules set file>\n" 1178 "[--" OPT_TRACE_FILE "=<input traces file>]\n" 1179 "[--" OPT_RULE_NUM 1180 "=<maximum number of rules for ACL context>]\n" 1181 "[--" OPT_TRACE_NUM 1182 "=<number of traces to read binary file in>]\n" 1183 "[--" OPT_TRACE_STEP 1184 "=<number of traces to classify per one call>]\n" 1185 "[--" OPT_BLD_CATEGORIES 1186 "=<number of categories to build with>]\n" 1187 "[--" OPT_RUN_CATEGORIES 1188 "=<number of categories to run with> " 1189 "should be either 1 or multiple of %zu, " 1190 "but not greater then %u]\n" 1191 "[--" OPT_MAX_SIZE 1192 "=<size limit (in bytes) for runtime ACL structures> " 1193 "leave 0 for default behaviour]\n" 1194 "[--" OPT_ITER_NUM "=<number of iterations to perform>]\n" 1195 "[--" OPT_VERBOSE "=<verbose level>]\n" 1196 "[--" OPT_SEARCH_ALG "=%s]\n" 1197 "[--" OPT_IPV6 "(=4B | 8B) <IPv6 rules and trace files>]\n", 1198 prgname, RTE_ACL_RESULTS_MULTIPLIER, 1199 (uint32_t)RTE_ACL_MAX_CATEGORIES, 1200 buf); 1201 } 1202 1203 static void 1204 dump_config(FILE *f) 1205 { 1206 fprintf(f, "%s:\n", __func__); 1207 fprintf(f, "%s:%s\n", OPT_RULE_FILE, config.rule_file); 1208 fprintf(f, "%s:%s\n", OPT_TRACE_FILE, config.trace_file); 1209 fprintf(f, "%s:%u\n", OPT_RULE_NUM, config.nb_rules); 1210 fprintf(f, "%s:%u\n", OPT_TRACE_NUM, config.nb_traces); 1211 fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step); 1212 fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories); 1213 fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories); 1214 fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size); 1215 fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num); 1216 fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose); 1217 fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg, 1218 config.alg.name); 1219 fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6); 1220 } 1221 1222 static void 1223 check_config(void) 1224 { 1225 if (config.rule_file == NULL) { 1226 print_usage(config.prgname); 1227 rte_exit(-EINVAL, "mandatory option %s is not specified\n", 1228 OPT_RULE_FILE); 1229 } 1230 } 1231 1232 1233 static void 1234 get_input_opts(int argc, char **argv) 1235 { 1236 static struct option lgopts[] = { 1237 {OPT_RULE_FILE, 1, 0, 0}, 1238 {OPT_TRACE_FILE, 1, 0, 0}, 1239 {OPT_TRACE_NUM, 1, 0, 0}, 1240 {OPT_RULE_NUM, 1, 0, 0}, 1241 {OPT_MAX_SIZE, 1, 0, 0}, 1242 {OPT_TRACE_STEP, 1, 0, 0}, 1243 {OPT_BLD_CATEGORIES, 1, 0, 0}, 1244 {OPT_RUN_CATEGORIES, 1, 0, 0}, 1245 {OPT_ITER_NUM, 1, 0, 0}, 1246 {OPT_VERBOSE, 1, 0, 0}, 1247 {OPT_SEARCH_ALG, 1, 0, 0}, 1248 {OPT_IPV6, 2, 0, 0}, 1249 {NULL, 0, 0, 0} 1250 }; 1251 1252 int opt, opt_idx; 1253 1254 while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) { 1255 1256 if (opt != 0) { 1257 print_usage(config.prgname); 1258 rte_exit(-EINVAL, "unknown option: %c", opt); 1259 } 1260 1261 if (strcmp(lgopts[opt_idx].name, OPT_RULE_FILE) == 0) { 1262 config.rule_file = optarg; 1263 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) { 1264 config.trace_file = optarg; 1265 } else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) { 1266 config.nb_rules = get_ulong_opt(optarg, 1267 lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1); 1268 } else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) { 1269 config.max_size = get_ulong_opt(optarg, 1270 lgopts[opt_idx].name, 0, SIZE_MAX); 1271 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) { 1272 config.nb_traces = get_ulong_opt(optarg, 1273 lgopts[opt_idx].name, 1, UINT32_MAX); 1274 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) { 1275 config.trace_step = get_ulong_opt(optarg, 1276 lgopts[opt_idx].name, 1, TRACE_STEP_MAX); 1277 } else if (strcmp(lgopts[opt_idx].name, 1278 OPT_BLD_CATEGORIES) == 0) { 1279 config.bld_categories = get_ulong_opt(optarg, 1280 lgopts[opt_idx].name, 1, 1281 RTE_ACL_MAX_CATEGORIES); 1282 } else if (strcmp(lgopts[opt_idx].name, 1283 OPT_RUN_CATEGORIES) == 0) { 1284 config.run_categories = get_ulong_opt(optarg, 1285 lgopts[opt_idx].name, 1, 1286 RTE_ACL_MAX_CATEGORIES); 1287 } else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) { 1288 config.iter_num = get_ulong_opt(optarg, 1289 lgopts[opt_idx].name, 1, INT32_MAX); 1290 } else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) { 1291 config.verbose = get_ulong_opt(optarg, 1292 lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX); 1293 } else if (strcmp(lgopts[opt_idx].name, 1294 OPT_SEARCH_ALG) == 0) { 1295 get_alg_opt(optarg, lgopts[opt_idx].name); 1296 } else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) { 1297 config.ipv6 = IPV6_FRMT_U32; 1298 if (optarg != NULL) 1299 get_ipv6_opt(optarg, lgopts[opt_idx].name); 1300 } 1301 } 1302 config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) : 1303 sizeof(struct ipv4_5tuple); 1304 1305 } 1306 1307 int 1308 main(int argc, char **argv) 1309 { 1310 int ret; 1311 uint32_t lcore; 1312 1313 ret = rte_eal_init(argc, argv); 1314 if (ret < 0) 1315 rte_panic("Cannot init EAL\n"); 1316 1317 argc -= ret; 1318 argv += ret; 1319 1320 config.prgname = argv[0]; 1321 1322 get_input_opts(argc, argv); 1323 dump_config(stdout); 1324 check_config(); 1325 1326 acx_init(); 1327 1328 if (config.trace_file != NULL) 1329 tracef_init(); 1330 1331 RTE_LCORE_FOREACH_WORKER(lcore) 1332 rte_eal_remote_launch(search_ip5tuples, NULL, lcore); 1333 1334 search_ip5tuples(NULL); 1335 1336 rte_eal_mp_wait_lcore(); 1337 1338 rte_acl_free(config.acx); 1339 return 0; 1340 } 1341