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