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