1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2020 Mellanox Technologies, Ltd 3 * 4 * This file contain the application main file 5 * This application provides the user the ability to test the 6 * insertion rate for specific rte_flow rule under stress state ~4M rule/ 7 * 8 * Then it will also provide packet per second measurement after installing 9 * all rules, the user may send traffic to test the PPS that match the rules 10 * after all rules are installed, to check performance or functionality after 11 * the stress. 12 * 13 * The flows insertion will go for all ports first, then it will print the 14 * results, after that the application will go into forwarding packets mode 15 * it will start receiving traffic if any and then forwarding it back and 16 * gives packet per second measurement. 17 */ 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <stdint.h> 23 #include <inttypes.h> 24 #include <stdarg.h> 25 #include <errno.h> 26 #include <getopt.h> 27 #include <stdbool.h> 28 #include <sys/time.h> 29 #include <signal.h> 30 #include <unistd.h> 31 32 #include <rte_malloc.h> 33 #include <rte_mempool.h> 34 #include <rte_mbuf.h> 35 #include <rte_ethdev.h> 36 #include <rte_flow.h> 37 38 #include "config.h" 39 #include "flow_gen.h" 40 41 #define MAX_ITERATIONS 100 42 #define DEFAULT_RULES_COUNT 4000000 43 #define DEFAULT_RULES_BATCH 100000 44 #define DEFAULT_GROUP 0 45 46 struct rte_flow *flow; 47 static uint8_t flow_group; 48 49 static uint64_t encap_data; 50 static uint64_t decap_data; 51 52 static uint64_t flow_items[MAX_ITEMS_NUM]; 53 static uint64_t flow_actions[MAX_ACTIONS_NUM]; 54 static uint64_t flow_attrs[MAX_ATTRS_NUM]; 55 static uint8_t items_idx, actions_idx, attrs_idx; 56 57 static uint64_t ports_mask; 58 static volatile bool force_quit; 59 static bool dump_iterations; 60 static bool delete_flag; 61 static bool dump_socket_mem_flag; 62 static bool enable_fwd; 63 64 static struct rte_mempool *mbuf_mp; 65 static uint32_t nb_lcores; 66 static uint32_t rules_count; 67 static uint32_t rules_batch; 68 static uint32_t hairpin_queues_num; /* total hairpin q number - default: 0 */ 69 static uint32_t nb_lcores; 70 71 #define MAX_PKT_BURST 32 72 #define LCORE_MODE_PKT 1 73 #define LCORE_MODE_STATS 2 74 #define MAX_STREAMS 64 75 #define MAX_LCORES 64 76 77 struct stream { 78 int tx_port; 79 int tx_queue; 80 int rx_port; 81 int rx_queue; 82 }; 83 84 struct lcore_info { 85 int mode; 86 int streams_nb; 87 struct stream streams[MAX_STREAMS]; 88 /* stats */ 89 uint64_t tx_pkts; 90 uint64_t tx_drops; 91 uint64_t rx_pkts; 92 struct rte_mbuf *pkts[MAX_PKT_BURST]; 93 } __rte_cache_aligned; 94 95 static struct lcore_info lcore_infos[MAX_LCORES]; 96 97 static void 98 usage(char *progname) 99 { 100 printf("\nusage: %s\n", progname); 101 printf("\nControl configurations:\n"); 102 printf(" --rules-count=N: to set the number of needed" 103 " rules to insert, default is %d\n", DEFAULT_RULES_COUNT); 104 printf(" --rules-batch=N: set number of batched rules," 105 " default is %d\n", DEFAULT_RULES_BATCH); 106 printf(" --dump-iterations: To print rates for each" 107 " iteration\n"); 108 printf(" --deletion-rate: Enable deletion rate" 109 " calculations\n"); 110 printf(" --dump-socket-mem: To dump all socket memory\n"); 111 printf(" --enable-fwd: To enable packets forwarding" 112 " after insertion\n"); 113 printf(" --portmask=N: hexadecimal bitmask of ports used\n"); 114 115 printf("To set flow attributes:\n"); 116 printf(" --ingress: set ingress attribute in flows\n"); 117 printf(" --egress: set egress attribute in flows\n"); 118 printf(" --transfer: set transfer attribute in flows\n"); 119 printf(" --group=N: set group for all flows," 120 " default is %d\n", DEFAULT_GROUP); 121 122 printf("To set flow items:\n"); 123 printf(" --ether: add ether layer in flow items\n"); 124 printf(" --vlan: add vlan layer in flow items\n"); 125 printf(" --ipv4: add ipv4 layer in flow items\n"); 126 printf(" --ipv6: add ipv6 layer in flow items\n"); 127 printf(" --tcp: add tcp layer in flow items\n"); 128 printf(" --udp: add udp layer in flow items\n"); 129 printf(" --vxlan: add vxlan layer in flow items\n"); 130 printf(" --vxlan-gpe: add vxlan-gpe layer in flow items\n"); 131 printf(" --gre: add gre layer in flow items\n"); 132 printf(" --geneve: add geneve layer in flow items\n"); 133 printf(" --gtp: add gtp layer in flow items\n"); 134 printf(" --meta: add meta layer in flow items\n"); 135 printf(" --tag: add tag layer in flow items\n"); 136 printf(" --icmpv4: add icmpv4 layer in flow items\n"); 137 printf(" --icmpv6: add icmpv6 layer in flow items\n"); 138 139 printf("To set flow actions:\n"); 140 printf(" --port-id: add port-id action in flow actions\n"); 141 printf(" --rss: add rss action in flow actions\n"); 142 printf(" --queue: add queue action in flow actions\n"); 143 printf(" --jump: add jump action in flow actions\n"); 144 printf(" --mark: add mark action in flow actions\n"); 145 printf(" --count: add count action in flow actions\n"); 146 printf(" --set-meta: add set meta action in flow actions\n"); 147 printf(" --set-tag: add set tag action in flow actions\n"); 148 printf(" --drop: add drop action in flow actions\n"); 149 printf(" --hairpin-queue=N: add hairpin-queue action in flow actions\n"); 150 printf(" --hairpin-rss=N: add hairpin-rss action in flow actions\n"); 151 printf(" --set-src-mac: add set src mac action to flow actions\n" 152 "Src mac to be set is random each flow\n"); 153 printf(" --set-dst-mac: add set dst mac action to flow actions\n" 154 "Dst mac to be set is random each flow\n"); 155 printf(" --set-src-ipv4: add set src ipv4 action to flow actions\n" 156 "Src ipv4 to be set is random each flow\n"); 157 printf(" --set-dst-ipv4 add set dst ipv4 action to flow actions\n" 158 "Dst ipv4 to be set is random each flow\n"); 159 printf(" --set-src-ipv6: add set src ipv6 action to flow actions\n" 160 "Src ipv6 to be set is random each flow\n"); 161 printf(" --set-dst-ipv6: add set dst ipv6 action to flow actions\n" 162 "Dst ipv6 to be set is random each flow\n"); 163 printf(" --set-src-tp: add set src tp action to flow actions\n" 164 "Src tp to be set is random each flow\n"); 165 printf(" --set-dst-tp: add set dst tp action to flow actions\n" 166 "Dst tp to be set is random each flow\n"); 167 printf(" --inc-tcp-ack: add inc tcp ack action to flow actions\n" 168 "tcp ack will be increments by 1\n"); 169 printf(" --dec-tcp-ack: add dec tcp ack action to flow actions\n" 170 "tcp ack will be decrements by 1\n"); 171 printf(" --inc-tcp-seq: add inc tcp seq action to flow actions\n" 172 "tcp seq will be increments by 1\n"); 173 printf(" --dec-tcp-seq: add dec tcp seq action to flow actions\n" 174 "tcp seq will be decrements by 1\n"); 175 printf(" --set-ttl: add set ttl action to flow actions\n" 176 "L3 ttl to be set is random each flow\n"); 177 printf(" --dec-ttl: add dec ttl action to flow actions\n" 178 "L3 ttl will be decrements by 1\n"); 179 printf(" --set-ipv4-dscp: add set ipv4 dscp action to flow actions\n" 180 "ipv4 dscp value to be set is random each flow\n"); 181 printf(" --set-ipv6-dscp: add set ipv6 dscp action to flow actions\n" 182 "ipv6 dscp value to be set is random each flow\n"); 183 printf(" --flag: add flag action to flow actions\n"); 184 printf(" --raw-encap=<data>: add raw encap action to flow actions\n" 185 "Data is the data needed to be encaped\n" 186 "Example: raw-encap=ether,ipv4,udp,vxlan\n"); 187 printf(" --raw-decap=<data>: add raw decap action to flow actions\n" 188 "Data is the data needed to be decaped\n" 189 "Example: raw-decap=ether,ipv4,udp,vxlan\n"); 190 printf(" --vxlan-encap: add vxlan-encap action to flow actions\n" 191 "Encapped data is fixed with pattern: ether,ipv4,udp,vxlan\n" 192 "With fixed values\n"); 193 printf(" --vxlan-decap: add vxlan_decap action to flow actions\n"); 194 } 195 196 static void 197 args_parse(int argc, char **argv) 198 { 199 uint64_t pm; 200 char **argvopt; 201 char *token; 202 char *end; 203 int n, opt; 204 int opt_idx; 205 size_t i; 206 207 static const struct option_dict { 208 const char *str; 209 const uint64_t mask; 210 uint64_t *map; 211 uint8_t *map_idx; 212 213 } flow_options[] = { 214 { 215 .str = "ether", 216 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH), 217 .map = &flow_items[0], 218 .map_idx = &items_idx 219 }, 220 { 221 .str = "ipv4", 222 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV4), 223 .map = &flow_items[0], 224 .map_idx = &items_idx 225 }, 226 { 227 .str = "ipv6", 228 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV6), 229 .map = &flow_items[0], 230 .map_idx = &items_idx 231 }, 232 { 233 .str = "vlan", 234 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VLAN), 235 .map = &flow_items[0], 236 .map_idx = &items_idx 237 }, 238 { 239 .str = "tcp", 240 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TCP), 241 .map = &flow_items[0], 242 .map_idx = &items_idx 243 }, 244 { 245 .str = "udp", 246 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_UDP), 247 .map = &flow_items[0], 248 .map_idx = &items_idx 249 }, 250 { 251 .str = "vxlan", 252 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN), 253 .map = &flow_items[0], 254 .map_idx = &items_idx 255 }, 256 { 257 .str = "vxlan-gpe", 258 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN_GPE), 259 .map = &flow_items[0], 260 .map_idx = &items_idx 261 }, 262 { 263 .str = "gre", 264 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GRE), 265 .map = &flow_items[0], 266 .map_idx = &items_idx 267 }, 268 { 269 .str = "geneve", 270 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GENEVE), 271 .map = &flow_items[0], 272 .map_idx = &items_idx 273 }, 274 { 275 .str = "gtp", 276 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GTP), 277 .map = &flow_items[0], 278 .map_idx = &items_idx 279 }, 280 { 281 .str = "meta", 282 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_META), 283 .map = &flow_items[0], 284 .map_idx = &items_idx 285 }, 286 { 287 .str = "tag", 288 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TAG), 289 .map = &flow_items[0], 290 .map_idx = &items_idx 291 }, 292 { 293 .str = "icmpv4", 294 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ICMP), 295 .map = &flow_items[0], 296 .map_idx = &items_idx 297 }, 298 { 299 .str = "icmpv6", 300 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ICMP6), 301 .map = &flow_items[0], 302 .map_idx = &items_idx 303 }, 304 { 305 .str = "ingress", 306 .mask = INGRESS, 307 .map = &flow_attrs[0], 308 .map_idx = &attrs_idx 309 }, 310 { 311 .str = "egress", 312 .mask = EGRESS, 313 .map = &flow_attrs[0], 314 .map_idx = &attrs_idx 315 }, 316 { 317 .str = "transfer", 318 .mask = TRANSFER, 319 .map = &flow_attrs[0], 320 .map_idx = &attrs_idx 321 }, 322 { 323 .str = "port-id", 324 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_PORT_ID), 325 .map = &flow_actions[0], 326 .map_idx = &actions_idx 327 }, 328 { 329 .str = "rss", 330 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_RSS), 331 .map = &flow_actions[0], 332 .map_idx = &actions_idx 333 }, 334 { 335 .str = "queue", 336 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_QUEUE), 337 .map = &flow_actions[0], 338 .map_idx = &actions_idx 339 }, 340 { 341 .str = "jump", 342 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_JUMP), 343 .map = &flow_actions[0], 344 .map_idx = &actions_idx 345 }, 346 { 347 .str = "mark", 348 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_MARK), 349 .map = &flow_actions[0], 350 .map_idx = &actions_idx 351 }, 352 { 353 .str = "count", 354 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_COUNT), 355 .map = &flow_actions[0], 356 .map_idx = &actions_idx 357 }, 358 { 359 .str = "set-meta", 360 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_META), 361 .map = &flow_actions[0], 362 .map_idx = &actions_idx 363 }, 364 { 365 .str = "set-tag", 366 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_TAG), 367 .map = &flow_actions[0], 368 .map_idx = &actions_idx 369 }, 370 { 371 .str = "drop", 372 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_DROP), 373 .map = &flow_actions[0], 374 .map_idx = &actions_idx 375 }, 376 { 377 .str = "set-src-mac", 378 .mask = FLOW_ACTION_MASK( 379 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC 380 ), 381 .map = &flow_actions[0], 382 .map_idx = &actions_idx 383 }, 384 { 385 .str = "set-dst-mac", 386 .mask = FLOW_ACTION_MASK( 387 RTE_FLOW_ACTION_TYPE_SET_MAC_DST 388 ), 389 .map = &flow_actions[0], 390 .map_idx = &actions_idx 391 }, 392 { 393 .str = "set-src-ipv4", 394 .mask = FLOW_ACTION_MASK( 395 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC 396 ), 397 .map = &flow_actions[0], 398 .map_idx = &actions_idx 399 }, 400 { 401 .str = "set-dst-ipv4", 402 .mask = FLOW_ACTION_MASK( 403 RTE_FLOW_ACTION_TYPE_SET_IPV4_DST 404 ), 405 .map = &flow_actions[0], 406 .map_idx = &actions_idx 407 }, 408 { 409 .str = "set-src-ipv6", 410 .mask = FLOW_ACTION_MASK( 411 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC 412 ), 413 .map = &flow_actions[0], 414 .map_idx = &actions_idx 415 }, 416 { 417 .str = "set-dst-ipv6", 418 .mask = FLOW_ACTION_MASK( 419 RTE_FLOW_ACTION_TYPE_SET_IPV6_DST 420 ), 421 .map = &flow_actions[0], 422 .map_idx = &actions_idx 423 }, 424 { 425 .str = "set-src-tp", 426 .mask = FLOW_ACTION_MASK( 427 RTE_FLOW_ACTION_TYPE_SET_TP_SRC 428 ), 429 .map = &flow_actions[0], 430 .map_idx = &actions_idx 431 }, 432 { 433 .str = "set-dst-tp", 434 .mask = FLOW_ACTION_MASK( 435 RTE_FLOW_ACTION_TYPE_SET_TP_DST 436 ), 437 .map = &flow_actions[0], 438 .map_idx = &actions_idx 439 }, 440 { 441 .str = "inc-tcp-ack", 442 .mask = FLOW_ACTION_MASK( 443 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK 444 ), 445 .map = &flow_actions[0], 446 .map_idx = &actions_idx 447 }, 448 { 449 .str = "dec-tcp-ack", 450 .mask = FLOW_ACTION_MASK( 451 RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK 452 ), 453 .map = &flow_actions[0], 454 .map_idx = &actions_idx 455 }, 456 { 457 .str = "inc-tcp-seq", 458 .mask = FLOW_ACTION_MASK( 459 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ 460 ), 461 .map = &flow_actions[0], 462 .map_idx = &actions_idx 463 }, 464 { 465 .str = "dec-tcp-seq", 466 .mask = FLOW_ACTION_MASK( 467 RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ 468 ), 469 .map = &flow_actions[0], 470 .map_idx = &actions_idx 471 }, 472 { 473 .str = "set-ttl", 474 .mask = FLOW_ACTION_MASK( 475 RTE_FLOW_ACTION_TYPE_SET_TTL 476 ), 477 .map = &flow_actions[0], 478 .map_idx = &actions_idx 479 }, 480 { 481 .str = "dec-ttl", 482 .mask = FLOW_ACTION_MASK( 483 RTE_FLOW_ACTION_TYPE_DEC_TTL 484 ), 485 .map = &flow_actions[0], 486 .map_idx = &actions_idx 487 }, 488 { 489 .str = "set-ipv4-dscp", 490 .mask = FLOW_ACTION_MASK( 491 RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP 492 ), 493 .map = &flow_actions[0], 494 .map_idx = &actions_idx 495 }, 496 { 497 .str = "set-ipv6-dscp", 498 .mask = FLOW_ACTION_MASK( 499 RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP 500 ), 501 .map = &flow_actions[0], 502 .map_idx = &actions_idx 503 }, 504 { 505 .str = "flag", 506 .mask = FLOW_ACTION_MASK( 507 RTE_FLOW_ACTION_TYPE_FLAG 508 ), 509 .map = &flow_actions[0], 510 .map_idx = &actions_idx 511 }, 512 { 513 .str = "vxlan-encap", 514 .mask = FLOW_ACTION_MASK( 515 RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP 516 ), 517 .map = &flow_actions[0], 518 .map_idx = &actions_idx 519 }, 520 { 521 .str = "vxlan-decap", 522 .mask = FLOW_ACTION_MASK( 523 RTE_FLOW_ACTION_TYPE_VXLAN_DECAP 524 ), 525 .map = &flow_actions[0], 526 .map_idx = &actions_idx 527 }, 528 }; 529 530 static const struct option lgopts[] = { 531 /* Control */ 532 { "help", 0, 0, 0 }, 533 { "rules-count", 1, 0, 0 }, 534 { "rules-batch", 1, 0, 0 }, 535 { "dump-iterations", 0, 0, 0 }, 536 { "deletion-rate", 0, 0, 0 }, 537 { "dump-socket-mem", 0, 0, 0 }, 538 { "enable-fwd", 0, 0, 0 }, 539 { "portmask", 1, 0, 0 }, 540 /* Attributes */ 541 { "ingress", 0, 0, 0 }, 542 { "egress", 0, 0, 0 }, 543 { "transfer", 0, 0, 0 }, 544 { "group", 1, 0, 0 }, 545 /* Items */ 546 { "ether", 0, 0, 0 }, 547 { "vlan", 0, 0, 0 }, 548 { "ipv4", 0, 0, 0 }, 549 { "ipv6", 0, 0, 0 }, 550 { "tcp", 0, 0, 0 }, 551 { "udp", 0, 0, 0 }, 552 { "vxlan", 0, 0, 0 }, 553 { "vxlan-gpe", 0, 0, 0 }, 554 { "gre", 0, 0, 0 }, 555 { "geneve", 0, 0, 0 }, 556 { "gtp", 0, 0, 0 }, 557 { "meta", 0, 0, 0 }, 558 { "tag", 0, 0, 0 }, 559 { "icmpv4", 0, 0, 0 }, 560 { "icmpv6", 0, 0, 0 }, 561 /* Actions */ 562 { "port-id", 0, 0, 0 }, 563 { "rss", 0, 0, 0 }, 564 { "queue", 0, 0, 0 }, 565 { "jump", 0, 0, 0 }, 566 { "mark", 0, 0, 0 }, 567 { "count", 0, 0, 0 }, 568 { "set-meta", 0, 0, 0 }, 569 { "set-tag", 0, 0, 0 }, 570 { "drop", 0, 0, 0 }, 571 { "hairpin-queue", 1, 0, 0 }, 572 { "hairpin-rss", 1, 0, 0 }, 573 { "set-src-mac", 0, 0, 0 }, 574 { "set-dst-mac", 0, 0, 0 }, 575 { "set-src-ipv4", 0, 0, 0 }, 576 { "set-dst-ipv4", 0, 0, 0 }, 577 { "set-src-ipv6", 0, 0, 0 }, 578 { "set-dst-ipv6", 0, 0, 0 }, 579 { "set-src-tp", 0, 0, 0 }, 580 { "set-dst-tp", 0, 0, 0 }, 581 { "inc-tcp-ack", 0, 0, 0 }, 582 { "dec-tcp-ack", 0, 0, 0 }, 583 { "inc-tcp-seq", 0, 0, 0 }, 584 { "dec-tcp-seq", 0, 0, 0 }, 585 { "set-ttl", 0, 0, 0 }, 586 { "dec-ttl", 0, 0, 0 }, 587 { "set-ipv4-dscp", 0, 0, 0 }, 588 { "set-ipv6-dscp", 0, 0, 0 }, 589 { "flag", 0, 0, 0 }, 590 { "raw-encap", 1, 0, 0 }, 591 { "raw-decap", 1, 0, 0 }, 592 { "vxlan-encap", 0, 0, 0 }, 593 { "vxlan-decap", 0, 0, 0 }, 594 }; 595 596 RTE_ETH_FOREACH_DEV(i) 597 ports_mask |= 1 << i; 598 599 hairpin_queues_num = 0; 600 argvopt = argv; 601 602 printf(":: Flow -> "); 603 while ((opt = getopt_long(argc, argvopt, "", 604 lgopts, &opt_idx)) != EOF) { 605 switch (opt) { 606 case 0: 607 if (strcmp(lgopts[opt_idx].name, "help") == 0) { 608 usage(argv[0]); 609 rte_exit(EXIT_SUCCESS, "Displayed help\n"); 610 } 611 612 if (strcmp(lgopts[opt_idx].name, "group") == 0) { 613 n = atoi(optarg); 614 if (n >= 0) 615 flow_group = n; 616 else 617 rte_exit(EXIT_SUCCESS, 618 "flow group should be >= 0\n"); 619 printf("group %d / ", flow_group); 620 } 621 622 for (i = 0; i < RTE_DIM(flow_options); i++) 623 if (strcmp(lgopts[opt_idx].name, 624 flow_options[i].str) == 0) { 625 flow_options[i].map[ 626 (*flow_options[i].map_idx)++] = 627 flow_options[i].mask; 628 printf("%s / ", flow_options[i].str); 629 } 630 631 if (strcmp(lgopts[opt_idx].name, 632 "hairpin-rss") == 0) { 633 n = atoi(optarg); 634 if (n > 0) 635 hairpin_queues_num = n; 636 else 637 rte_exit(EXIT_SUCCESS, 638 "Hairpin queues should be > 0\n"); 639 640 flow_actions[actions_idx++] = 641 HAIRPIN_RSS_ACTION; 642 printf("hairpin-rss / "); 643 } 644 if (strcmp(lgopts[opt_idx].name, 645 "hairpin-queue") == 0) { 646 n = atoi(optarg); 647 if (n > 0) 648 hairpin_queues_num = n; 649 else 650 rte_exit(EXIT_SUCCESS, 651 "Hairpin queues should be > 0\n"); 652 653 flow_actions[actions_idx++] = 654 HAIRPIN_QUEUE_ACTION; 655 printf("hairpin-queue / "); 656 } 657 658 if (strcmp(lgopts[opt_idx].name, "raw-encap") == 0) { 659 printf("raw-encap "); 660 flow_actions[actions_idx++] = 661 FLOW_ITEM_MASK( 662 RTE_FLOW_ACTION_TYPE_RAW_ENCAP 663 ); 664 665 token = strtok(optarg, ","); 666 while (token != NULL) { 667 for (i = 0; i < RTE_DIM(flow_options); i++) { 668 if (strcmp(flow_options[i].str, token) == 0) { 669 printf("%s,", token); 670 encap_data |= flow_options[i].mask; 671 break; 672 } 673 /* Reached last item with no match */ 674 if (i == (RTE_DIM(flow_options) - 1)) { 675 fprintf(stderr, "Invalid encap item: %s\n", token); 676 usage(argv[0]); 677 rte_exit(EXIT_SUCCESS, "Invalid encap item\n"); 678 } 679 } 680 token = strtok(NULL, ","); 681 } 682 printf(" / "); 683 } 684 if (strcmp(lgopts[opt_idx].name, "raw-decap") == 0) { 685 printf("raw-decap "); 686 flow_actions[actions_idx++] = 687 FLOW_ITEM_MASK( 688 RTE_FLOW_ACTION_TYPE_RAW_DECAP 689 ); 690 691 token = strtok(optarg, ","); 692 while (token != NULL) { 693 for (i = 0; i < RTE_DIM(flow_options); i++) { 694 if (strcmp(flow_options[i].str, token) == 0) { 695 printf("%s,", token); 696 encap_data |= flow_options[i].mask; 697 break; 698 } 699 /* Reached last item with no match */ 700 if (i == (RTE_DIM(flow_options) - 1)) { 701 fprintf(stderr, "Invalid decap item: %s\n", token); 702 usage(argv[0]); 703 rte_exit(EXIT_SUCCESS, "Invalid decap item\n"); 704 } 705 } 706 token = strtok(NULL, ","); 707 } 708 printf(" / "); 709 } 710 /* Control */ 711 if (strcmp(lgopts[opt_idx].name, 712 "rules-batch") == 0) { 713 n = atoi(optarg); 714 if (n >= DEFAULT_RULES_BATCH) 715 rules_batch = n; 716 else { 717 printf("\n\nrules_batch should be >= %d\n", 718 DEFAULT_RULES_BATCH); 719 rte_exit(EXIT_SUCCESS, " "); 720 } 721 } 722 if (strcmp(lgopts[opt_idx].name, 723 "rules-count") == 0) { 724 n = atoi(optarg); 725 if (n >= (int) rules_batch) 726 rules_count = n; 727 else { 728 printf("\n\nrules_count should be >= %d\n", 729 rules_batch); 730 } 731 } 732 if (strcmp(lgopts[opt_idx].name, 733 "dump-iterations") == 0) 734 dump_iterations = true; 735 if (strcmp(lgopts[opt_idx].name, 736 "deletion-rate") == 0) 737 delete_flag = true; 738 if (strcmp(lgopts[opt_idx].name, 739 "dump-socket-mem") == 0) 740 dump_socket_mem_flag = true; 741 if (strcmp(lgopts[opt_idx].name, 742 "enable-fwd") == 0) 743 enable_fwd = true; 744 if (strcmp(lgopts[opt_idx].name, 745 "portmask") == 0) { 746 /* parse hexadecimal string */ 747 end = NULL; 748 pm = strtoull(optarg, &end, 16); 749 if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0')) 750 rte_exit(EXIT_FAILURE, "Invalid fwd port mask\n"); 751 ports_mask = pm; 752 } 753 break; 754 default: 755 fprintf(stderr, "Invalid option: %s\n", argv[optind]); 756 usage(argv[0]); 757 rte_exit(EXIT_SUCCESS, "Invalid option\n"); 758 break; 759 } 760 } 761 printf("end_flow\n"); 762 } 763 764 /* Dump the socket memory statistics on console */ 765 static size_t 766 dump_socket_mem(FILE *f) 767 { 768 struct rte_malloc_socket_stats socket_stats; 769 unsigned int i = 0; 770 size_t total = 0; 771 size_t alloc = 0; 772 size_t free = 0; 773 unsigned int n_alloc = 0; 774 unsigned int n_free = 0; 775 bool active_nodes = false; 776 777 778 for (i = 0; i < RTE_MAX_NUMA_NODES; i++) { 779 if (rte_malloc_get_socket_stats(i, &socket_stats) || 780 !socket_stats.heap_totalsz_bytes) 781 continue; 782 active_nodes = true; 783 total += socket_stats.heap_totalsz_bytes; 784 alloc += socket_stats.heap_allocsz_bytes; 785 free += socket_stats.heap_freesz_bytes; 786 n_alloc += socket_stats.alloc_count; 787 n_free += socket_stats.free_count; 788 if (dump_socket_mem_flag) { 789 fprintf(f, "::::::::::::::::::::::::::::::::::::::::"); 790 fprintf(f, 791 "\nSocket %u:\nsize(M) total: %.6lf\nalloc:" 792 " %.6lf(%.3lf%%)\nfree: %.6lf" 793 "\nmax: %.6lf" 794 "\ncount alloc: %u\nfree: %u\n", 795 i, 796 socket_stats.heap_totalsz_bytes / 1.0e6, 797 socket_stats.heap_allocsz_bytes / 1.0e6, 798 (double)socket_stats.heap_allocsz_bytes * 100 / 799 (double)socket_stats.heap_totalsz_bytes, 800 socket_stats.heap_freesz_bytes / 1.0e6, 801 socket_stats.greatest_free_size / 1.0e6, 802 socket_stats.alloc_count, 803 socket_stats.free_count); 804 fprintf(f, "::::::::::::::::::::::::::::::::::::::::"); 805 } 806 } 807 if (dump_socket_mem_flag && active_nodes) { 808 fprintf(f, 809 "\nTotal: size(M)\ntotal: %.6lf" 810 "\nalloc: %.6lf(%.3lf%%)\nfree: %.6lf" 811 "\ncount alloc: %u\nfree: %u\n", 812 total / 1.0e6, alloc / 1.0e6, 813 (double)alloc * 100 / (double)total, free / 1.0e6, 814 n_alloc, n_free); 815 fprintf(f, "::::::::::::::::::::::::::::::::::::::::\n"); 816 } 817 return alloc; 818 } 819 820 static void 821 print_flow_error(struct rte_flow_error error) 822 { 823 printf("Flow can't be created %d message: %s\n", 824 error.type, 825 error.message ? error.message : "(no stated reason)"); 826 } 827 828 static inline void 829 destroy_flows(int port_id, struct rte_flow **flow_list) 830 { 831 struct rte_flow_error error; 832 clock_t start_iter, end_iter; 833 double cpu_time_used = 0; 834 double flows_rate; 835 double cpu_time_per_iter[MAX_ITERATIONS]; 836 double delta; 837 uint32_t i; 838 int iter_id; 839 840 for (i = 0; i < MAX_ITERATIONS; i++) 841 cpu_time_per_iter[i] = -1; 842 843 if (rules_batch > rules_count) 844 rules_batch = rules_count; 845 846 /* Deletion Rate */ 847 printf("Flows Deletion on port = %d\n", port_id); 848 start_iter = clock(); 849 for (i = 0; i < rules_count; i++) { 850 if (flow_list[i] == 0) 851 break; 852 853 memset(&error, 0x33, sizeof(error)); 854 if (rte_flow_destroy(port_id, flow_list[i], &error)) { 855 print_flow_error(error); 856 rte_exit(EXIT_FAILURE, "Error in deleting flow"); 857 } 858 859 if (i && !((i + 1) % rules_batch)) { 860 /* Save the deletion rate of each iter */ 861 end_iter = clock(); 862 delta = (double) (end_iter - start_iter); 863 iter_id = ((i + 1) / rules_batch) - 1; 864 cpu_time_per_iter[iter_id] = 865 delta / CLOCKS_PER_SEC; 866 cpu_time_used += cpu_time_per_iter[iter_id]; 867 start_iter = clock(); 868 } 869 } 870 871 /* Deletion rate per iteration */ 872 if (dump_iterations) 873 for (i = 0; i < MAX_ITERATIONS; i++) { 874 if (cpu_time_per_iter[i] == -1) 875 continue; 876 delta = (double)(rules_batch / 877 cpu_time_per_iter[i]); 878 flows_rate = delta / 1000; 879 printf(":: Iteration #%d: %d flows " 880 "in %f sec[ Rate = %f K/Sec ]\n", 881 i, rules_batch, 882 cpu_time_per_iter[i], flows_rate); 883 } 884 885 /* Deletion rate for all flows */ 886 flows_rate = ((double) (rules_count / cpu_time_used) / 1000); 887 printf("\n:: Total flow deletion rate -> %f K/Sec\n", 888 flows_rate); 889 printf(":: The time for deleting %d in flows %f seconds\n", 890 rules_count, cpu_time_used); 891 } 892 893 static inline void 894 flows_handler(void) 895 { 896 struct rte_flow **flow_list; 897 struct rte_flow_error error; 898 clock_t start_iter, end_iter; 899 double cpu_time_used; 900 double flows_rate; 901 double cpu_time_per_iter[MAX_ITERATIONS]; 902 double delta; 903 uint16_t nr_ports; 904 uint32_t i; 905 int port_id; 906 int iter_id; 907 uint32_t flow_index; 908 uint64_t global_items[MAX_ITEMS_NUM] = { 0 }; 909 uint64_t global_actions[MAX_ACTIONS_NUM] = { 0 }; 910 911 global_items[0] = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH); 912 global_actions[0] = FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP); 913 914 nr_ports = rte_eth_dev_count_avail(); 915 916 for (i = 0; i < MAX_ITERATIONS; i++) 917 cpu_time_per_iter[i] = -1; 918 919 if (rules_batch > rules_count) 920 rules_batch = rules_count; 921 922 printf(":: Flows Count per port: %d\n", rules_count); 923 924 flow_list = rte_zmalloc("flow_list", 925 (sizeof(struct rte_flow *) * rules_count) + 1, 0); 926 if (flow_list == NULL) 927 rte_exit(EXIT_FAILURE, "No Memory available!"); 928 929 for (port_id = 0; port_id < nr_ports; port_id++) { 930 /* If port outside portmask */ 931 if (!((ports_mask >> port_id) & 0x1)) 932 continue; 933 cpu_time_used = 0; 934 flow_index = 0; 935 if (flow_group > 0) { 936 /* 937 * Create global rule to jump into flow_group, 938 * this way the app will avoid the default rules. 939 * 940 * Global rule: 941 * group 0 eth / end actions jump group <flow_group> 942 * 943 */ 944 flow = generate_flow(port_id, 0, flow_attrs, 945 global_items, global_actions, 946 flow_group, 0, 0, 0, 0, &error); 947 948 if (flow == NULL) { 949 print_flow_error(error); 950 rte_exit(EXIT_FAILURE, "error in creating flow"); 951 } 952 flow_list[flow_index++] = flow; 953 } 954 955 /* Insertion Rate */ 956 printf("Flows insertion on port = %d\n", port_id); 957 start_iter = clock(); 958 for (i = 0; i < rules_count; i++) { 959 flow = generate_flow(port_id, flow_group, 960 flow_attrs, flow_items, flow_actions, 961 JUMP_ACTION_TABLE, i, 962 hairpin_queues_num, 963 encap_data, decap_data, 964 &error); 965 966 if (force_quit) 967 i = rules_count; 968 969 if (!flow) { 970 print_flow_error(error); 971 rte_exit(EXIT_FAILURE, "error in creating flow"); 972 } 973 974 flow_list[flow_index++] = flow; 975 976 if (i && !((i + 1) % rules_batch)) { 977 /* Save the insertion rate of each iter */ 978 end_iter = clock(); 979 delta = (double) (end_iter - start_iter); 980 iter_id = ((i + 1) / rules_batch) - 1; 981 cpu_time_per_iter[iter_id] = 982 delta / CLOCKS_PER_SEC; 983 cpu_time_used += cpu_time_per_iter[iter_id]; 984 start_iter = clock(); 985 } 986 } 987 988 /* Iteration rate per iteration */ 989 if (dump_iterations) 990 for (i = 0; i < MAX_ITERATIONS; i++) { 991 if (cpu_time_per_iter[i] == -1) 992 continue; 993 delta = (double)(rules_batch / 994 cpu_time_per_iter[i]); 995 flows_rate = delta / 1000; 996 printf(":: Iteration #%d: %d flows " 997 "in %f sec[ Rate = %f K/Sec ]\n", 998 i, rules_batch, 999 cpu_time_per_iter[i], flows_rate); 1000 } 1001 1002 /* Insertion rate for all flows */ 1003 flows_rate = ((double) (rules_count / cpu_time_used) / 1000); 1004 printf("\n:: Total flow insertion rate -> %f K/Sec\n", 1005 flows_rate); 1006 printf(":: The time for creating %d in flows %f seconds\n", 1007 rules_count, cpu_time_used); 1008 1009 if (delete_flag) 1010 destroy_flows(port_id, flow_list); 1011 } 1012 } 1013 1014 static void 1015 signal_handler(int signum) 1016 { 1017 if (signum == SIGINT || signum == SIGTERM) { 1018 printf("\n\nSignal %d received, preparing to exit...\n", 1019 signum); 1020 printf("Error: Stats are wrong due to sudden signal!\n\n"); 1021 force_quit = true; 1022 } 1023 } 1024 1025 static inline uint16_t 1026 do_rx(struct lcore_info *li, uint16_t rx_port, uint16_t rx_queue) 1027 { 1028 uint16_t cnt = 0; 1029 cnt = rte_eth_rx_burst(rx_port, rx_queue, li->pkts, MAX_PKT_BURST); 1030 li->rx_pkts += cnt; 1031 return cnt; 1032 } 1033 1034 static inline void 1035 do_tx(struct lcore_info *li, uint16_t cnt, uint16_t tx_port, 1036 uint16_t tx_queue) 1037 { 1038 uint16_t nr_tx = 0; 1039 uint16_t i; 1040 1041 nr_tx = rte_eth_tx_burst(tx_port, tx_queue, li->pkts, cnt); 1042 li->tx_pkts += nr_tx; 1043 li->tx_drops += cnt - nr_tx; 1044 1045 for (i = nr_tx; i < cnt; i++) 1046 rte_pktmbuf_free(li->pkts[i]); 1047 } 1048 1049 /* 1050 * Method to convert numbers into pretty numbers that easy 1051 * to read. The design here is to add comma after each three 1052 * digits and set all of this inside buffer. 1053 * 1054 * For example if n = 1799321, the output will be 1055 * 1,799,321 after this method which is easier to read. 1056 */ 1057 static char * 1058 pretty_number(uint64_t n, char *buf) 1059 { 1060 char p[6][4]; 1061 int i = 0; 1062 int off = 0; 1063 1064 while (n > 1000) { 1065 sprintf(p[i], "%03d", (int)(n % 1000)); 1066 n /= 1000; 1067 i += 1; 1068 } 1069 1070 sprintf(p[i++], "%d", (int)n); 1071 1072 while (i--) 1073 off += sprintf(buf + off, "%s,", p[i]); 1074 buf[strlen(buf) - 1] = '\0'; 1075 1076 return buf; 1077 } 1078 1079 static void 1080 packet_per_second_stats(void) 1081 { 1082 struct lcore_info *old; 1083 struct lcore_info *li, *oli; 1084 int nr_lines = 0; 1085 int i; 1086 1087 old = rte_zmalloc("old", 1088 sizeof(struct lcore_info) * MAX_LCORES, 0); 1089 if (old == NULL) 1090 rte_exit(EXIT_FAILURE, "No Memory available!"); 1091 1092 memcpy(old, lcore_infos, 1093 sizeof(struct lcore_info) * MAX_LCORES); 1094 1095 while (!force_quit) { 1096 uint64_t total_tx_pkts = 0; 1097 uint64_t total_rx_pkts = 0; 1098 uint64_t total_tx_drops = 0; 1099 uint64_t tx_delta, rx_delta, drops_delta; 1100 char buf[3][32]; 1101 int nr_valid_core = 0; 1102 1103 sleep(1); 1104 1105 if (nr_lines) { 1106 char go_up_nr_lines[16]; 1107 1108 sprintf(go_up_nr_lines, "%c[%dA\r", 27, nr_lines); 1109 printf("%s\r", go_up_nr_lines); 1110 } 1111 1112 printf("\n%6s %16s %16s %16s\n", "core", "tx", "tx drops", "rx"); 1113 printf("%6s %16s %16s %16s\n", "------", "----------------", 1114 "----------------", "----------------"); 1115 nr_lines = 3; 1116 for (i = 0; i < MAX_LCORES; i++) { 1117 li = &lcore_infos[i]; 1118 oli = &old[i]; 1119 if (li->mode != LCORE_MODE_PKT) 1120 continue; 1121 1122 tx_delta = li->tx_pkts - oli->tx_pkts; 1123 rx_delta = li->rx_pkts - oli->rx_pkts; 1124 drops_delta = li->tx_drops - oli->tx_drops; 1125 printf("%6d %16s %16s %16s\n", i, 1126 pretty_number(tx_delta, buf[0]), 1127 pretty_number(drops_delta, buf[1]), 1128 pretty_number(rx_delta, buf[2])); 1129 1130 total_tx_pkts += tx_delta; 1131 total_rx_pkts += rx_delta; 1132 total_tx_drops += drops_delta; 1133 1134 nr_valid_core++; 1135 nr_lines += 1; 1136 } 1137 1138 if (nr_valid_core > 1) { 1139 printf("%6s %16s %16s %16s\n", "total", 1140 pretty_number(total_tx_pkts, buf[0]), 1141 pretty_number(total_tx_drops, buf[1]), 1142 pretty_number(total_rx_pkts, buf[2])); 1143 nr_lines += 1; 1144 } 1145 1146 memcpy(old, lcore_infos, 1147 sizeof(struct lcore_info) * MAX_LCORES); 1148 } 1149 } 1150 1151 static int 1152 start_forwarding(void *data __rte_unused) 1153 { 1154 int lcore = rte_lcore_id(); 1155 int stream_id; 1156 uint16_t cnt; 1157 struct lcore_info *li = &lcore_infos[lcore]; 1158 1159 if (!li->mode) 1160 return 0; 1161 1162 if (li->mode == LCORE_MODE_STATS) { 1163 printf(":: started stats on lcore %u\n", lcore); 1164 packet_per_second_stats(); 1165 return 0; 1166 } 1167 1168 while (!force_quit) 1169 for (stream_id = 0; stream_id < MAX_STREAMS; stream_id++) { 1170 if (li->streams[stream_id].rx_port == -1) 1171 continue; 1172 1173 cnt = do_rx(li, 1174 li->streams[stream_id].rx_port, 1175 li->streams[stream_id].rx_queue); 1176 if (cnt) 1177 do_tx(li, cnt, 1178 li->streams[stream_id].tx_port, 1179 li->streams[stream_id].tx_queue); 1180 } 1181 return 0; 1182 } 1183 1184 static void 1185 init_lcore_info(void) 1186 { 1187 int i, j; 1188 unsigned int lcore; 1189 uint16_t nr_port; 1190 uint16_t queue; 1191 int port; 1192 int stream_id = 0; 1193 int streams_per_core; 1194 int unassigned_streams; 1195 int nb_fwd_streams; 1196 nr_port = rte_eth_dev_count_avail(); 1197 1198 /* First logical core is reserved for stats printing */ 1199 lcore = rte_get_next_lcore(-1, 0, 0); 1200 lcore_infos[lcore].mode = LCORE_MODE_STATS; 1201 1202 /* 1203 * Initialize all cores 1204 * All cores at first must have -1 value in all streams 1205 * This means that this stream is not used, or not set 1206 * yet. 1207 */ 1208 for (i = 0; i < MAX_LCORES; i++) 1209 for (j = 0; j < MAX_STREAMS; j++) { 1210 lcore_infos[i].streams[j].tx_port = -1; 1211 lcore_infos[i].streams[j].rx_port = -1; 1212 lcore_infos[i].streams[j].tx_queue = -1; 1213 lcore_infos[i].streams[j].rx_queue = -1; 1214 lcore_infos[i].streams_nb = 0; 1215 } 1216 1217 /* 1218 * Calculate the total streams count. 1219 * Also distribute those streams count between the available 1220 * logical cores except first core, since it's reserved for 1221 * stats prints. 1222 */ 1223 nb_fwd_streams = nr_port * RXQ_NUM; 1224 if ((int)(nb_lcores - 1) >= nb_fwd_streams) 1225 for (i = 0; i < (int)(nb_lcores - 1); i++) { 1226 lcore = rte_get_next_lcore(lcore, 0, 0); 1227 lcore_infos[lcore].streams_nb = 1; 1228 } 1229 else { 1230 streams_per_core = nb_fwd_streams / (nb_lcores - 1); 1231 unassigned_streams = nb_fwd_streams % (nb_lcores - 1); 1232 for (i = 0; i < (int)(nb_lcores - 1); i++) { 1233 lcore = rte_get_next_lcore(lcore, 0, 0); 1234 lcore_infos[lcore].streams_nb = streams_per_core; 1235 if (unassigned_streams) { 1236 lcore_infos[lcore].streams_nb++; 1237 unassigned_streams--; 1238 } 1239 } 1240 } 1241 1242 /* 1243 * Set the streams for the cores according to each logical 1244 * core stream count. 1245 * The streams is built on the design of what received should 1246 * forward as well, this means that if you received packets on 1247 * port 0 queue 0 then the same queue should forward the 1248 * packets, using the same logical core. 1249 */ 1250 lcore = rte_get_next_lcore(-1, 0, 0); 1251 for (port = 0; port < nr_port; port++) { 1252 /* Create FWD stream */ 1253 for (queue = 0; queue < RXQ_NUM; queue++) { 1254 if (!lcore_infos[lcore].streams_nb || 1255 !(stream_id % lcore_infos[lcore].streams_nb)) { 1256 lcore = rte_get_next_lcore(lcore, 0, 0); 1257 lcore_infos[lcore].mode = LCORE_MODE_PKT; 1258 stream_id = 0; 1259 } 1260 lcore_infos[lcore].streams[stream_id].rx_queue = queue; 1261 lcore_infos[lcore].streams[stream_id].tx_queue = queue; 1262 lcore_infos[lcore].streams[stream_id].rx_port = port; 1263 lcore_infos[lcore].streams[stream_id].tx_port = port; 1264 stream_id++; 1265 } 1266 } 1267 1268 /* Print all streams */ 1269 printf(":: Stream -> core id[N]: (rx_port, rx_queue)->(tx_port, tx_queue)\n"); 1270 for (i = 0; i < MAX_LCORES; i++) 1271 for (j = 0; j < MAX_STREAMS; j++) { 1272 /* No streams for this core */ 1273 if (lcore_infos[i].streams[j].tx_port == -1) 1274 break; 1275 printf("Stream -> core id[%d]: (%d,%d)->(%d,%d)\n", 1276 i, 1277 lcore_infos[i].streams[j].rx_port, 1278 lcore_infos[i].streams[j].rx_queue, 1279 lcore_infos[i].streams[j].tx_port, 1280 lcore_infos[i].streams[j].tx_queue); 1281 } 1282 } 1283 1284 static void 1285 init_port(void) 1286 { 1287 int ret; 1288 uint16_t std_queue; 1289 uint16_t hairpin_queue; 1290 uint16_t port_id; 1291 uint16_t nr_ports; 1292 uint16_t nr_queues; 1293 struct rte_eth_hairpin_conf hairpin_conf = { 1294 .peer_count = 1, 1295 }; 1296 struct rte_eth_conf port_conf = { 1297 .rx_adv_conf = { 1298 .rss_conf.rss_hf = 1299 GET_RSS_HF(), 1300 } 1301 }; 1302 struct rte_eth_txconf txq_conf; 1303 struct rte_eth_rxconf rxq_conf; 1304 struct rte_eth_dev_info dev_info; 1305 1306 nr_queues = RXQ_NUM; 1307 if (hairpin_queues_num != 0) 1308 nr_queues = RXQ_NUM + hairpin_queues_num; 1309 1310 nr_ports = rte_eth_dev_count_avail(); 1311 if (nr_ports == 0) 1312 rte_exit(EXIT_FAILURE, "Error: no port detected\n"); 1313 1314 mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool", 1315 TOTAL_MBUF_NUM, MBUF_CACHE_SIZE, 1316 0, MBUF_SIZE, 1317 rte_socket_id()); 1318 if (mbuf_mp == NULL) 1319 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n"); 1320 1321 for (port_id = 0; port_id < nr_ports; port_id++) { 1322 ret = rte_eth_dev_info_get(port_id, &dev_info); 1323 if (ret != 0) 1324 rte_exit(EXIT_FAILURE, 1325 "Error during getting device" 1326 " (port %u) info: %s\n", 1327 port_id, strerror(-ret)); 1328 1329 port_conf.txmode.offloads &= dev_info.tx_offload_capa; 1330 port_conf.rxmode.offloads &= dev_info.rx_offload_capa; 1331 1332 printf(":: initializing port: %d\n", port_id); 1333 1334 ret = rte_eth_dev_configure(port_id, nr_queues, 1335 nr_queues, &port_conf); 1336 if (ret < 0) 1337 rte_exit(EXIT_FAILURE, 1338 ":: cannot configure device: err=%d, port=%u\n", 1339 ret, port_id); 1340 1341 rxq_conf = dev_info.default_rxconf; 1342 for (std_queue = 0; std_queue < RXQ_NUM; std_queue++) { 1343 ret = rte_eth_rx_queue_setup(port_id, std_queue, NR_RXD, 1344 rte_eth_dev_socket_id(port_id), 1345 &rxq_conf, 1346 mbuf_mp); 1347 if (ret < 0) 1348 rte_exit(EXIT_FAILURE, 1349 ":: Rx queue setup failed: err=%d, port=%u\n", 1350 ret, port_id); 1351 } 1352 1353 txq_conf = dev_info.default_txconf; 1354 for (std_queue = 0; std_queue < TXQ_NUM; std_queue++) { 1355 ret = rte_eth_tx_queue_setup(port_id, std_queue, NR_TXD, 1356 rte_eth_dev_socket_id(port_id), 1357 &txq_conf); 1358 if (ret < 0) 1359 rte_exit(EXIT_FAILURE, 1360 ":: Tx queue setup failed: err=%d, port=%u\n", 1361 ret, port_id); 1362 } 1363 1364 /* Catch all packets from traffic generator. */ 1365 ret = rte_eth_promiscuous_enable(port_id); 1366 if (ret != 0) 1367 rte_exit(EXIT_FAILURE, 1368 ":: promiscuous mode enable failed: err=%s, port=%u\n", 1369 rte_strerror(-ret), port_id); 1370 1371 if (hairpin_queues_num != 0) { 1372 /* 1373 * Configure peer which represents hairpin Tx. 1374 * Hairpin queue numbers start after standard queues 1375 * (RXQ_NUM and TXQ_NUM). 1376 */ 1377 for (hairpin_queue = RXQ_NUM, std_queue = 0; 1378 hairpin_queue < nr_queues; 1379 hairpin_queue++, std_queue++) { 1380 hairpin_conf.peers[0].port = port_id; 1381 hairpin_conf.peers[0].queue = 1382 std_queue + TXQ_NUM; 1383 ret = rte_eth_rx_hairpin_queue_setup( 1384 port_id, hairpin_queue, 1385 NR_RXD, &hairpin_conf); 1386 if (ret != 0) 1387 rte_exit(EXIT_FAILURE, 1388 ":: Hairpin rx queue setup failed: err=%d, port=%u\n", 1389 ret, port_id); 1390 } 1391 1392 for (hairpin_queue = TXQ_NUM, std_queue = 0; 1393 hairpin_queue < nr_queues; 1394 hairpin_queue++, std_queue++) { 1395 hairpin_conf.peers[0].port = port_id; 1396 hairpin_conf.peers[0].queue = 1397 std_queue + RXQ_NUM; 1398 ret = rte_eth_tx_hairpin_queue_setup( 1399 port_id, hairpin_queue, 1400 NR_TXD, &hairpin_conf); 1401 if (ret != 0) 1402 rte_exit(EXIT_FAILURE, 1403 ":: Hairpin tx queue setup failed: err=%d, port=%u\n", 1404 ret, port_id); 1405 } 1406 } 1407 1408 ret = rte_eth_dev_start(port_id); 1409 if (ret < 0) 1410 rte_exit(EXIT_FAILURE, 1411 "rte_eth_dev_start:err=%d, port=%u\n", 1412 ret, port_id); 1413 1414 printf(":: initializing port: %d done\n", port_id); 1415 } 1416 } 1417 1418 int 1419 main(int argc, char **argv) 1420 { 1421 int ret; 1422 uint16_t port; 1423 struct rte_flow_error error; 1424 int64_t alloc, last_alloc; 1425 1426 ret = rte_eal_init(argc, argv); 1427 if (ret < 0) 1428 rte_exit(EXIT_FAILURE, "EAL init failed\n"); 1429 1430 force_quit = false; 1431 dump_iterations = false; 1432 rules_count = DEFAULT_RULES_COUNT; 1433 rules_batch = DEFAULT_RULES_BATCH; 1434 delete_flag = false; 1435 dump_socket_mem_flag = false; 1436 flow_group = DEFAULT_GROUP; 1437 1438 signal(SIGINT, signal_handler); 1439 signal(SIGTERM, signal_handler); 1440 1441 argc -= ret; 1442 argv += ret; 1443 if (argc > 1) 1444 args_parse(argc, argv); 1445 1446 init_port(); 1447 1448 nb_lcores = rte_lcore_count(); 1449 if (nb_lcores <= 1) 1450 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n"); 1451 1452 last_alloc = (int64_t)dump_socket_mem(stdout); 1453 flows_handler(); 1454 alloc = (int64_t)dump_socket_mem(stdout); 1455 1456 if (last_alloc) 1457 fprintf(stdout, ":: Memory allocation change(M): %.6lf\n", 1458 (alloc - last_alloc) / 1.0e6); 1459 1460 if (enable_fwd) { 1461 init_lcore_info(); 1462 rte_eal_mp_remote_launch(start_forwarding, NULL, CALL_MAIN); 1463 } 1464 1465 RTE_ETH_FOREACH_DEV(port) { 1466 rte_flow_flush(port, &error); 1467 if (rte_eth_dev_stop(port) != 0) 1468 printf("Failed to stop device on port %u\n", port); 1469 rte_eth_dev_close(port); 1470 } 1471 return 0; 1472 } 1473