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 #include <rte_mtr.h> 38 39 #include "config.h" 40 #include "flow_gen.h" 41 42 #define MAX_BATCHES_COUNT 100 43 #define DEFAULT_RULES_COUNT 4000000 44 #define DEFAULT_RULES_BATCH 100000 45 #define DEFAULT_GROUP 0 46 47 struct rte_flow *flow; 48 static uint8_t flow_group; 49 50 static uint64_t encap_data; 51 static uint64_t decap_data; 52 53 static uint64_t flow_items[MAX_ITEMS_NUM]; 54 static uint64_t flow_actions[MAX_ACTIONS_NUM]; 55 static uint64_t flow_attrs[MAX_ATTRS_NUM]; 56 static uint8_t items_idx, actions_idx, attrs_idx; 57 58 static uint64_t ports_mask; 59 static volatile bool force_quit; 60 static bool dump_iterations; 61 static bool delete_flag; 62 static bool dump_socket_mem_flag; 63 static bool enable_fwd; 64 static bool unique_data; 65 66 static uint8_t rx_queues_count; 67 static uint8_t tx_queues_count; 68 static uint8_t rxd_count; 69 static uint8_t txd_count; 70 static uint32_t mbuf_size; 71 static uint32_t mbuf_cache_size; 72 static uint32_t total_mbuf_num; 73 74 static struct rte_mempool *mbuf_mp; 75 static uint32_t nb_lcores; 76 static uint32_t rules_count; 77 static uint32_t rules_batch; 78 static uint32_t hairpin_queues_num; /* total hairpin q number - default: 0 */ 79 static uint32_t nb_lcores; 80 81 #define MAX_PKT_BURST 32 82 #define LCORE_MODE_PKT 1 83 #define LCORE_MODE_STATS 2 84 #define MAX_STREAMS 64 85 #define METER_CREATE 1 86 #define METER_DELETE 2 87 88 struct stream { 89 int tx_port; 90 int tx_queue; 91 int rx_port; 92 int rx_queue; 93 }; 94 95 struct lcore_info { 96 int mode; 97 int streams_nb; 98 struct stream streams[MAX_STREAMS]; 99 /* stats */ 100 uint64_t tx_pkts; 101 uint64_t tx_drops; 102 uint64_t rx_pkts; 103 struct rte_mbuf *pkts[MAX_PKT_BURST]; 104 } __rte_cache_aligned; 105 106 static struct lcore_info lcore_infos[RTE_MAX_LCORE]; 107 108 struct used_cpu_time { 109 double insertion[MAX_PORTS][RTE_MAX_LCORE]; 110 double deletion[MAX_PORTS][RTE_MAX_LCORE]; 111 }; 112 113 struct multi_cores_pool { 114 uint32_t cores_count; 115 uint32_t rules_count; 116 struct used_cpu_time meters_record; 117 struct used_cpu_time flows_record; 118 int64_t last_alloc[RTE_MAX_LCORE]; 119 int64_t current_alloc[RTE_MAX_LCORE]; 120 } __rte_cache_aligned; 121 122 static struct multi_cores_pool mc_pool = { 123 .cores_count = 1, 124 }; 125 126 static void 127 usage(char *progname) 128 { 129 printf("\nusage: %s\n", progname); 130 printf("\nControl configurations:\n"); 131 printf(" --rules-count=N: to set the number of needed" 132 " rules to insert, default is %d\n", DEFAULT_RULES_COUNT); 133 printf(" --rules-batch=N: set number of batched rules," 134 " default is %d\n", DEFAULT_RULES_BATCH); 135 printf(" --dump-iterations: To print rates for each" 136 " iteration\n"); 137 printf(" --deletion-rate: Enable deletion rate" 138 " calculations\n"); 139 printf(" --dump-socket-mem: To dump all socket memory\n"); 140 printf(" --enable-fwd: To enable packets forwarding" 141 " after insertion\n"); 142 printf(" --portmask=N: hexadecimal bitmask of ports used\n"); 143 printf(" --unique-data: flag to set using unique data for all" 144 " actions that support data, such as header modify and encap actions\n"); 145 146 printf("To set flow attributes:\n"); 147 printf(" --ingress: set ingress attribute in flows\n"); 148 printf(" --egress: set egress attribute in flows\n"); 149 printf(" --transfer: set transfer attribute in flows\n"); 150 printf(" --group=N: set group for all flows," 151 " default is %d\n", DEFAULT_GROUP); 152 printf(" --cores=N: to set the number of needed " 153 "cores to insert rte_flow rules, default is 1\n"); 154 printf(" --rxq=N: to set the count of receive queues\n"); 155 printf(" --txq=N: to set the count of send queues\n"); 156 printf(" --rxd=N: to set the count of rxd\n"); 157 printf(" --txd=N: to set the count of txd\n"); 158 printf(" --mbuf-size=N: to set the size of mbuf\n"); 159 printf(" --mbuf-cache-size=N: to set the size of mbuf cache\n"); 160 printf(" --total-mbuf-count=N: to set the count of total mbuf count\n"); 161 162 163 printf("To set flow items:\n"); 164 printf(" --ether: add ether layer in flow items\n"); 165 printf(" --vlan: add vlan layer in flow items\n"); 166 printf(" --ipv4: add ipv4 layer in flow items\n"); 167 printf(" --ipv6: add ipv6 layer in flow items\n"); 168 printf(" --tcp: add tcp layer in flow items\n"); 169 printf(" --udp: add udp layer in flow items\n"); 170 printf(" --vxlan: add vxlan layer in flow items\n"); 171 printf(" --vxlan-gpe: add vxlan-gpe layer in flow items\n"); 172 printf(" --gre: add gre layer in flow items\n"); 173 printf(" --geneve: add geneve layer in flow items\n"); 174 printf(" --gtp: add gtp layer in flow items\n"); 175 printf(" --meta: add meta layer in flow items\n"); 176 printf(" --tag: add tag layer in flow items\n"); 177 printf(" --icmpv4: add icmpv4 layer in flow items\n"); 178 printf(" --icmpv6: add icmpv6 layer in flow items\n"); 179 180 printf("To set flow actions:\n"); 181 printf(" --port-id: add port-id action in flow actions\n"); 182 printf(" --rss: add rss action in flow actions\n"); 183 printf(" --queue: add queue action in flow actions\n"); 184 printf(" --jump: add jump action in flow actions\n"); 185 printf(" --mark: add mark action in flow actions\n"); 186 printf(" --count: add count action in flow actions\n"); 187 printf(" --set-meta: add set meta action in flow actions\n"); 188 printf(" --set-tag: add set tag action in flow actions\n"); 189 printf(" --drop: add drop action in flow actions\n"); 190 printf(" --hairpin-queue=N: add hairpin-queue action in flow actions\n"); 191 printf(" --hairpin-rss=N: add hairpin-rss action in flow actions\n"); 192 printf(" --set-src-mac: add set src mac action to flow actions\n" 193 "Src mac to be set is random each flow\n"); 194 printf(" --set-dst-mac: add set dst mac action to flow actions\n" 195 "Dst mac to be set is random each flow\n"); 196 printf(" --set-src-ipv4: add set src ipv4 action to flow actions\n" 197 "Src ipv4 to be set is random each flow\n"); 198 printf(" --set-dst-ipv4 add set dst ipv4 action to flow actions\n" 199 "Dst ipv4 to be set is random each flow\n"); 200 printf(" --set-src-ipv6: add set src ipv6 action to flow actions\n" 201 "Src ipv6 to be set is random each flow\n"); 202 printf(" --set-dst-ipv6: add set dst ipv6 action to flow actions\n" 203 "Dst ipv6 to be set is random each flow\n"); 204 printf(" --set-src-tp: add set src tp action to flow actions\n" 205 "Src tp to be set is random each flow\n"); 206 printf(" --set-dst-tp: add set dst tp action to flow actions\n" 207 "Dst tp to be set is random each flow\n"); 208 printf(" --inc-tcp-ack: add inc tcp ack action to flow actions\n" 209 "tcp ack will be increments by 1\n"); 210 printf(" --dec-tcp-ack: add dec tcp ack action to flow actions\n" 211 "tcp ack will be decrements by 1\n"); 212 printf(" --inc-tcp-seq: add inc tcp seq action to flow actions\n" 213 "tcp seq will be increments by 1\n"); 214 printf(" --dec-tcp-seq: add dec tcp seq action to flow actions\n" 215 "tcp seq will be decrements by 1\n"); 216 printf(" --set-ttl: add set ttl action to flow actions\n" 217 "L3 ttl to be set is random each flow\n"); 218 printf(" --dec-ttl: add dec ttl action to flow actions\n" 219 "L3 ttl will be decrements by 1\n"); 220 printf(" --set-ipv4-dscp: add set ipv4 dscp action to flow actions\n" 221 "ipv4 dscp value to be set is random each flow\n"); 222 printf(" --set-ipv6-dscp: add set ipv6 dscp action to flow actions\n" 223 "ipv6 dscp value to be set is random each flow\n"); 224 printf(" --flag: add flag action to flow actions\n"); 225 printf(" --meter: add meter action to flow actions\n"); 226 printf(" --raw-encap=<data>: add raw encap action to flow actions\n" 227 "Data is the data needed to be encaped\n" 228 "Example: raw-encap=ether,ipv4,udp,vxlan\n"); 229 printf(" --raw-decap=<data>: add raw decap action to flow actions\n" 230 "Data is the data needed to be decaped\n" 231 "Example: raw-decap=ether,ipv4,udp,vxlan\n"); 232 printf(" --vxlan-encap: add vxlan-encap action to flow actions\n" 233 "Encapped data is fixed with pattern: ether,ipv4,udp,vxlan\n" 234 "With fixed values\n"); 235 printf(" --vxlan-decap: add vxlan_decap action to flow actions\n"); 236 } 237 238 static void 239 args_parse(int argc, char **argv) 240 { 241 uint64_t pm; 242 char **argvopt; 243 char *token; 244 char *end; 245 int n, opt; 246 int opt_idx; 247 size_t i; 248 249 static const struct option_dict { 250 const char *str; 251 const uint64_t mask; 252 uint64_t *map; 253 uint8_t *map_idx; 254 255 } flow_options[] = { 256 { 257 .str = "ether", 258 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH), 259 .map = &flow_items[0], 260 .map_idx = &items_idx 261 }, 262 { 263 .str = "ipv4", 264 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV4), 265 .map = &flow_items[0], 266 .map_idx = &items_idx 267 }, 268 { 269 .str = "ipv6", 270 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV6), 271 .map = &flow_items[0], 272 .map_idx = &items_idx 273 }, 274 { 275 .str = "vlan", 276 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VLAN), 277 .map = &flow_items[0], 278 .map_idx = &items_idx 279 }, 280 { 281 .str = "tcp", 282 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TCP), 283 .map = &flow_items[0], 284 .map_idx = &items_idx 285 }, 286 { 287 .str = "udp", 288 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_UDP), 289 .map = &flow_items[0], 290 .map_idx = &items_idx 291 }, 292 { 293 .str = "vxlan", 294 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN), 295 .map = &flow_items[0], 296 .map_idx = &items_idx 297 }, 298 { 299 .str = "vxlan-gpe", 300 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN_GPE), 301 .map = &flow_items[0], 302 .map_idx = &items_idx 303 }, 304 { 305 .str = "gre", 306 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GRE), 307 .map = &flow_items[0], 308 .map_idx = &items_idx 309 }, 310 { 311 .str = "geneve", 312 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GENEVE), 313 .map = &flow_items[0], 314 .map_idx = &items_idx 315 }, 316 { 317 .str = "gtp", 318 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GTP), 319 .map = &flow_items[0], 320 .map_idx = &items_idx 321 }, 322 { 323 .str = "meta", 324 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_META), 325 .map = &flow_items[0], 326 .map_idx = &items_idx 327 }, 328 { 329 .str = "tag", 330 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TAG), 331 .map = &flow_items[0], 332 .map_idx = &items_idx 333 }, 334 { 335 .str = "icmpv4", 336 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ICMP), 337 .map = &flow_items[0], 338 .map_idx = &items_idx 339 }, 340 { 341 .str = "icmpv6", 342 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ICMP6), 343 .map = &flow_items[0], 344 .map_idx = &items_idx 345 }, 346 { 347 .str = "ingress", 348 .mask = INGRESS, 349 .map = &flow_attrs[0], 350 .map_idx = &attrs_idx 351 }, 352 { 353 .str = "egress", 354 .mask = EGRESS, 355 .map = &flow_attrs[0], 356 .map_idx = &attrs_idx 357 }, 358 { 359 .str = "transfer", 360 .mask = TRANSFER, 361 .map = &flow_attrs[0], 362 .map_idx = &attrs_idx 363 }, 364 { 365 .str = "port-id", 366 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_PORT_ID), 367 .map = &flow_actions[0], 368 .map_idx = &actions_idx 369 }, 370 { 371 .str = "rss", 372 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_RSS), 373 .map = &flow_actions[0], 374 .map_idx = &actions_idx 375 }, 376 { 377 .str = "queue", 378 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_QUEUE), 379 .map = &flow_actions[0], 380 .map_idx = &actions_idx 381 }, 382 { 383 .str = "jump", 384 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_JUMP), 385 .map = &flow_actions[0], 386 .map_idx = &actions_idx 387 }, 388 { 389 .str = "mark", 390 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_MARK), 391 .map = &flow_actions[0], 392 .map_idx = &actions_idx 393 }, 394 { 395 .str = "count", 396 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_COUNT), 397 .map = &flow_actions[0], 398 .map_idx = &actions_idx 399 }, 400 { 401 .str = "set-meta", 402 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_META), 403 .map = &flow_actions[0], 404 .map_idx = &actions_idx 405 }, 406 { 407 .str = "set-tag", 408 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_TAG), 409 .map = &flow_actions[0], 410 .map_idx = &actions_idx 411 }, 412 { 413 .str = "drop", 414 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_DROP), 415 .map = &flow_actions[0], 416 .map_idx = &actions_idx 417 }, 418 { 419 .str = "set-src-mac", 420 .mask = FLOW_ACTION_MASK( 421 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC 422 ), 423 .map = &flow_actions[0], 424 .map_idx = &actions_idx 425 }, 426 { 427 .str = "set-dst-mac", 428 .mask = FLOW_ACTION_MASK( 429 RTE_FLOW_ACTION_TYPE_SET_MAC_DST 430 ), 431 .map = &flow_actions[0], 432 .map_idx = &actions_idx 433 }, 434 { 435 .str = "set-src-ipv4", 436 .mask = FLOW_ACTION_MASK( 437 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC 438 ), 439 .map = &flow_actions[0], 440 .map_idx = &actions_idx 441 }, 442 { 443 .str = "set-dst-ipv4", 444 .mask = FLOW_ACTION_MASK( 445 RTE_FLOW_ACTION_TYPE_SET_IPV4_DST 446 ), 447 .map = &flow_actions[0], 448 .map_idx = &actions_idx 449 }, 450 { 451 .str = "set-src-ipv6", 452 .mask = FLOW_ACTION_MASK( 453 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC 454 ), 455 .map = &flow_actions[0], 456 .map_idx = &actions_idx 457 }, 458 { 459 .str = "set-dst-ipv6", 460 .mask = FLOW_ACTION_MASK( 461 RTE_FLOW_ACTION_TYPE_SET_IPV6_DST 462 ), 463 .map = &flow_actions[0], 464 .map_idx = &actions_idx 465 }, 466 { 467 .str = "set-src-tp", 468 .mask = FLOW_ACTION_MASK( 469 RTE_FLOW_ACTION_TYPE_SET_TP_SRC 470 ), 471 .map = &flow_actions[0], 472 .map_idx = &actions_idx 473 }, 474 { 475 .str = "set-dst-tp", 476 .mask = FLOW_ACTION_MASK( 477 RTE_FLOW_ACTION_TYPE_SET_TP_DST 478 ), 479 .map = &flow_actions[0], 480 .map_idx = &actions_idx 481 }, 482 { 483 .str = "inc-tcp-ack", 484 .mask = FLOW_ACTION_MASK( 485 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK 486 ), 487 .map = &flow_actions[0], 488 .map_idx = &actions_idx 489 }, 490 { 491 .str = "dec-tcp-ack", 492 .mask = FLOW_ACTION_MASK( 493 RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK 494 ), 495 .map = &flow_actions[0], 496 .map_idx = &actions_idx 497 }, 498 { 499 .str = "inc-tcp-seq", 500 .mask = FLOW_ACTION_MASK( 501 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ 502 ), 503 .map = &flow_actions[0], 504 .map_idx = &actions_idx 505 }, 506 { 507 .str = "dec-tcp-seq", 508 .mask = FLOW_ACTION_MASK( 509 RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ 510 ), 511 .map = &flow_actions[0], 512 .map_idx = &actions_idx 513 }, 514 { 515 .str = "set-ttl", 516 .mask = FLOW_ACTION_MASK( 517 RTE_FLOW_ACTION_TYPE_SET_TTL 518 ), 519 .map = &flow_actions[0], 520 .map_idx = &actions_idx 521 }, 522 { 523 .str = "dec-ttl", 524 .mask = FLOW_ACTION_MASK( 525 RTE_FLOW_ACTION_TYPE_DEC_TTL 526 ), 527 .map = &flow_actions[0], 528 .map_idx = &actions_idx 529 }, 530 { 531 .str = "set-ipv4-dscp", 532 .mask = FLOW_ACTION_MASK( 533 RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP 534 ), 535 .map = &flow_actions[0], 536 .map_idx = &actions_idx 537 }, 538 { 539 .str = "set-ipv6-dscp", 540 .mask = FLOW_ACTION_MASK( 541 RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP 542 ), 543 .map = &flow_actions[0], 544 .map_idx = &actions_idx 545 }, 546 { 547 .str = "flag", 548 .mask = FLOW_ACTION_MASK( 549 RTE_FLOW_ACTION_TYPE_FLAG 550 ), 551 .map = &flow_actions[0], 552 .map_idx = &actions_idx 553 }, 554 { 555 .str = "meter", 556 .mask = FLOW_ACTION_MASK( 557 RTE_FLOW_ACTION_TYPE_METER 558 ), 559 .map = &flow_actions[0], 560 .map_idx = &actions_idx 561 }, 562 { 563 .str = "vxlan-encap", 564 .mask = FLOW_ACTION_MASK( 565 RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP 566 ), 567 .map = &flow_actions[0], 568 .map_idx = &actions_idx 569 }, 570 { 571 .str = "vxlan-decap", 572 .mask = FLOW_ACTION_MASK( 573 RTE_FLOW_ACTION_TYPE_VXLAN_DECAP 574 ), 575 .map = &flow_actions[0], 576 .map_idx = &actions_idx 577 }, 578 }; 579 580 static const struct option lgopts[] = { 581 /* Control */ 582 { "help", 0, 0, 0 }, 583 { "rules-count", 1, 0, 0 }, 584 { "rules-batch", 1, 0, 0 }, 585 { "dump-iterations", 0, 0, 0 }, 586 { "deletion-rate", 0, 0, 0 }, 587 { "dump-socket-mem", 0, 0, 0 }, 588 { "enable-fwd", 0, 0, 0 }, 589 { "unique-data", 0, 0, 0 }, 590 { "portmask", 1, 0, 0 }, 591 { "cores", 1, 0, 0 }, 592 { "meter-profile-alg", 1, 0, 0 }, 593 { "rxq", 1, 0, 0 }, 594 { "txq", 1, 0, 0 }, 595 { "rxd", 1, 0, 0 }, 596 { "txd", 1, 0, 0 }, 597 { "mbuf-size", 1, 0, 0 }, 598 { "mbuf-cache-size", 1, 0, 0 }, 599 { "total-mbuf-count", 1, 0, 0 }, 600 /* Attributes */ 601 { "ingress", 0, 0, 0 }, 602 { "egress", 0, 0, 0 }, 603 { "transfer", 0, 0, 0 }, 604 { "group", 1, 0, 0 }, 605 /* Items */ 606 { "ether", 0, 0, 0 }, 607 { "vlan", 0, 0, 0 }, 608 { "ipv4", 0, 0, 0 }, 609 { "ipv6", 0, 0, 0 }, 610 { "tcp", 0, 0, 0 }, 611 { "udp", 0, 0, 0 }, 612 { "vxlan", 0, 0, 0 }, 613 { "vxlan-gpe", 0, 0, 0 }, 614 { "gre", 0, 0, 0 }, 615 { "geneve", 0, 0, 0 }, 616 { "gtp", 0, 0, 0 }, 617 { "meta", 0, 0, 0 }, 618 { "tag", 0, 0, 0 }, 619 { "icmpv4", 0, 0, 0 }, 620 { "icmpv6", 0, 0, 0 }, 621 /* Actions */ 622 { "port-id", 0, 0, 0 }, 623 { "rss", 0, 0, 0 }, 624 { "queue", 0, 0, 0 }, 625 { "jump", 0, 0, 0 }, 626 { "mark", 0, 0, 0 }, 627 { "count", 0, 0, 0 }, 628 { "set-meta", 0, 0, 0 }, 629 { "set-tag", 0, 0, 0 }, 630 { "drop", 0, 0, 0 }, 631 { "hairpin-queue", 1, 0, 0 }, 632 { "hairpin-rss", 1, 0, 0 }, 633 { "set-src-mac", 0, 0, 0 }, 634 { "set-dst-mac", 0, 0, 0 }, 635 { "set-src-ipv4", 0, 0, 0 }, 636 { "set-dst-ipv4", 0, 0, 0 }, 637 { "set-src-ipv6", 0, 0, 0 }, 638 { "set-dst-ipv6", 0, 0, 0 }, 639 { "set-src-tp", 0, 0, 0 }, 640 { "set-dst-tp", 0, 0, 0 }, 641 { "inc-tcp-ack", 0, 0, 0 }, 642 { "dec-tcp-ack", 0, 0, 0 }, 643 { "inc-tcp-seq", 0, 0, 0 }, 644 { "dec-tcp-seq", 0, 0, 0 }, 645 { "set-ttl", 0, 0, 0 }, 646 { "dec-ttl", 0, 0, 0 }, 647 { "set-ipv4-dscp", 0, 0, 0 }, 648 { "set-ipv6-dscp", 0, 0, 0 }, 649 { "flag", 0, 0, 0 }, 650 { "meter", 0, 0, 0 }, 651 { "raw-encap", 1, 0, 0 }, 652 { "raw-decap", 1, 0, 0 }, 653 { "vxlan-encap", 0, 0, 0 }, 654 { "vxlan-decap", 0, 0, 0 }, 655 }; 656 657 RTE_ETH_FOREACH_DEV(i) 658 ports_mask |= 1 << i; 659 660 hairpin_queues_num = 0; 661 argvopt = argv; 662 663 printf(":: Flow -> "); 664 while ((opt = getopt_long(argc, argvopt, "", 665 lgopts, &opt_idx)) != EOF) { 666 switch (opt) { 667 case 0: 668 if (strcmp(lgopts[opt_idx].name, "help") == 0) { 669 usage(argv[0]); 670 exit(EXIT_SUCCESS); 671 } 672 673 if (strcmp(lgopts[opt_idx].name, "group") == 0) { 674 n = atoi(optarg); 675 if (n >= 0) 676 flow_group = n; 677 else 678 rte_exit(EXIT_FAILURE, 679 "flow group should be >= 0\n"); 680 printf("group %d / ", flow_group); 681 } 682 683 for (i = 0; i < RTE_DIM(flow_options); i++) 684 if (strcmp(lgopts[opt_idx].name, 685 flow_options[i].str) == 0) { 686 flow_options[i].map[ 687 (*flow_options[i].map_idx)++] = 688 flow_options[i].mask; 689 printf("%s / ", flow_options[i].str); 690 } 691 692 if (strcmp(lgopts[opt_idx].name, 693 "hairpin-rss") == 0) { 694 n = atoi(optarg); 695 if (n > 0) 696 hairpin_queues_num = n; 697 else 698 rte_exit(EXIT_FAILURE, 699 "Hairpin queues should be > 0\n"); 700 701 flow_actions[actions_idx++] = 702 HAIRPIN_RSS_ACTION; 703 printf("hairpin-rss / "); 704 } 705 if (strcmp(lgopts[opt_idx].name, 706 "hairpin-queue") == 0) { 707 n = atoi(optarg); 708 if (n > 0) 709 hairpin_queues_num = n; 710 else 711 rte_exit(EXIT_FAILURE, 712 "Hairpin queues should be > 0\n"); 713 714 flow_actions[actions_idx++] = 715 HAIRPIN_QUEUE_ACTION; 716 printf("hairpin-queue / "); 717 } 718 719 if (strcmp(lgopts[opt_idx].name, "raw-encap") == 0) { 720 printf("raw-encap "); 721 flow_actions[actions_idx++] = 722 FLOW_ITEM_MASK( 723 RTE_FLOW_ACTION_TYPE_RAW_ENCAP 724 ); 725 726 token = strtok(optarg, ","); 727 while (token != NULL) { 728 for (i = 0; i < RTE_DIM(flow_options); i++) { 729 if (strcmp(flow_options[i].str, token) == 0) { 730 printf("%s,", token); 731 encap_data |= flow_options[i].mask; 732 break; 733 } 734 /* Reached last item with no match */ 735 if (i == (RTE_DIM(flow_options) - 1)) 736 rte_exit(EXIT_FAILURE, 737 "Invalid encap item: %s\n", token); 738 } 739 token = strtok(NULL, ","); 740 } 741 printf(" / "); 742 } 743 if (strcmp(lgopts[opt_idx].name, "raw-decap") == 0) { 744 printf("raw-decap "); 745 flow_actions[actions_idx++] = 746 FLOW_ITEM_MASK( 747 RTE_FLOW_ACTION_TYPE_RAW_DECAP 748 ); 749 750 token = strtok(optarg, ","); 751 while (token != NULL) { 752 for (i = 0; i < RTE_DIM(flow_options); i++) { 753 if (strcmp(flow_options[i].str, token) == 0) { 754 printf("%s,", token); 755 decap_data |= flow_options[i].mask; 756 break; 757 } 758 /* Reached last item with no match */ 759 if (i == (RTE_DIM(flow_options) - 1)) 760 rte_exit(EXIT_FAILURE, 761 "Invalid decap item %s\n", token); 762 } 763 token = strtok(NULL, ","); 764 } 765 printf(" / "); 766 } 767 /* Control */ 768 if (strcmp(lgopts[opt_idx].name, 769 "rules-batch") == 0) { 770 n = atoi(optarg); 771 if (n >= DEFAULT_RULES_BATCH) 772 rules_batch = n; 773 else { 774 rte_exit(EXIT_FAILURE, 775 "rules_batch should be >= %d\n", 776 DEFAULT_RULES_BATCH); 777 } 778 } 779 if (strcmp(lgopts[opt_idx].name, 780 "rules-count") == 0) { 781 n = atoi(optarg); 782 if (n >= (int) rules_batch) 783 rules_count = n; 784 else { 785 rte_exit(EXIT_FAILURE, 786 "rules_count should be >= %d\n", 787 rules_batch); 788 } 789 } 790 if (strcmp(lgopts[opt_idx].name, 791 "dump-iterations") == 0) 792 dump_iterations = true; 793 if (strcmp(lgopts[opt_idx].name, 794 "unique-data") == 0) 795 unique_data = true; 796 if (strcmp(lgopts[opt_idx].name, 797 "deletion-rate") == 0) 798 delete_flag = true; 799 if (strcmp(lgopts[opt_idx].name, 800 "dump-socket-mem") == 0) 801 dump_socket_mem_flag = true; 802 if (strcmp(lgopts[opt_idx].name, 803 "enable-fwd") == 0) 804 enable_fwd = true; 805 if (strcmp(lgopts[opt_idx].name, 806 "portmask") == 0) { 807 /* parse hexadecimal string */ 808 end = NULL; 809 pm = strtoull(optarg, &end, 16); 810 if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0')) 811 rte_exit(EXIT_FAILURE, "Invalid fwd port mask\n"); 812 ports_mask = pm; 813 } 814 if (strcmp(lgopts[opt_idx].name, "rxq") == 0) { 815 n = atoi(optarg); 816 rx_queues_count = (uint8_t) n; 817 } 818 if (strcmp(lgopts[opt_idx].name, "txq") == 0) { 819 n = atoi(optarg); 820 tx_queues_count = (uint8_t) n; 821 } 822 if (strcmp(lgopts[opt_idx].name, "rxd") == 0) { 823 n = atoi(optarg); 824 rxd_count = (uint8_t) n; 825 } 826 if (strcmp(lgopts[opt_idx].name, "txd") == 0) { 827 n = atoi(optarg); 828 txd_count = (uint8_t) n; 829 } 830 if (strcmp(lgopts[opt_idx].name, "mbuf-size") == 0) { 831 n = atoi(optarg); 832 mbuf_size = (uint32_t) n; 833 } 834 if (strcmp(lgopts[opt_idx].name, "mbuf-cache-size") == 0) { 835 n = atoi(optarg); 836 mbuf_cache_size = (uint32_t) n; 837 } 838 if (strcmp(lgopts[opt_idx].name, "total-mbuf-count") == 0) { 839 n = atoi(optarg); 840 total_mbuf_num = (uint32_t) n; 841 } 842 if (strcmp(lgopts[opt_idx].name, "cores") == 0) { 843 n = atoi(optarg); 844 if ((int) rte_lcore_count() <= n) { 845 rte_exit(EXIT_FAILURE, 846 "Error: you need %d cores to run on multi-cores\n" 847 "Existing cores are: %d\n", n, rte_lcore_count()); 848 } 849 if (n <= RTE_MAX_LCORE && n > 0) 850 mc_pool.cores_count = n; 851 else { 852 rte_exit(EXIT_FAILURE, 853 "Error: cores count must be > 0 and < %d\n", 854 RTE_MAX_LCORE); 855 } 856 } 857 break; 858 default: 859 usage(argv[0]); 860 rte_exit(EXIT_FAILURE, "Invalid option: %s\n", 861 argv[optind]); 862 break; 863 } 864 } 865 printf("end_flow\n"); 866 } 867 868 /* Dump the socket memory statistics on console */ 869 static size_t 870 dump_socket_mem(FILE *f) 871 { 872 struct rte_malloc_socket_stats socket_stats; 873 unsigned int i = 0; 874 size_t total = 0; 875 size_t alloc = 0; 876 size_t free = 0; 877 unsigned int n_alloc = 0; 878 unsigned int n_free = 0; 879 bool active_nodes = false; 880 881 882 for (i = 0; i < RTE_MAX_NUMA_NODES; i++) { 883 if (rte_malloc_get_socket_stats(i, &socket_stats) || 884 !socket_stats.heap_totalsz_bytes) 885 continue; 886 active_nodes = true; 887 total += socket_stats.heap_totalsz_bytes; 888 alloc += socket_stats.heap_allocsz_bytes; 889 free += socket_stats.heap_freesz_bytes; 890 n_alloc += socket_stats.alloc_count; 891 n_free += socket_stats.free_count; 892 if (dump_socket_mem_flag) { 893 fprintf(f, "::::::::::::::::::::::::::::::::::::::::"); 894 fprintf(f, 895 "\nSocket %u:\nsize(M) total: %.6lf\nalloc:" 896 " %.6lf(%.3lf%%)\nfree: %.6lf" 897 "\nmax: %.6lf" 898 "\ncount alloc: %u\nfree: %u\n", 899 i, 900 socket_stats.heap_totalsz_bytes / 1.0e6, 901 socket_stats.heap_allocsz_bytes / 1.0e6, 902 (double)socket_stats.heap_allocsz_bytes * 100 / 903 (double)socket_stats.heap_totalsz_bytes, 904 socket_stats.heap_freesz_bytes / 1.0e6, 905 socket_stats.greatest_free_size / 1.0e6, 906 socket_stats.alloc_count, 907 socket_stats.free_count); 908 fprintf(f, "::::::::::::::::::::::::::::::::::::::::"); 909 } 910 } 911 if (dump_socket_mem_flag && active_nodes) { 912 fprintf(f, 913 "\nTotal: size(M)\ntotal: %.6lf" 914 "\nalloc: %.6lf(%.3lf%%)\nfree: %.6lf" 915 "\ncount alloc: %u\nfree: %u\n", 916 total / 1.0e6, alloc / 1.0e6, 917 (double)alloc * 100 / (double)total, free / 1.0e6, 918 n_alloc, n_free); 919 fprintf(f, "::::::::::::::::::::::::::::::::::::::::\n"); 920 } 921 return alloc; 922 } 923 924 static void 925 print_flow_error(struct rte_flow_error error) 926 { 927 printf("Flow can't be created %d message: %s\n", 928 error.type, 929 error.message ? error.message : "(no stated reason)"); 930 } 931 932 static inline void 933 print_rules_batches(double *cpu_time_per_batch) 934 { 935 uint8_t idx; 936 double delta; 937 double rate; 938 939 for (idx = 0; idx < MAX_BATCHES_COUNT; idx++) { 940 if (!cpu_time_per_batch[idx]) 941 break; 942 delta = (double)(rules_batch / cpu_time_per_batch[idx]); 943 rate = delta / 1000; /* Save rate in K unit. */ 944 printf(":: Rules batch #%d: %d rules " 945 "in %f sec[ Rate = %f K Rule/Sec ]\n", 946 idx, rules_batch, 947 cpu_time_per_batch[idx], rate); 948 } 949 } 950 951 952 static inline int 953 has_meter(void) 954 { 955 int i; 956 957 for (i = 0; i < MAX_ACTIONS_NUM; i++) { 958 if (flow_actions[i] == 0) 959 break; 960 if (flow_actions[i] 961 & FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_METER)) 962 return 1; 963 } 964 return 0; 965 } 966 967 static void 968 create_meter_rule(int port_id, uint32_t counter) 969 { 970 int ret; 971 struct rte_mtr_params params; 972 uint32_t default_prof_id = 100; 973 struct rte_mtr_error error; 974 975 memset(¶ms, 0, sizeof(struct rte_mtr_params)); 976 params.meter_enable = 1; 977 params.stats_mask = 0xffff; 978 params.use_prev_mtr_color = 0; 979 params.dscp_table = NULL; 980 981 /*create meter*/ 982 params.meter_profile_id = default_prof_id; 983 ret = rte_mtr_create(port_id, counter, ¶ms, 1, &error); 984 if (ret != 0) { 985 printf("Port %u create meter idx(%d) error(%d) message: %s\n", 986 port_id, counter, error.type, 987 error.message ? error.message : "(no stated reason)"); 988 rte_exit(EXIT_FAILURE, "Error in creating meter\n"); 989 } 990 } 991 992 static void 993 destroy_meter_rule(int port_id, uint32_t counter) 994 { 995 struct rte_mtr_error error; 996 997 if (rte_mtr_destroy(port_id, counter, &error)) { 998 printf("Port %u destroy meter(%d) error(%d) message: %s\n", 999 port_id, counter, error.type, 1000 error.message ? error.message : "(no stated reason)"); 1001 rte_exit(EXIT_FAILURE, "Error in deleting meter rule\n"); 1002 } 1003 } 1004 1005 static void 1006 meters_handler(int port_id, uint8_t core_id, uint8_t ops) 1007 { 1008 uint64_t start_batch; 1009 double cpu_time_used, insertion_rate; 1010 int rules_count_per_core, rules_batch_idx; 1011 uint32_t counter, start_counter = 0, end_counter; 1012 double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 }; 1013 1014 rules_count_per_core = rules_count / mc_pool.cores_count; 1015 1016 if (core_id) 1017 start_counter = core_id * rules_count_per_core; 1018 end_counter = (core_id + 1) * rules_count_per_core; 1019 1020 cpu_time_used = 0; 1021 start_batch = rte_get_timer_cycles(); 1022 for (counter = start_counter; counter < end_counter; counter++) { 1023 if (ops == METER_CREATE) 1024 create_meter_rule(port_id, counter); 1025 else 1026 destroy_meter_rule(port_id, counter); 1027 /* 1028 * Save the insertion rate for rules batch. 1029 * Check if the insertion reached the rules 1030 * patch counter, then save the insertion rate 1031 * for this batch. 1032 */ 1033 if (!((counter + 1) % rules_batch)) { 1034 rules_batch_idx = ((counter + 1) / rules_batch) - 1; 1035 cpu_time_per_batch[rules_batch_idx] = 1036 ((double)(rte_get_timer_cycles() - start_batch)) 1037 / rte_get_timer_hz(); 1038 cpu_time_used += cpu_time_per_batch[rules_batch_idx]; 1039 start_batch = rte_get_timer_cycles(); 1040 } 1041 } 1042 1043 /* Print insertion rates for all batches */ 1044 if (dump_iterations) 1045 print_rules_batches(cpu_time_per_batch); 1046 1047 insertion_rate = 1048 ((double) (rules_count_per_core / cpu_time_used) / 1000); 1049 1050 /* Insertion rate for all rules in one core */ 1051 printf(":: Port %d :: Core %d Meter %s :: start @[%d] - end @[%d]," 1052 " use:%.02fs, rate:%.02fk Rule/Sec\n", 1053 port_id, core_id, ops == METER_CREATE ? "create" : "delete", 1054 start_counter, end_counter - 1, 1055 cpu_time_used, insertion_rate); 1056 1057 if (ops == METER_CREATE) 1058 mc_pool.meters_record.insertion[port_id][core_id] 1059 = cpu_time_used; 1060 else 1061 mc_pool.meters_record.deletion[port_id][core_id] 1062 = cpu_time_used; 1063 } 1064 1065 static void 1066 destroy_meter_profile(void) 1067 { 1068 struct rte_mtr_error error; 1069 uint16_t nr_ports; 1070 int port_id; 1071 1072 nr_ports = rte_eth_dev_count_avail(); 1073 for (port_id = 0; port_id < nr_ports; port_id++) { 1074 /* If port outside portmask */ 1075 if (!((ports_mask >> port_id) & 0x1)) 1076 continue; 1077 1078 if (rte_mtr_meter_profile_delete 1079 (port_id, DEFAULT_METER_PROF_ID, &error)) { 1080 printf("Port %u del profile error(%d) message: %s\n", 1081 port_id, error.type, 1082 error.message ? error.message : "(no stated reason)"); 1083 rte_exit(EXIT_FAILURE, "Error: Destroy meter profile Failed!\n"); 1084 } 1085 } 1086 } 1087 1088 static void 1089 create_meter_profile(void) 1090 { 1091 uint16_t nr_ports; 1092 int ret, port_id; 1093 struct rte_mtr_meter_profile mp; 1094 struct rte_mtr_error error; 1095 1096 /* 1097 *currently , only create one meter file for one port 1098 *1 meter profile -> N meter rules -> N rte flows 1099 */ 1100 memset(&mp, 0, sizeof(struct rte_mtr_meter_profile)); 1101 nr_ports = rte_eth_dev_count_avail(); 1102 for (port_id = 0; port_id < nr_ports; port_id++) { 1103 /* If port outside portmask */ 1104 if (!((ports_mask >> port_id) & 0x1)) 1105 continue; 1106 1107 mp.alg = RTE_MTR_SRTCM_RFC2697; 1108 mp.srtcm_rfc2697.cir = METER_CIR; 1109 mp.srtcm_rfc2697.cbs = METER_CIR / 8; 1110 mp.srtcm_rfc2697.ebs = 0; 1111 1112 ret = rte_mtr_meter_profile_add 1113 (port_id, DEFAULT_METER_PROF_ID, &mp, &error); 1114 if (ret != 0) { 1115 printf("Port %u create Profile error(%d) message: %s\n", 1116 port_id, error.type, 1117 error.message ? error.message : "(no stated reason)"); 1118 rte_exit(EXIT_FAILURE, "Error: Creation meter profile Failed!\n"); 1119 } 1120 } 1121 } 1122 1123 static inline void 1124 destroy_flows(int port_id, uint8_t core_id, struct rte_flow **flows_list) 1125 { 1126 struct rte_flow_error error; 1127 clock_t start_batch, end_batch; 1128 double cpu_time_used = 0; 1129 double deletion_rate; 1130 double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 }; 1131 double delta; 1132 uint32_t i; 1133 int rules_batch_idx; 1134 int rules_count_per_core; 1135 1136 rules_count_per_core = rules_count / mc_pool.cores_count; 1137 /* If group > 0 , should add 1 flow which created in group 0 */ 1138 if (flow_group > 0 && core_id == 0) 1139 rules_count_per_core++; 1140 1141 start_batch = rte_get_timer_cycles(); 1142 for (i = 0; i < (uint32_t) rules_count_per_core; i++) { 1143 if (flows_list[i] == 0) 1144 break; 1145 1146 memset(&error, 0x33, sizeof(error)); 1147 if (rte_flow_destroy(port_id, flows_list[i], &error)) { 1148 print_flow_error(error); 1149 rte_exit(EXIT_FAILURE, "Error in deleting flow\n"); 1150 } 1151 1152 /* 1153 * Save the deletion rate for rules batch. 1154 * Check if the deletion reached the rules 1155 * patch counter, then save the deletion rate 1156 * for this batch. 1157 */ 1158 if (!((i + 1) % rules_batch)) { 1159 end_batch = rte_get_timer_cycles(); 1160 delta = (double) (end_batch - start_batch); 1161 rules_batch_idx = ((i + 1) / rules_batch) - 1; 1162 cpu_time_per_batch[rules_batch_idx] = delta / rte_get_timer_hz(); 1163 cpu_time_used += cpu_time_per_batch[rules_batch_idx]; 1164 start_batch = rte_get_timer_cycles(); 1165 } 1166 } 1167 1168 /* Print deletion rates for all batches */ 1169 if (dump_iterations) 1170 print_rules_batches(cpu_time_per_batch); 1171 1172 /* Deletion rate for all rules */ 1173 deletion_rate = ((double) (rules_count_per_core / cpu_time_used) / 1000); 1174 printf(":: Port %d :: Core %d :: Rules deletion rate -> %f K Rule/Sec\n", 1175 port_id, core_id, deletion_rate); 1176 printf(":: Port %d :: Core %d :: The time for deleting %d rules is %f seconds\n", 1177 port_id, core_id, rules_count_per_core, cpu_time_used); 1178 1179 mc_pool.flows_record.deletion[port_id][core_id] = cpu_time_used; 1180 } 1181 1182 static struct rte_flow ** 1183 insert_flows(int port_id, uint8_t core_id) 1184 { 1185 struct rte_flow **flows_list; 1186 struct rte_flow_error error; 1187 clock_t start_batch, end_batch; 1188 double first_flow_latency; 1189 double cpu_time_used; 1190 double insertion_rate; 1191 double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 }; 1192 double delta; 1193 uint32_t flow_index; 1194 uint32_t counter, start_counter = 0, end_counter; 1195 uint64_t global_items[MAX_ITEMS_NUM] = { 0 }; 1196 uint64_t global_actions[MAX_ACTIONS_NUM] = { 0 }; 1197 int rules_batch_idx; 1198 int rules_count_per_core; 1199 1200 rules_count_per_core = rules_count / mc_pool.cores_count; 1201 1202 /* Set boundaries of rules for each core. */ 1203 if (core_id) 1204 start_counter = core_id * rules_count_per_core; 1205 end_counter = (core_id + 1) * rules_count_per_core; 1206 1207 global_items[0] = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH); 1208 global_actions[0] = FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP); 1209 1210 flows_list = rte_zmalloc("flows_list", 1211 (sizeof(struct rte_flow *) * rules_count_per_core) + 1, 0); 1212 if (flows_list == NULL) 1213 rte_exit(EXIT_FAILURE, "No Memory available!\n"); 1214 1215 cpu_time_used = 0; 1216 flow_index = 0; 1217 if (flow_group > 0 && core_id == 0) { 1218 /* 1219 * Create global rule to jump into flow_group, 1220 * this way the app will avoid the default rules. 1221 * 1222 * This rule will be created only once. 1223 * 1224 * Global rule: 1225 * group 0 eth / end actions jump group <flow_group> 1226 */ 1227 flow = generate_flow(port_id, 0, flow_attrs, 1228 global_items, global_actions, 1229 flow_group, 0, 0, 0, 0, core_id, rx_queues_count, 1230 unique_data, &error); 1231 1232 if (flow == NULL) { 1233 print_flow_error(error); 1234 rte_exit(EXIT_FAILURE, "Error in creating flow\n"); 1235 } 1236 flows_list[flow_index++] = flow; 1237 } 1238 1239 start_batch = rte_get_timer_cycles(); 1240 for (counter = start_counter; counter < end_counter; counter++) { 1241 flow = generate_flow(port_id, flow_group, 1242 flow_attrs, flow_items, flow_actions, 1243 JUMP_ACTION_TABLE, counter, 1244 hairpin_queues_num, 1245 encap_data, decap_data, 1246 core_id, rx_queues_count, 1247 unique_data, &error); 1248 1249 if (!counter) { 1250 first_flow_latency = (double) (rte_get_timer_cycles() - start_batch); 1251 first_flow_latency /= rte_get_timer_hz(); 1252 /* In millisecond */ 1253 first_flow_latency *= 1000; 1254 printf(":: First Flow Latency :: Port %d :: First flow " 1255 "installed in %f milliseconds\n", 1256 port_id, first_flow_latency); 1257 } 1258 1259 if (force_quit) 1260 counter = end_counter; 1261 1262 if (!flow) { 1263 print_flow_error(error); 1264 rte_exit(EXIT_FAILURE, "Error in creating flow\n"); 1265 } 1266 1267 flows_list[flow_index++] = flow; 1268 1269 /* 1270 * Save the insertion rate for rules batch. 1271 * Check if the insertion reached the rules 1272 * patch counter, then save the insertion rate 1273 * for this batch. 1274 */ 1275 if (!((counter + 1) % rules_batch)) { 1276 end_batch = rte_get_timer_cycles(); 1277 delta = (double) (end_batch - start_batch); 1278 rules_batch_idx = ((counter + 1) / rules_batch) - 1; 1279 cpu_time_per_batch[rules_batch_idx] = delta / rte_get_timer_hz(); 1280 cpu_time_used += cpu_time_per_batch[rules_batch_idx]; 1281 start_batch = rte_get_timer_cycles(); 1282 } 1283 } 1284 1285 /* Print insertion rates for all batches */ 1286 if (dump_iterations) 1287 print_rules_batches(cpu_time_per_batch); 1288 1289 printf(":: Port %d :: Core %d boundaries :: start @[%d] - end @[%d]\n", 1290 port_id, core_id, start_counter, end_counter - 1); 1291 1292 /* Insertion rate for all rules in one core */ 1293 insertion_rate = ((double) (rules_count_per_core / cpu_time_used) / 1000); 1294 printf(":: Port %d :: Core %d :: Rules insertion rate -> %f K Rule/Sec\n", 1295 port_id, core_id, insertion_rate); 1296 printf(":: Port %d :: Core %d :: The time for creating %d in rules %f seconds\n", 1297 port_id, core_id, rules_count_per_core, cpu_time_used); 1298 1299 mc_pool.flows_record.insertion[port_id][core_id] = cpu_time_used; 1300 return flows_list; 1301 } 1302 1303 static void 1304 flows_handler(uint8_t core_id) 1305 { 1306 struct rte_flow **flows_list; 1307 uint16_t nr_ports; 1308 int port_id; 1309 1310 nr_ports = rte_eth_dev_count_avail(); 1311 1312 if (rules_batch > rules_count) 1313 rules_batch = rules_count; 1314 1315 printf(":: Rules Count per port: %d\n\n", rules_count); 1316 1317 for (port_id = 0; port_id < nr_ports; port_id++) { 1318 /* If port outside portmask */ 1319 if (!((ports_mask >> port_id) & 0x1)) 1320 continue; 1321 1322 /* Insertion part. */ 1323 mc_pool.last_alloc[core_id] = (int64_t)dump_socket_mem(stdout); 1324 if (has_meter()) 1325 meters_handler(port_id, core_id, METER_CREATE); 1326 flows_list = insert_flows(port_id, core_id); 1327 if (flows_list == NULL) 1328 rte_exit(EXIT_FAILURE, "Error: Insertion Failed!\n"); 1329 mc_pool.current_alloc[core_id] = (int64_t)dump_socket_mem(stdout); 1330 1331 /* Deletion part. */ 1332 if (delete_flag) { 1333 destroy_flows(port_id, core_id, flows_list); 1334 if (has_meter()) 1335 meters_handler(port_id, core_id, METER_DELETE); 1336 } 1337 } 1338 } 1339 1340 static void 1341 dump_used_cpu_time(const char *item, 1342 uint16_t port, struct used_cpu_time *used_time) 1343 { 1344 uint32_t i; 1345 /* Latency: total count of rte rules divided 1346 * over max time used by thread between all 1347 * threads time. 1348 * 1349 * Throughput: total count of rte rules divided 1350 * over the average of the time cosumed by all 1351 * threads time. 1352 */ 1353 double insertion_latency_time; 1354 double insertion_throughput_time; 1355 double deletion_latency_time; 1356 double deletion_throughput_time; 1357 double insertion_latency, insertion_throughput; 1358 double deletion_latency, deletion_throughput; 1359 1360 /* Save first insertion/deletion rates from first thread. 1361 * Start comparing with all threads, if any thread used 1362 * time more than current saved, replace it. 1363 * 1364 * Thus in the end we will have the max time used for 1365 * insertion/deletion by one thread. 1366 * 1367 * As for memory consumption, save the min of all threads 1368 * of last alloc, and save the max for all threads for 1369 * current alloc. 1370 */ 1371 1372 insertion_latency_time = used_time->insertion[port][0]; 1373 deletion_latency_time = used_time->deletion[port][0]; 1374 insertion_throughput_time = used_time->insertion[port][0]; 1375 deletion_throughput_time = used_time->deletion[port][0]; 1376 1377 i = mc_pool.cores_count; 1378 while (i-- > 1) { 1379 insertion_throughput_time += used_time->insertion[port][i]; 1380 deletion_throughput_time += used_time->deletion[port][i]; 1381 if (insertion_latency_time < used_time->insertion[port][i]) 1382 insertion_latency_time = used_time->insertion[port][i]; 1383 if (deletion_latency_time < used_time->deletion[port][i]) 1384 deletion_latency_time = used_time->deletion[port][i]; 1385 } 1386 1387 insertion_latency = ((double) (mc_pool.rules_count 1388 / insertion_latency_time) / 1000); 1389 deletion_latency = ((double) (mc_pool.rules_count 1390 / deletion_latency_time) / 1000); 1391 1392 insertion_throughput_time /= mc_pool.cores_count; 1393 deletion_throughput_time /= mc_pool.cores_count; 1394 insertion_throughput = ((double) (mc_pool.rules_count 1395 / insertion_throughput_time) / 1000); 1396 deletion_throughput = ((double) (mc_pool.rules_count 1397 / deletion_throughput_time) / 1000); 1398 1399 /* Latency stats */ 1400 printf("\n%s\n:: [Latency | Insertion] All Cores :: Port %d :: ", 1401 item, port); 1402 printf("Total flows insertion rate -> %f K Rules/Sec\n", 1403 insertion_latency); 1404 printf(":: [Latency | Insertion] All Cores :: Port %d :: ", port); 1405 printf("The time for creating %d rules is %f seconds\n", 1406 mc_pool.rules_count, insertion_latency_time); 1407 1408 /* Throughput stats */ 1409 printf(":: [Throughput | Insertion] All Cores :: Port %d :: ", port); 1410 printf("Total flows insertion rate -> %f K Rules/Sec\n", 1411 insertion_throughput); 1412 printf(":: [Throughput | Insertion] All Cores :: Port %d :: ", port); 1413 printf("The average time for creating %d rules is %f seconds\n", 1414 mc_pool.rules_count, insertion_throughput_time); 1415 1416 if (delete_flag) { 1417 /* Latency stats */ 1418 printf(":: [Latency | Deletion] All Cores :: Port %d :: Total " 1419 "deletion rate -> %f K Rules/Sec\n", 1420 port, deletion_latency); 1421 printf(":: [Latency | Deletion] All Cores :: Port %d :: ", 1422 port); 1423 printf("The time for deleting %d rules is %f seconds\n", 1424 mc_pool.rules_count, deletion_latency_time); 1425 1426 /* Throughput stats */ 1427 printf(":: [Throughput | Deletion] All Cores :: Port %d :: Total " 1428 "deletion rate -> %f K Rules/Sec\n", 1429 port, deletion_throughput); 1430 printf(":: [Throughput | Deletion] All Cores :: Port %d :: ", 1431 port); 1432 printf("The average time for deleting %d rules is %f seconds\n", 1433 mc_pool.rules_count, deletion_throughput_time); 1434 } 1435 } 1436 1437 static void 1438 dump_used_mem(uint16_t port) 1439 { 1440 uint32_t i; 1441 int64_t last_alloc, current_alloc; 1442 int flow_size_in_bytes; 1443 1444 last_alloc = mc_pool.last_alloc[0]; 1445 current_alloc = mc_pool.current_alloc[0]; 1446 1447 i = mc_pool.cores_count; 1448 while (i-- > 1) { 1449 if (last_alloc > mc_pool.last_alloc[i]) 1450 last_alloc = mc_pool.last_alloc[i]; 1451 if (current_alloc < mc_pool.current_alloc[i]) 1452 current_alloc = mc_pool.current_alloc[i]; 1453 } 1454 1455 flow_size_in_bytes = (current_alloc - last_alloc) / mc_pool.rules_count; 1456 printf("\n:: Port %d :: rte_flow size in DPDK layer: %d Bytes\n", 1457 port, flow_size_in_bytes); 1458 } 1459 1460 static int 1461 run_rte_flow_handler_cores(void *data __rte_unused) 1462 { 1463 uint16_t port; 1464 int lcore_counter = 0; 1465 int lcore_id = rte_lcore_id(); 1466 int i; 1467 1468 RTE_LCORE_FOREACH(i) { 1469 /* If core not needed return. */ 1470 if (lcore_id == i) { 1471 printf(":: lcore %d mapped with index %d\n", lcore_id, lcore_counter); 1472 if (lcore_counter >= (int) mc_pool.cores_count) 1473 return 0; 1474 break; 1475 } 1476 lcore_counter++; 1477 } 1478 lcore_id = lcore_counter; 1479 1480 if (lcore_id >= (int) mc_pool.cores_count) 1481 return 0; 1482 1483 mc_pool.rules_count = rules_count; 1484 1485 flows_handler(lcore_id); 1486 1487 /* Only main core to print total results. */ 1488 if (lcore_id != 0) 1489 return 0; 1490 1491 /* Make sure all cores finished insertion/deletion process. */ 1492 rte_eal_mp_wait_lcore(); 1493 1494 RTE_ETH_FOREACH_DEV(port) { 1495 /* If port outside portmask */ 1496 if (!((ports_mask >> port) & 0x1)) 1497 continue; 1498 if (has_meter()) 1499 dump_used_cpu_time("Meters:", 1500 port, &mc_pool.meters_record); 1501 dump_used_cpu_time("Flows:", 1502 port, &mc_pool.flows_record); 1503 dump_used_mem(port); 1504 } 1505 1506 return 0; 1507 } 1508 1509 static void 1510 signal_handler(int signum) 1511 { 1512 if (signum == SIGINT || signum == SIGTERM) { 1513 printf("\n\nSignal %d received, preparing to exit...\n", 1514 signum); 1515 printf("Error: Stats are wrong due to sudden signal!\n\n"); 1516 force_quit = true; 1517 } 1518 } 1519 1520 static inline uint16_t 1521 do_rx(struct lcore_info *li, uint16_t rx_port, uint16_t rx_queue) 1522 { 1523 uint16_t cnt = 0; 1524 cnt = rte_eth_rx_burst(rx_port, rx_queue, li->pkts, MAX_PKT_BURST); 1525 li->rx_pkts += cnt; 1526 return cnt; 1527 } 1528 1529 static inline void 1530 do_tx(struct lcore_info *li, uint16_t cnt, uint16_t tx_port, 1531 uint16_t tx_queue) 1532 { 1533 uint16_t nr_tx = 0; 1534 uint16_t i; 1535 1536 nr_tx = rte_eth_tx_burst(tx_port, tx_queue, li->pkts, cnt); 1537 li->tx_pkts += nr_tx; 1538 li->tx_drops += cnt - nr_tx; 1539 1540 for (i = nr_tx; i < cnt; i++) 1541 rte_pktmbuf_free(li->pkts[i]); 1542 } 1543 1544 /* 1545 * Method to convert numbers into pretty numbers that easy 1546 * to read. The design here is to add comma after each three 1547 * digits and set all of this inside buffer. 1548 * 1549 * For example if n = 1799321, the output will be 1550 * 1,799,321 after this method which is easier to read. 1551 */ 1552 static char * 1553 pretty_number(uint64_t n, char *buf) 1554 { 1555 char p[6][4]; 1556 int i = 0; 1557 int off = 0; 1558 1559 while (n > 1000) { 1560 sprintf(p[i], "%03d", (int)(n % 1000)); 1561 n /= 1000; 1562 i += 1; 1563 } 1564 1565 sprintf(p[i++], "%d", (int)n); 1566 1567 while (i--) 1568 off += sprintf(buf + off, "%s,", p[i]); 1569 buf[strlen(buf) - 1] = '\0'; 1570 1571 return buf; 1572 } 1573 1574 static void 1575 packet_per_second_stats(void) 1576 { 1577 struct lcore_info *old; 1578 struct lcore_info *li, *oli; 1579 int nr_lines = 0; 1580 int i; 1581 1582 old = rte_zmalloc("old", 1583 sizeof(struct lcore_info) * RTE_MAX_LCORE, 0); 1584 if (old == NULL) 1585 rte_exit(EXIT_FAILURE, "No Memory available!\n"); 1586 1587 memcpy(old, lcore_infos, 1588 sizeof(struct lcore_info) * RTE_MAX_LCORE); 1589 1590 while (!force_quit) { 1591 uint64_t total_tx_pkts = 0; 1592 uint64_t total_rx_pkts = 0; 1593 uint64_t total_tx_drops = 0; 1594 uint64_t tx_delta, rx_delta, drops_delta; 1595 char buf[3][32]; 1596 int nr_valid_core = 0; 1597 1598 sleep(1); 1599 1600 if (nr_lines) { 1601 char go_up_nr_lines[16]; 1602 1603 sprintf(go_up_nr_lines, "%c[%dA\r", 27, nr_lines); 1604 printf("%s\r", go_up_nr_lines); 1605 } 1606 1607 printf("\n%6s %16s %16s %16s\n", "core", "tx", "tx drops", "rx"); 1608 printf("%6s %16s %16s %16s\n", "------", "----------------", 1609 "----------------", "----------------"); 1610 nr_lines = 3; 1611 for (i = 0; i < RTE_MAX_LCORE; i++) { 1612 li = &lcore_infos[i]; 1613 oli = &old[i]; 1614 if (li->mode != LCORE_MODE_PKT) 1615 continue; 1616 1617 tx_delta = li->tx_pkts - oli->tx_pkts; 1618 rx_delta = li->rx_pkts - oli->rx_pkts; 1619 drops_delta = li->tx_drops - oli->tx_drops; 1620 printf("%6d %16s %16s %16s\n", i, 1621 pretty_number(tx_delta, buf[0]), 1622 pretty_number(drops_delta, buf[1]), 1623 pretty_number(rx_delta, buf[2])); 1624 1625 total_tx_pkts += tx_delta; 1626 total_rx_pkts += rx_delta; 1627 total_tx_drops += drops_delta; 1628 1629 nr_valid_core++; 1630 nr_lines += 1; 1631 } 1632 1633 if (nr_valid_core > 1) { 1634 printf("%6s %16s %16s %16s\n", "total", 1635 pretty_number(total_tx_pkts, buf[0]), 1636 pretty_number(total_tx_drops, buf[1]), 1637 pretty_number(total_rx_pkts, buf[2])); 1638 nr_lines += 1; 1639 } 1640 1641 memcpy(old, lcore_infos, 1642 sizeof(struct lcore_info) * RTE_MAX_LCORE); 1643 } 1644 } 1645 1646 static int 1647 start_forwarding(void *data __rte_unused) 1648 { 1649 int lcore = rte_lcore_id(); 1650 int stream_id; 1651 uint16_t cnt; 1652 struct lcore_info *li = &lcore_infos[lcore]; 1653 1654 if (!li->mode) 1655 return 0; 1656 1657 if (li->mode == LCORE_MODE_STATS) { 1658 printf(":: started stats on lcore %u\n", lcore); 1659 packet_per_second_stats(); 1660 return 0; 1661 } 1662 1663 while (!force_quit) 1664 for (stream_id = 0; stream_id < MAX_STREAMS; stream_id++) { 1665 if (li->streams[stream_id].rx_port == -1) 1666 continue; 1667 1668 cnt = do_rx(li, 1669 li->streams[stream_id].rx_port, 1670 li->streams[stream_id].rx_queue); 1671 if (cnt) 1672 do_tx(li, cnt, 1673 li->streams[stream_id].tx_port, 1674 li->streams[stream_id].tx_queue); 1675 } 1676 return 0; 1677 } 1678 1679 static void 1680 init_lcore_info(void) 1681 { 1682 int i, j; 1683 unsigned int lcore; 1684 uint16_t nr_port; 1685 uint16_t queue; 1686 int port; 1687 int stream_id = 0; 1688 int streams_per_core; 1689 int unassigned_streams; 1690 int nb_fwd_streams; 1691 nr_port = rte_eth_dev_count_avail(); 1692 1693 /* First logical core is reserved for stats printing */ 1694 lcore = rte_get_next_lcore(-1, 0, 0); 1695 lcore_infos[lcore].mode = LCORE_MODE_STATS; 1696 1697 /* 1698 * Initialize all cores 1699 * All cores at first must have -1 value in all streams 1700 * This means that this stream is not used, or not set 1701 * yet. 1702 */ 1703 for (i = 0; i < RTE_MAX_LCORE; i++) 1704 for (j = 0; j < MAX_STREAMS; j++) { 1705 lcore_infos[i].streams[j].tx_port = -1; 1706 lcore_infos[i].streams[j].rx_port = -1; 1707 lcore_infos[i].streams[j].tx_queue = -1; 1708 lcore_infos[i].streams[j].rx_queue = -1; 1709 lcore_infos[i].streams_nb = 0; 1710 } 1711 1712 /* 1713 * Calculate the total streams count. 1714 * Also distribute those streams count between the available 1715 * logical cores except first core, since it's reserved for 1716 * stats prints. 1717 */ 1718 nb_fwd_streams = nr_port * rx_queues_count; 1719 if ((int)(nb_lcores - 1) >= nb_fwd_streams) 1720 for (i = 0; i < (int)(nb_lcores - 1); i++) { 1721 lcore = rte_get_next_lcore(lcore, 0, 0); 1722 lcore_infos[lcore].streams_nb = 1; 1723 } 1724 else { 1725 streams_per_core = nb_fwd_streams / (nb_lcores - 1); 1726 unassigned_streams = nb_fwd_streams % (nb_lcores - 1); 1727 for (i = 0; i < (int)(nb_lcores - 1); i++) { 1728 lcore = rte_get_next_lcore(lcore, 0, 0); 1729 lcore_infos[lcore].streams_nb = streams_per_core; 1730 if (unassigned_streams) { 1731 lcore_infos[lcore].streams_nb++; 1732 unassigned_streams--; 1733 } 1734 } 1735 } 1736 1737 /* 1738 * Set the streams for the cores according to each logical 1739 * core stream count. 1740 * The streams is built on the design of what received should 1741 * forward as well, this means that if you received packets on 1742 * port 0 queue 0 then the same queue should forward the 1743 * packets, using the same logical core. 1744 */ 1745 lcore = rte_get_next_lcore(-1, 0, 0); 1746 for (port = 0; port < nr_port; port++) { 1747 /* Create FWD stream */ 1748 for (queue = 0; queue < rx_queues_count; queue++) { 1749 if (!lcore_infos[lcore].streams_nb || 1750 !(stream_id % lcore_infos[lcore].streams_nb)) { 1751 lcore = rte_get_next_lcore(lcore, 0, 0); 1752 lcore_infos[lcore].mode = LCORE_MODE_PKT; 1753 stream_id = 0; 1754 } 1755 lcore_infos[lcore].streams[stream_id].rx_queue = queue; 1756 lcore_infos[lcore].streams[stream_id].tx_queue = queue; 1757 lcore_infos[lcore].streams[stream_id].rx_port = port; 1758 lcore_infos[lcore].streams[stream_id].tx_port = port; 1759 stream_id++; 1760 } 1761 } 1762 1763 /* Print all streams */ 1764 printf(":: Stream -> core id[N]: (rx_port, rx_queue)->(tx_port, tx_queue)\n"); 1765 for (i = 0; i < RTE_MAX_LCORE; i++) 1766 for (j = 0; j < MAX_STREAMS; j++) { 1767 /* No streams for this core */ 1768 if (lcore_infos[i].streams[j].tx_port == -1) 1769 break; 1770 printf("Stream -> core id[%d]: (%d,%d)->(%d,%d)\n", 1771 i, 1772 lcore_infos[i].streams[j].rx_port, 1773 lcore_infos[i].streams[j].rx_queue, 1774 lcore_infos[i].streams[j].tx_port, 1775 lcore_infos[i].streams[j].tx_queue); 1776 } 1777 } 1778 1779 static void 1780 init_port(void) 1781 { 1782 int ret; 1783 uint16_t std_queue; 1784 uint16_t hairpin_queue; 1785 uint16_t port_id; 1786 uint16_t nr_ports; 1787 uint16_t nr_queues; 1788 struct rte_eth_hairpin_conf hairpin_conf = { 1789 .peer_count = 1, 1790 }; 1791 struct rte_eth_conf port_conf = { 1792 .rx_adv_conf = { 1793 .rss_conf.rss_hf = 1794 GET_RSS_HF(), 1795 } 1796 }; 1797 struct rte_eth_txconf txq_conf; 1798 struct rte_eth_rxconf rxq_conf; 1799 struct rte_eth_dev_info dev_info; 1800 1801 nr_queues = rx_queues_count; 1802 if (hairpin_queues_num != 0) 1803 nr_queues = rx_queues_count + hairpin_queues_num; 1804 1805 nr_ports = rte_eth_dev_count_avail(); 1806 if (nr_ports == 0) 1807 rte_exit(EXIT_FAILURE, "Error: no port detected\n"); 1808 1809 mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool", 1810 total_mbuf_num, mbuf_cache_size, 1811 0, mbuf_size, 1812 rte_socket_id()); 1813 if (mbuf_mp == NULL) 1814 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n"); 1815 1816 for (port_id = 0; port_id < nr_ports; port_id++) { 1817 uint64_t rx_metadata = 0; 1818 1819 rx_metadata |= RTE_ETH_RX_METADATA_USER_FLAG; 1820 rx_metadata |= RTE_ETH_RX_METADATA_USER_MARK; 1821 1822 ret = rte_eth_rx_metadata_negotiate(port_id, &rx_metadata); 1823 if (ret == 0) { 1824 if (!(rx_metadata & RTE_ETH_RX_METADATA_USER_FLAG)) { 1825 printf(":: flow action FLAG will not affect Rx mbufs on port=%u\n", 1826 port_id); 1827 } 1828 1829 if (!(rx_metadata & RTE_ETH_RX_METADATA_USER_MARK)) { 1830 printf(":: flow action MARK will not affect Rx mbufs on port=%u\n", 1831 port_id); 1832 } 1833 } else if (ret != -ENOTSUP) { 1834 rte_exit(EXIT_FAILURE, "Error when negotiating Rx meta features on port=%u: %s\n", 1835 port_id, rte_strerror(-ret)); 1836 } 1837 1838 ret = rte_eth_dev_info_get(port_id, &dev_info); 1839 if (ret != 0) 1840 rte_exit(EXIT_FAILURE, 1841 "Error during getting device" 1842 " (port %u) info: %s\n", 1843 port_id, strerror(-ret)); 1844 1845 port_conf.txmode.offloads &= dev_info.tx_offload_capa; 1846 port_conf.rxmode.offloads &= dev_info.rx_offload_capa; 1847 1848 printf(":: initializing port: %d\n", port_id); 1849 1850 ret = rte_eth_dev_configure(port_id, nr_queues, 1851 nr_queues, &port_conf); 1852 if (ret < 0) 1853 rte_exit(EXIT_FAILURE, 1854 ":: cannot configure device: err=%d, port=%u\n", 1855 ret, port_id); 1856 1857 rxq_conf = dev_info.default_rxconf; 1858 for (std_queue = 0; std_queue < rx_queues_count; std_queue++) { 1859 ret = rte_eth_rx_queue_setup(port_id, std_queue, rxd_count, 1860 rte_eth_dev_socket_id(port_id), 1861 &rxq_conf, 1862 mbuf_mp); 1863 if (ret < 0) 1864 rte_exit(EXIT_FAILURE, 1865 ":: Rx queue setup failed: err=%d, port=%u\n", 1866 ret, port_id); 1867 } 1868 1869 txq_conf = dev_info.default_txconf; 1870 for (std_queue = 0; std_queue < tx_queues_count; std_queue++) { 1871 ret = rte_eth_tx_queue_setup(port_id, std_queue, txd_count, 1872 rte_eth_dev_socket_id(port_id), 1873 &txq_conf); 1874 if (ret < 0) 1875 rte_exit(EXIT_FAILURE, 1876 ":: Tx queue setup failed: err=%d, port=%u\n", 1877 ret, port_id); 1878 } 1879 1880 /* Catch all packets from traffic generator. */ 1881 ret = rte_eth_promiscuous_enable(port_id); 1882 if (ret != 0) 1883 rte_exit(EXIT_FAILURE, 1884 ":: promiscuous mode enable failed: err=%s, port=%u\n", 1885 rte_strerror(-ret), port_id); 1886 1887 if (hairpin_queues_num != 0) { 1888 /* 1889 * Configure peer which represents hairpin Tx. 1890 * Hairpin queue numbers start after standard queues 1891 * (rx_queues_count and tx_queues_count). 1892 */ 1893 for (hairpin_queue = rx_queues_count, std_queue = 0; 1894 hairpin_queue < nr_queues; 1895 hairpin_queue++, std_queue++) { 1896 hairpin_conf.peers[0].port = port_id; 1897 hairpin_conf.peers[0].queue = 1898 std_queue + tx_queues_count; 1899 ret = rte_eth_rx_hairpin_queue_setup( 1900 port_id, hairpin_queue, 1901 rxd_count, &hairpin_conf); 1902 if (ret != 0) 1903 rte_exit(EXIT_FAILURE, 1904 ":: Hairpin rx queue setup failed: err=%d, port=%u\n", 1905 ret, port_id); 1906 } 1907 1908 for (hairpin_queue = tx_queues_count, std_queue = 0; 1909 hairpin_queue < nr_queues; 1910 hairpin_queue++, std_queue++) { 1911 hairpin_conf.peers[0].port = port_id; 1912 hairpin_conf.peers[0].queue = 1913 std_queue + rx_queues_count; 1914 ret = rte_eth_tx_hairpin_queue_setup( 1915 port_id, hairpin_queue, 1916 txd_count, &hairpin_conf); 1917 if (ret != 0) 1918 rte_exit(EXIT_FAILURE, 1919 ":: Hairpin tx queue setup failed: err=%d, port=%u\n", 1920 ret, port_id); 1921 } 1922 } 1923 1924 ret = rte_eth_dev_start(port_id); 1925 if (ret < 0) 1926 rte_exit(EXIT_FAILURE, 1927 "rte_eth_dev_start:err=%d, port=%u\n", 1928 ret, port_id); 1929 1930 printf(":: initializing port: %d done\n", port_id); 1931 } 1932 } 1933 1934 int 1935 main(int argc, char **argv) 1936 { 1937 int ret; 1938 uint16_t port; 1939 struct rte_flow_error error; 1940 1941 ret = rte_eal_init(argc, argv); 1942 if (ret < 0) 1943 rte_exit(EXIT_FAILURE, "EAL init failed\n"); 1944 1945 force_quit = false; 1946 dump_iterations = false; 1947 rules_count = DEFAULT_RULES_COUNT; 1948 rules_batch = DEFAULT_RULES_BATCH; 1949 delete_flag = false; 1950 dump_socket_mem_flag = false; 1951 flow_group = DEFAULT_GROUP; 1952 unique_data = false; 1953 1954 rx_queues_count = (uint8_t) RXQ_NUM; 1955 tx_queues_count = (uint8_t) TXQ_NUM; 1956 rxd_count = (uint8_t) NR_RXD; 1957 txd_count = (uint8_t) NR_TXD; 1958 mbuf_size = (uint32_t) MBUF_SIZE; 1959 mbuf_cache_size = (uint32_t) MBUF_CACHE_SIZE; 1960 total_mbuf_num = (uint32_t) TOTAL_MBUF_NUM; 1961 1962 signal(SIGINT, signal_handler); 1963 signal(SIGTERM, signal_handler); 1964 1965 argc -= ret; 1966 argv += ret; 1967 if (argc > 1) 1968 args_parse(argc, argv); 1969 1970 init_port(); 1971 1972 nb_lcores = rte_lcore_count(); 1973 if (nb_lcores <= 1) 1974 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n"); 1975 1976 printf(":: Flows Count per port: %d\n\n", rules_count); 1977 1978 if (has_meter()) 1979 create_meter_profile(); 1980 rte_eal_mp_remote_launch(run_rte_flow_handler_cores, NULL, CALL_MAIN); 1981 1982 if (enable_fwd) { 1983 init_lcore_info(); 1984 rte_eal_mp_remote_launch(start_forwarding, NULL, CALL_MAIN); 1985 } 1986 if (has_meter() && delete_flag) 1987 destroy_meter_profile(); 1988 1989 RTE_ETH_FOREACH_DEV(port) { 1990 rte_flow_flush(port, &error); 1991 if (rte_eth_dev_stop(port) != 0) 1992 printf("Failed to stop device on port %u\n", port); 1993 rte_eth_dev_close(port); 1994 } 1995 printf("\nBye ...\n"); 1996 return 0; 1997 } 1998