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