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