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