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