1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020 Mellanox Technologies, Ltd
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/
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
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.
32 #include <rte_malloc.h>
33 #include <rte_mempool.h>
35 #include <rte_ethdev.h>
41 #define MAX_BATCHES_COUNT 100
42 #define DEFAULT_RULES_COUNT 4000000
43 #define DEFAULT_RULES_BATCH 100000
44 #define DEFAULT_GROUP 0
46 struct rte_flow *flow;
47 static uint8_t flow_group;
49 static uint64_t encap_data;
50 static uint64_t decap_data;
52 static uint64_t flow_items[MAX_ITEMS_NUM];
53 static uint64_t flow_actions[MAX_ACTIONS_NUM];
54 static uint64_t flow_attrs[MAX_ATTRS_NUM];
55 static uint8_t items_idx, actions_idx, attrs_idx;
57 static uint64_t ports_mask;
58 static volatile bool force_quit;
59 static bool dump_iterations;
60 static bool delete_flag;
61 static bool dump_socket_mem_flag;
62 static bool enable_fwd;
64 static struct rte_mempool *mbuf_mp;
65 static uint32_t nb_lcores;
66 static uint32_t rules_count;
67 static uint32_t rules_batch;
68 static uint32_t hairpin_queues_num; /* total hairpin q number - default: 0 */
69 static uint32_t nb_lcores;
71 #define MAX_PKT_BURST 32
72 #define LCORE_MODE_PKT 1
73 #define LCORE_MODE_STATS 2
74 #define MAX_STREAMS 64
86 struct stream streams[MAX_STREAMS];
91 struct rte_mbuf *pkts[MAX_PKT_BURST];
92 } __rte_cache_aligned;
94 static struct lcore_info lcore_infos[RTE_MAX_LCORE];
96 struct used_cpu_time {
97 double insertion[MAX_PORTS][RTE_MAX_LCORE];
98 double deletion[MAX_PORTS][RTE_MAX_LCORE];
101 struct multi_cores_pool {
102 uint32_t cores_count;
103 uint32_t rules_count;
104 struct used_cpu_time create_meter;
105 struct used_cpu_time create_flow;
106 int64_t last_alloc[RTE_MAX_LCORE];
107 int64_t current_alloc[RTE_MAX_LCORE];
108 } __rte_cache_aligned;
110 static struct multi_cores_pool mc_pool = {
115 usage(char *progname)
117 printf("\nusage: %s\n", progname);
118 printf("\nControl configurations:\n");
119 printf(" --rules-count=N: to set the number of needed"
120 " rules to insert, default is %d\n", DEFAULT_RULES_COUNT);
121 printf(" --rules-batch=N: set number of batched rules,"
122 " default is %d\n", DEFAULT_RULES_BATCH);
123 printf(" --dump-iterations: To print rates for each"
125 printf(" --deletion-rate: Enable deletion rate"
127 printf(" --dump-socket-mem: To dump all socket memory\n");
128 printf(" --enable-fwd: To enable packets forwarding"
129 " after insertion\n");
130 printf(" --portmask=N: hexadecimal bitmask of ports used\n");
132 printf("To set flow attributes:\n");
133 printf(" --ingress: set ingress attribute in flows\n");
134 printf(" --egress: set egress attribute in flows\n");
135 printf(" --transfer: set transfer attribute in flows\n");
136 printf(" --group=N: set group for all flows,"
137 " default is %d\n", DEFAULT_GROUP);
138 printf(" --cores=N: to set the number of needed "
139 "cores to insert rte_flow rules, default is 1\n");
141 printf("To set flow items:\n");
142 printf(" --ether: add ether layer in flow items\n");
143 printf(" --vlan: add vlan layer in flow items\n");
144 printf(" --ipv4: add ipv4 layer in flow items\n");
145 printf(" --ipv6: add ipv6 layer in flow items\n");
146 printf(" --tcp: add tcp layer in flow items\n");
147 printf(" --udp: add udp layer in flow items\n");
148 printf(" --vxlan: add vxlan layer in flow items\n");
149 printf(" --vxlan-gpe: add vxlan-gpe layer in flow items\n");
150 printf(" --gre: add gre layer in flow items\n");
151 printf(" --geneve: add geneve layer in flow items\n");
152 printf(" --gtp: add gtp layer in flow items\n");
153 printf(" --meta: add meta layer in flow items\n");
154 printf(" --tag: add tag layer in flow items\n");
155 printf(" --icmpv4: add icmpv4 layer in flow items\n");
156 printf(" --icmpv6: add icmpv6 layer in flow items\n");
158 printf("To set flow actions:\n");
159 printf(" --port-id: add port-id action in flow actions\n");
160 printf(" --rss: add rss action in flow actions\n");
161 printf(" --queue: add queue action in flow actions\n");
162 printf(" --jump: add jump action in flow actions\n");
163 printf(" --mark: add mark action in flow actions\n");
164 printf(" --count: add count action in flow actions\n");
165 printf(" --set-meta: add set meta action in flow actions\n");
166 printf(" --set-tag: add set tag action in flow actions\n");
167 printf(" --drop: add drop action in flow actions\n");
168 printf(" --hairpin-queue=N: add hairpin-queue action in flow actions\n");
169 printf(" --hairpin-rss=N: add hairpin-rss action in flow actions\n");
170 printf(" --set-src-mac: add set src mac action to flow actions\n"
171 "Src mac to be set is random each flow\n");
172 printf(" --set-dst-mac: add set dst mac action to flow actions\n"
173 "Dst mac to be set is random each flow\n");
174 printf(" --set-src-ipv4: add set src ipv4 action to flow actions\n"
175 "Src ipv4 to be set is random each flow\n");
176 printf(" --set-dst-ipv4 add set dst ipv4 action to flow actions\n"
177 "Dst ipv4 to be set is random each flow\n");
178 printf(" --set-src-ipv6: add set src ipv6 action to flow actions\n"
179 "Src ipv6 to be set is random each flow\n");
180 printf(" --set-dst-ipv6: add set dst ipv6 action to flow actions\n"
181 "Dst ipv6 to be set is random each flow\n");
182 printf(" --set-src-tp: add set src tp action to flow actions\n"
183 "Src tp to be set is random each flow\n");
184 printf(" --set-dst-tp: add set dst tp action to flow actions\n"
185 "Dst tp to be set is random each flow\n");
186 printf(" --inc-tcp-ack: add inc tcp ack action to flow actions\n"
187 "tcp ack will be increments by 1\n");
188 printf(" --dec-tcp-ack: add dec tcp ack action to flow actions\n"
189 "tcp ack will be decrements by 1\n");
190 printf(" --inc-tcp-seq: add inc tcp seq action to flow actions\n"
191 "tcp seq will be increments by 1\n");
192 printf(" --dec-tcp-seq: add dec tcp seq action to flow actions\n"
193 "tcp seq will be decrements by 1\n");
194 printf(" --set-ttl: add set ttl action to flow actions\n"
195 "L3 ttl to be set is random each flow\n");
196 printf(" --dec-ttl: add dec ttl action to flow actions\n"
197 "L3 ttl will be decrements by 1\n");
198 printf(" --set-ipv4-dscp: add set ipv4 dscp action to flow actions\n"
199 "ipv4 dscp value to be set is random each flow\n");
200 printf(" --set-ipv6-dscp: add set ipv6 dscp action to flow actions\n"
201 "ipv6 dscp value to be set is random each flow\n");
202 printf(" --flag: add flag action to flow actions\n");
203 printf(" --raw-encap=<data>: add raw encap action to flow actions\n"
204 "Data is the data needed to be encaped\n"
205 "Example: raw-encap=ether,ipv4,udp,vxlan\n");
206 printf(" --raw-decap=<data>: add raw decap action to flow actions\n"
207 "Data is the data needed to be decaped\n"
208 "Example: raw-decap=ether,ipv4,udp,vxlan\n");
209 printf(" --vxlan-encap: add vxlan-encap action to flow actions\n"
210 "Encapped data is fixed with pattern: ether,ipv4,udp,vxlan\n"
211 "With fixed values\n");
212 printf(" --vxlan-decap: add vxlan_decap action to flow actions\n");
216 args_parse(int argc, char **argv)
226 static const struct option_dict {
235 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH),
236 .map = &flow_items[0],
237 .map_idx = &items_idx
241 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV4),
242 .map = &flow_items[0],
243 .map_idx = &items_idx
247 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV6),
248 .map = &flow_items[0],
249 .map_idx = &items_idx
253 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VLAN),
254 .map = &flow_items[0],
255 .map_idx = &items_idx
259 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TCP),
260 .map = &flow_items[0],
261 .map_idx = &items_idx
265 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_UDP),
266 .map = &flow_items[0],
267 .map_idx = &items_idx
271 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN),
272 .map = &flow_items[0],
273 .map_idx = &items_idx
277 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN_GPE),
278 .map = &flow_items[0],
279 .map_idx = &items_idx
283 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GRE),
284 .map = &flow_items[0],
285 .map_idx = &items_idx
289 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GENEVE),
290 .map = &flow_items[0],
291 .map_idx = &items_idx
295 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GTP),
296 .map = &flow_items[0],
297 .map_idx = &items_idx
301 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_META),
302 .map = &flow_items[0],
303 .map_idx = &items_idx
307 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TAG),
308 .map = &flow_items[0],
309 .map_idx = &items_idx
313 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ICMP),
314 .map = &flow_items[0],
315 .map_idx = &items_idx
319 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ICMP6),
320 .map = &flow_items[0],
321 .map_idx = &items_idx
326 .map = &flow_attrs[0],
327 .map_idx = &attrs_idx
332 .map = &flow_attrs[0],
333 .map_idx = &attrs_idx
338 .map = &flow_attrs[0],
339 .map_idx = &attrs_idx
343 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_PORT_ID),
344 .map = &flow_actions[0],
345 .map_idx = &actions_idx
349 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_RSS),
350 .map = &flow_actions[0],
351 .map_idx = &actions_idx
355 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_QUEUE),
356 .map = &flow_actions[0],
357 .map_idx = &actions_idx
361 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_JUMP),
362 .map = &flow_actions[0],
363 .map_idx = &actions_idx
367 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_MARK),
368 .map = &flow_actions[0],
369 .map_idx = &actions_idx
373 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_COUNT),
374 .map = &flow_actions[0],
375 .map_idx = &actions_idx
379 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_META),
380 .map = &flow_actions[0],
381 .map_idx = &actions_idx
385 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_TAG),
386 .map = &flow_actions[0],
387 .map_idx = &actions_idx
391 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_DROP),
392 .map = &flow_actions[0],
393 .map_idx = &actions_idx
396 .str = "set-src-mac",
397 .mask = FLOW_ACTION_MASK(
398 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC
400 .map = &flow_actions[0],
401 .map_idx = &actions_idx
404 .str = "set-dst-mac",
405 .mask = FLOW_ACTION_MASK(
406 RTE_FLOW_ACTION_TYPE_SET_MAC_DST
408 .map = &flow_actions[0],
409 .map_idx = &actions_idx
412 .str = "set-src-ipv4",
413 .mask = FLOW_ACTION_MASK(
414 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC
416 .map = &flow_actions[0],
417 .map_idx = &actions_idx
420 .str = "set-dst-ipv4",
421 .mask = FLOW_ACTION_MASK(
422 RTE_FLOW_ACTION_TYPE_SET_IPV4_DST
424 .map = &flow_actions[0],
425 .map_idx = &actions_idx
428 .str = "set-src-ipv6",
429 .mask = FLOW_ACTION_MASK(
430 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC
432 .map = &flow_actions[0],
433 .map_idx = &actions_idx
436 .str = "set-dst-ipv6",
437 .mask = FLOW_ACTION_MASK(
438 RTE_FLOW_ACTION_TYPE_SET_IPV6_DST
440 .map = &flow_actions[0],
441 .map_idx = &actions_idx
445 .mask = FLOW_ACTION_MASK(
446 RTE_FLOW_ACTION_TYPE_SET_TP_SRC
448 .map = &flow_actions[0],
449 .map_idx = &actions_idx
453 .mask = FLOW_ACTION_MASK(
454 RTE_FLOW_ACTION_TYPE_SET_TP_DST
456 .map = &flow_actions[0],
457 .map_idx = &actions_idx
460 .str = "inc-tcp-ack",
461 .mask = FLOW_ACTION_MASK(
462 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK
464 .map = &flow_actions[0],
465 .map_idx = &actions_idx
468 .str = "dec-tcp-ack",
469 .mask = FLOW_ACTION_MASK(
470 RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK
472 .map = &flow_actions[0],
473 .map_idx = &actions_idx
476 .str = "inc-tcp-seq",
477 .mask = FLOW_ACTION_MASK(
478 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ
480 .map = &flow_actions[0],
481 .map_idx = &actions_idx
484 .str = "dec-tcp-seq",
485 .mask = FLOW_ACTION_MASK(
486 RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ
488 .map = &flow_actions[0],
489 .map_idx = &actions_idx
493 .mask = FLOW_ACTION_MASK(
494 RTE_FLOW_ACTION_TYPE_SET_TTL
496 .map = &flow_actions[0],
497 .map_idx = &actions_idx
501 .mask = FLOW_ACTION_MASK(
502 RTE_FLOW_ACTION_TYPE_DEC_TTL
504 .map = &flow_actions[0],
505 .map_idx = &actions_idx
508 .str = "set-ipv4-dscp",
509 .mask = FLOW_ACTION_MASK(
510 RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP
512 .map = &flow_actions[0],
513 .map_idx = &actions_idx
516 .str = "set-ipv6-dscp",
517 .mask = FLOW_ACTION_MASK(
518 RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP
520 .map = &flow_actions[0],
521 .map_idx = &actions_idx
525 .mask = FLOW_ACTION_MASK(
526 RTE_FLOW_ACTION_TYPE_FLAG
528 .map = &flow_actions[0],
529 .map_idx = &actions_idx
532 .str = "vxlan-encap",
533 .mask = FLOW_ACTION_MASK(
534 RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP
536 .map = &flow_actions[0],
537 .map_idx = &actions_idx
540 .str = "vxlan-decap",
541 .mask = FLOW_ACTION_MASK(
542 RTE_FLOW_ACTION_TYPE_VXLAN_DECAP
544 .map = &flow_actions[0],
545 .map_idx = &actions_idx
549 static const struct option lgopts[] = {
552 { "rules-count", 1, 0, 0 },
553 { "rules-batch", 1, 0, 0 },
554 { "dump-iterations", 0, 0, 0 },
555 { "deletion-rate", 0, 0, 0 },
556 { "dump-socket-mem", 0, 0, 0 },
557 { "enable-fwd", 0, 0, 0 },
558 { "portmask", 1, 0, 0 },
559 { "cores", 1, 0, 0 },
561 { "ingress", 0, 0, 0 },
562 { "egress", 0, 0, 0 },
563 { "transfer", 0, 0, 0 },
564 { "group", 1, 0, 0 },
566 { "ether", 0, 0, 0 },
572 { "vxlan", 0, 0, 0 },
573 { "vxlan-gpe", 0, 0, 0 },
575 { "geneve", 0, 0, 0 },
579 { "icmpv4", 0, 0, 0 },
580 { "icmpv6", 0, 0, 0 },
582 { "port-id", 0, 0, 0 },
584 { "queue", 0, 0, 0 },
587 { "count", 0, 0, 0 },
588 { "set-meta", 0, 0, 0 },
589 { "set-tag", 0, 0, 0 },
591 { "hairpin-queue", 1, 0, 0 },
592 { "hairpin-rss", 1, 0, 0 },
593 { "set-src-mac", 0, 0, 0 },
594 { "set-dst-mac", 0, 0, 0 },
595 { "set-src-ipv4", 0, 0, 0 },
596 { "set-dst-ipv4", 0, 0, 0 },
597 { "set-src-ipv6", 0, 0, 0 },
598 { "set-dst-ipv6", 0, 0, 0 },
599 { "set-src-tp", 0, 0, 0 },
600 { "set-dst-tp", 0, 0, 0 },
601 { "inc-tcp-ack", 0, 0, 0 },
602 { "dec-tcp-ack", 0, 0, 0 },
603 { "inc-tcp-seq", 0, 0, 0 },
604 { "dec-tcp-seq", 0, 0, 0 },
605 { "set-ttl", 0, 0, 0 },
606 { "dec-ttl", 0, 0, 0 },
607 { "set-ipv4-dscp", 0, 0, 0 },
608 { "set-ipv6-dscp", 0, 0, 0 },
610 { "raw-encap", 1, 0, 0 },
611 { "raw-decap", 1, 0, 0 },
612 { "vxlan-encap", 0, 0, 0 },
613 { "vxlan-decap", 0, 0, 0 },
616 RTE_ETH_FOREACH_DEV(i)
617 ports_mask |= 1 << i;
619 hairpin_queues_num = 0;
622 printf(":: Flow -> ");
623 while ((opt = getopt_long(argc, argvopt, "",
624 lgopts, &opt_idx)) != EOF) {
627 if (strcmp(lgopts[opt_idx].name, "help") == 0) {
629 rte_exit(EXIT_SUCCESS, "Displayed help\n");
632 if (strcmp(lgopts[opt_idx].name, "group") == 0) {
637 rte_exit(EXIT_SUCCESS,
638 "flow group should be >= 0\n");
639 printf("group %d / ", flow_group);
642 for (i = 0; i < RTE_DIM(flow_options); i++)
643 if (strcmp(lgopts[opt_idx].name,
644 flow_options[i].str) == 0) {
646 (*flow_options[i].map_idx)++] =
647 flow_options[i].mask;
648 printf("%s / ", flow_options[i].str);
651 if (strcmp(lgopts[opt_idx].name,
652 "hairpin-rss") == 0) {
655 hairpin_queues_num = n;
657 rte_exit(EXIT_SUCCESS,
658 "Hairpin queues should be > 0\n");
660 flow_actions[actions_idx++] =
662 printf("hairpin-rss / ");
664 if (strcmp(lgopts[opt_idx].name,
665 "hairpin-queue") == 0) {
668 hairpin_queues_num = n;
670 rte_exit(EXIT_SUCCESS,
671 "Hairpin queues should be > 0\n");
673 flow_actions[actions_idx++] =
674 HAIRPIN_QUEUE_ACTION;
675 printf("hairpin-queue / ");
678 if (strcmp(lgopts[opt_idx].name, "raw-encap") == 0) {
679 printf("raw-encap ");
680 flow_actions[actions_idx++] =
682 RTE_FLOW_ACTION_TYPE_RAW_ENCAP
685 token = strtok(optarg, ",");
686 while (token != NULL) {
687 for (i = 0; i < RTE_DIM(flow_options); i++) {
688 if (strcmp(flow_options[i].str, token) == 0) {
689 printf("%s,", token);
690 encap_data |= flow_options[i].mask;
693 /* Reached last item with no match */
694 if (i == (RTE_DIM(flow_options) - 1)) {
695 fprintf(stderr, "Invalid encap item: %s\n", token);
697 rte_exit(EXIT_SUCCESS, "Invalid encap item\n");
700 token = strtok(NULL, ",");
704 if (strcmp(lgopts[opt_idx].name, "raw-decap") == 0) {
705 printf("raw-decap ");
706 flow_actions[actions_idx++] =
708 RTE_FLOW_ACTION_TYPE_RAW_DECAP
711 token = strtok(optarg, ",");
712 while (token != NULL) {
713 for (i = 0; i < RTE_DIM(flow_options); i++) {
714 if (strcmp(flow_options[i].str, token) == 0) {
715 printf("%s,", token);
716 encap_data |= flow_options[i].mask;
719 /* Reached last item with no match */
720 if (i == (RTE_DIM(flow_options) - 1)) {
721 fprintf(stderr, "Invalid decap item: %s\n", token);
723 rte_exit(EXIT_SUCCESS, "Invalid decap item\n");
726 token = strtok(NULL, ",");
731 if (strcmp(lgopts[opt_idx].name,
732 "rules-batch") == 0) {
734 if (n >= DEFAULT_RULES_BATCH)
737 printf("\n\nrules_batch should be >= %d\n",
738 DEFAULT_RULES_BATCH);
739 rte_exit(EXIT_SUCCESS, " ");
742 if (strcmp(lgopts[opt_idx].name,
743 "rules-count") == 0) {
745 if (n >= (int) rules_batch)
748 printf("\n\nrules_count should be >= %d\n",
752 if (strcmp(lgopts[opt_idx].name,
753 "dump-iterations") == 0)
754 dump_iterations = true;
755 if (strcmp(lgopts[opt_idx].name,
756 "deletion-rate") == 0)
758 if (strcmp(lgopts[opt_idx].name,
759 "dump-socket-mem") == 0)
760 dump_socket_mem_flag = true;
761 if (strcmp(lgopts[opt_idx].name,
764 if (strcmp(lgopts[opt_idx].name,
766 /* parse hexadecimal string */
768 pm = strtoull(optarg, &end, 16);
769 if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0'))
770 rte_exit(EXIT_FAILURE, "Invalid fwd port mask\n");
773 if (strcmp(lgopts[opt_idx].name, "cores") == 0) {
775 if ((int) rte_lcore_count() <= n) {
776 printf("\nError: you need %d cores to run on multi-cores\n"
777 "Existing cores are: %d\n", n, rte_lcore_count());
778 rte_exit(EXIT_FAILURE, " ");
780 if (n <= RTE_MAX_LCORE && n > 0)
781 mc_pool.cores_count = n;
783 printf("Error: cores count must be > 0 "
784 " and < %d\n", RTE_MAX_LCORE);
785 rte_exit(EXIT_FAILURE, " ");
790 fprintf(stderr, "Invalid option: %s\n", argv[optind]);
792 rte_exit(EXIT_SUCCESS, "Invalid option\n");
796 printf("end_flow\n");
799 /* Dump the socket memory statistics on console */
801 dump_socket_mem(FILE *f)
803 struct rte_malloc_socket_stats socket_stats;
808 unsigned int n_alloc = 0;
809 unsigned int n_free = 0;
810 bool active_nodes = false;
813 for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
814 if (rte_malloc_get_socket_stats(i, &socket_stats) ||
815 !socket_stats.heap_totalsz_bytes)
818 total += socket_stats.heap_totalsz_bytes;
819 alloc += socket_stats.heap_allocsz_bytes;
820 free += socket_stats.heap_freesz_bytes;
821 n_alloc += socket_stats.alloc_count;
822 n_free += socket_stats.free_count;
823 if (dump_socket_mem_flag) {
824 fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
826 "\nSocket %u:\nsize(M) total: %.6lf\nalloc:"
827 " %.6lf(%.3lf%%)\nfree: %.6lf"
829 "\ncount alloc: %u\nfree: %u\n",
831 socket_stats.heap_totalsz_bytes / 1.0e6,
832 socket_stats.heap_allocsz_bytes / 1.0e6,
833 (double)socket_stats.heap_allocsz_bytes * 100 /
834 (double)socket_stats.heap_totalsz_bytes,
835 socket_stats.heap_freesz_bytes / 1.0e6,
836 socket_stats.greatest_free_size / 1.0e6,
837 socket_stats.alloc_count,
838 socket_stats.free_count);
839 fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
842 if (dump_socket_mem_flag && active_nodes) {
844 "\nTotal: size(M)\ntotal: %.6lf"
845 "\nalloc: %.6lf(%.3lf%%)\nfree: %.6lf"
846 "\ncount alloc: %u\nfree: %u\n",
847 total / 1.0e6, alloc / 1.0e6,
848 (double)alloc * 100 / (double)total, free / 1.0e6,
850 fprintf(f, "::::::::::::::::::::::::::::::::::::::::\n");
856 print_flow_error(struct rte_flow_error error)
858 printf("Flow can't be created %d message: %s\n",
860 error.message ? error.message : "(no stated reason)");
864 print_rules_batches(double *cpu_time_per_batch)
870 for (idx = 0; idx < MAX_BATCHES_COUNT; idx++) {
871 if (!cpu_time_per_batch[idx])
873 delta = (double)(rules_batch / cpu_time_per_batch[idx]);
874 rate = delta / 1000; /* Save rate in K unit. */
875 printf(":: Rules batch #%d: %d rules "
876 "in %f sec[ Rate = %f K Rule/Sec ]\n",
878 cpu_time_per_batch[idx], rate);
883 destroy_flows(int port_id, uint8_t core_id, struct rte_flow **flows_list)
885 struct rte_flow_error error;
886 clock_t start_batch, end_batch;
887 double cpu_time_used = 0;
888 double deletion_rate;
889 double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 };
893 int rules_count_per_core;
895 rules_count_per_core = rules_count / mc_pool.cores_count;
897 start_batch = rte_rdtsc();
898 for (i = 0; i < (uint32_t) rules_count_per_core; i++) {
899 if (flows_list[i] == 0)
902 memset(&error, 0x33, sizeof(error));
903 if (rte_flow_destroy(port_id, flows_list[i], &error)) {
904 print_flow_error(error);
905 rte_exit(EXIT_FAILURE, "Error in deleting flow");
909 * Save the deletion rate for rules batch.
910 * Check if the deletion reached the rules
911 * patch counter, then save the deletion rate
914 if (!((i + 1) % rules_batch)) {
915 end_batch = rte_rdtsc();
916 delta = (double) (end_batch - start_batch);
917 rules_batch_idx = ((i + 1) / rules_batch) - 1;
918 cpu_time_per_batch[rules_batch_idx] = delta / rte_get_tsc_hz();
919 cpu_time_used += cpu_time_per_batch[rules_batch_idx];
920 start_batch = rte_rdtsc();
924 /* Print deletion rates for all batches */
926 print_rules_batches(cpu_time_per_batch);
928 /* Deletion rate for all rules */
929 deletion_rate = ((double) (rules_count_per_core / cpu_time_used) / 1000);
930 printf(":: Port %d :: Core %d :: Rules deletion rate -> %f K Rule/Sec\n",
931 port_id, core_id, deletion_rate);
932 printf(":: Port %d :: Core %d :: The time for deleting %d rules is %f seconds\n",
933 port_id, core_id, rules_count_per_core, cpu_time_used);
935 mc_pool.create_flow.deletion[port_id][core_id] = cpu_time_used;
938 static struct rte_flow **
939 insert_flows(int port_id, uint8_t core_id)
941 struct rte_flow **flows_list;
942 struct rte_flow_error error;
943 clock_t start_batch, end_batch;
944 double cpu_time_used;
945 double insertion_rate;
946 double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 };
949 uint32_t counter, start_counter = 0, end_counter;
950 uint64_t global_items[MAX_ITEMS_NUM] = { 0 };
951 uint64_t global_actions[MAX_ACTIONS_NUM] = { 0 };
953 int rules_count_per_core;
955 rules_count_per_core = rules_count / mc_pool.cores_count;
957 /* Set boundaries of rules for each core. */
959 start_counter = core_id * rules_count_per_core;
960 end_counter = (core_id + 1) * rules_count_per_core;
962 global_items[0] = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH);
963 global_actions[0] = FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP);
965 flows_list = rte_zmalloc("flows_list",
966 (sizeof(struct rte_flow *) * rules_count_per_core) + 1, 0);
967 if (flows_list == NULL)
968 rte_exit(EXIT_FAILURE, "No Memory available!");
972 if (flow_group > 0 && core_id == 0) {
974 * Create global rule to jump into flow_group,
975 * this way the app will avoid the default rules.
977 * This rule will be created only once.
980 * group 0 eth / end actions jump group <flow_group>
982 flow = generate_flow(port_id, 0, flow_attrs,
983 global_items, global_actions,
984 flow_group, 0, 0, 0, 0, core_id, &error);
987 print_flow_error(error);
988 rte_exit(EXIT_FAILURE, "error in creating flow");
990 flows_list[flow_index++] = flow;
993 start_batch = rte_rdtsc();
994 for (counter = start_counter; counter < end_counter; counter++) {
995 flow = generate_flow(port_id, flow_group,
996 flow_attrs, flow_items, flow_actions,
997 JUMP_ACTION_TABLE, counter,
999 encap_data, decap_data,
1003 counter = end_counter;
1006 print_flow_error(error);
1007 rte_exit(EXIT_FAILURE, "error in creating flow");
1010 flows_list[flow_index++] = flow;
1013 * Save the insertion rate for rules batch.
1014 * Check if the insertion reached the rules
1015 * patch counter, then save the insertion rate
1018 if (!((counter + 1) % rules_batch)) {
1019 end_batch = rte_rdtsc();
1020 delta = (double) (end_batch - start_batch);
1021 rules_batch_idx = ((counter + 1) / rules_batch) - 1;
1022 cpu_time_per_batch[rules_batch_idx] = delta / rte_get_tsc_hz();
1023 cpu_time_used += cpu_time_per_batch[rules_batch_idx];
1024 start_batch = rte_rdtsc();
1028 /* Print insertion rates for all batches */
1029 if (dump_iterations)
1030 print_rules_batches(cpu_time_per_batch);
1032 printf(":: Port %d :: Core %d boundaries :: start @[%d] - end @[%d]\n",
1033 port_id, core_id, start_counter, end_counter - 1);
1035 /* Insertion rate for all rules in one core */
1036 insertion_rate = ((double) (rules_count_per_core / cpu_time_used) / 1000);
1037 printf(":: Port %d :: Core %d :: Rules insertion rate -> %f K Rule/Sec\n",
1038 port_id, core_id, insertion_rate);
1039 printf(":: Port %d :: Core %d :: The time for creating %d in rules %f seconds\n",
1040 port_id, core_id, rules_count_per_core, cpu_time_used);
1042 mc_pool.create_flow.insertion[port_id][core_id] = cpu_time_used;
1047 flows_handler(uint8_t core_id)
1049 struct rte_flow **flows_list;
1053 nr_ports = rte_eth_dev_count_avail();
1055 if (rules_batch > rules_count)
1056 rules_batch = rules_count;
1058 printf(":: Rules Count per port: %d\n\n", rules_count);
1060 for (port_id = 0; port_id < nr_ports; port_id++) {
1061 /* If port outside portmask */
1062 if (!((ports_mask >> port_id) & 0x1))
1065 /* Insertion part. */
1066 mc_pool.last_alloc[core_id] = (int64_t)dump_socket_mem(stdout);
1067 flows_list = insert_flows(port_id, core_id);
1068 if (flows_list == NULL)
1069 rte_exit(EXIT_FAILURE, "Error: Insertion Failed!\n");
1070 mc_pool.current_alloc[core_id] = (int64_t)dump_socket_mem(stdout);
1072 /* Deletion part. */
1074 destroy_flows(port_id, core_id, flows_list);
1079 dump_used_cpu_time(const char *item,
1080 uint16_t port, struct used_cpu_time *used_time)
1083 /* Latency: total count of rte rules divided
1084 * over max time used by thread between all
1087 * Throughput: total count of rte rules divided
1088 * over the average of the time cosumed by all
1091 double insertion_latency_time;
1092 double insertion_throughput_time;
1093 double deletion_latency_time;
1094 double deletion_throughput_time;
1095 double insertion_latency, insertion_throughput;
1096 double deletion_latency, deletion_throughput;
1098 /* Save first insertion/deletion rates from first thread.
1099 * Start comparing with all threads, if any thread used
1100 * time more than current saved, replace it.
1102 * Thus in the end we will have the max time used for
1103 * insertion/deletion by one thread.
1105 * As for memory consumption, save the min of all threads
1106 * of last alloc, and save the max for all threads for
1110 insertion_latency_time = used_time->insertion[port][0];
1111 deletion_latency_time = used_time->deletion[port][0];
1112 insertion_throughput_time = used_time->insertion[port][0];
1113 deletion_throughput_time = used_time->deletion[port][0];
1115 i = mc_pool.cores_count;
1117 insertion_throughput_time += used_time->insertion[port][i];
1118 deletion_throughput_time += used_time->deletion[port][i];
1119 if (insertion_latency_time < used_time->insertion[port][i])
1120 insertion_latency_time = used_time->insertion[port][i];
1121 if (deletion_latency_time < used_time->deletion[port][i])
1122 deletion_latency_time = used_time->deletion[port][i];
1125 insertion_latency = ((double) (mc_pool.rules_count
1126 / insertion_latency_time) / 1000);
1127 deletion_latency = ((double) (mc_pool.rules_count
1128 / deletion_latency_time) / 1000);
1130 insertion_throughput_time /= mc_pool.cores_count;
1131 deletion_throughput_time /= mc_pool.cores_count;
1132 insertion_throughput = ((double) (mc_pool.rules_count
1133 / insertion_throughput_time) / 1000);
1134 deletion_throughput = ((double) (mc_pool.rules_count
1135 / deletion_throughput_time) / 1000);
1138 printf("\n%s\n:: [Latency | Insertion] All Cores :: Port %d :: ",
1140 printf("Total flows insertion rate -> %f K Rules/Sec\n",
1142 printf(":: [Latency | Insertion] All Cores :: Port %d :: ", port);
1143 printf("The time for creating %d rules is %f seconds\n",
1144 mc_pool.rules_count, insertion_latency_time);
1146 /* Throughput stats */
1147 printf(":: [Throughput | Insertion] All Cores :: Port %d :: ", port);
1148 printf("Total flows insertion rate -> %f K Rules/Sec\n",
1149 insertion_throughput);
1150 printf(":: [Throughput | Insertion] All Cores :: Port %d :: ", port);
1151 printf("The average time for creating %d rules is %f seconds\n",
1152 mc_pool.rules_count, insertion_throughput_time);
1156 printf(":: [Latency | Deletion] All Cores :: Port %d :: Total "
1157 "deletion rate -> %f K Rules/Sec\n",
1158 port, deletion_latency);
1159 printf(":: [Latency | Deletion] All Cores :: Port %d :: ",
1161 printf("The time for deleting %d rules is %f seconds\n",
1162 mc_pool.rules_count, deletion_latency_time);
1164 /* Throughput stats */
1165 printf(":: [Throughput | Deletion] All Cores :: Port %d :: Total "
1166 "deletion rate -> %f K Rules/Sec\n",
1167 port, deletion_throughput);
1168 printf(":: [Throughput | Deletion] All Cores :: Port %d :: ",
1170 printf("The average time for deleting %d rules is %f seconds\n",
1171 mc_pool.rules_count, deletion_throughput_time);
1176 dump_used_mem(uint16_t port)
1179 int64_t last_alloc, current_alloc;
1180 int flow_size_in_bytes;
1182 last_alloc = mc_pool.last_alloc[0];
1183 current_alloc = mc_pool.current_alloc[0];
1185 i = mc_pool.cores_count;
1187 if (last_alloc > mc_pool.last_alloc[i])
1188 last_alloc = mc_pool.last_alloc[i];
1189 if (current_alloc < mc_pool.current_alloc[i])
1190 current_alloc = mc_pool.current_alloc[i];
1193 flow_size_in_bytes = (current_alloc - last_alloc) / mc_pool.rules_count;
1194 printf("\n:: Port %d :: rte_flow size in DPDK layer: %d Bytes\n",
1195 port, flow_size_in_bytes);
1199 run_rte_flow_handler_cores(void *data __rte_unused)
1202 int lcore_counter = 0;
1203 int lcore_id = rte_lcore_id();
1206 RTE_LCORE_FOREACH(i) {
1207 /* If core not needed return. */
1208 if (lcore_id == i) {
1209 printf(":: lcore %d mapped with index %d\n", lcore_id, lcore_counter);
1210 if (lcore_counter >= (int) mc_pool.cores_count)
1216 lcore_id = lcore_counter;
1218 if (lcore_id >= (int) mc_pool.cores_count)
1221 mc_pool.rules_count = rules_count;
1223 flows_handler(lcore_id);
1225 /* Only main core to print total results. */
1229 /* Make sure all cores finished insertion/deletion process. */
1230 rte_eal_mp_wait_lcore();
1232 RTE_ETH_FOREACH_DEV(port) {
1234 dump_used_cpu_time("Flows:",
1235 port, &mc_pool.create_flow);
1236 dump_used_mem(port);
1243 signal_handler(int signum)
1245 if (signum == SIGINT || signum == SIGTERM) {
1246 printf("\n\nSignal %d received, preparing to exit...\n",
1248 printf("Error: Stats are wrong due to sudden signal!\n\n");
1253 static inline uint16_t
1254 do_rx(struct lcore_info *li, uint16_t rx_port, uint16_t rx_queue)
1257 cnt = rte_eth_rx_burst(rx_port, rx_queue, li->pkts, MAX_PKT_BURST);
1263 do_tx(struct lcore_info *li, uint16_t cnt, uint16_t tx_port,
1269 nr_tx = rte_eth_tx_burst(tx_port, tx_queue, li->pkts, cnt);
1270 li->tx_pkts += nr_tx;
1271 li->tx_drops += cnt - nr_tx;
1273 for (i = nr_tx; i < cnt; i++)
1274 rte_pktmbuf_free(li->pkts[i]);
1278 * Method to convert numbers into pretty numbers that easy
1279 * to read. The design here is to add comma after each three
1280 * digits and set all of this inside buffer.
1282 * For example if n = 1799321, the output will be
1283 * 1,799,321 after this method which is easier to read.
1286 pretty_number(uint64_t n, char *buf)
1293 sprintf(p[i], "%03d", (int)(n % 1000));
1298 sprintf(p[i++], "%d", (int)n);
1301 off += sprintf(buf + off, "%s,", p[i]);
1302 buf[strlen(buf) - 1] = '\0';
1308 packet_per_second_stats(void)
1310 struct lcore_info *old;
1311 struct lcore_info *li, *oli;
1315 old = rte_zmalloc("old",
1316 sizeof(struct lcore_info) * RTE_MAX_LCORE, 0);
1318 rte_exit(EXIT_FAILURE, "No Memory available!");
1320 memcpy(old, lcore_infos,
1321 sizeof(struct lcore_info) * RTE_MAX_LCORE);
1323 while (!force_quit) {
1324 uint64_t total_tx_pkts = 0;
1325 uint64_t total_rx_pkts = 0;
1326 uint64_t total_tx_drops = 0;
1327 uint64_t tx_delta, rx_delta, drops_delta;
1329 int nr_valid_core = 0;
1334 char go_up_nr_lines[16];
1336 sprintf(go_up_nr_lines, "%c[%dA\r", 27, nr_lines);
1337 printf("%s\r", go_up_nr_lines);
1340 printf("\n%6s %16s %16s %16s\n", "core", "tx", "tx drops", "rx");
1341 printf("%6s %16s %16s %16s\n", "------", "----------------",
1342 "----------------", "----------------");
1344 for (i = 0; i < RTE_MAX_LCORE; i++) {
1345 li = &lcore_infos[i];
1347 if (li->mode != LCORE_MODE_PKT)
1350 tx_delta = li->tx_pkts - oli->tx_pkts;
1351 rx_delta = li->rx_pkts - oli->rx_pkts;
1352 drops_delta = li->tx_drops - oli->tx_drops;
1353 printf("%6d %16s %16s %16s\n", i,
1354 pretty_number(tx_delta, buf[0]),
1355 pretty_number(drops_delta, buf[1]),
1356 pretty_number(rx_delta, buf[2]));
1358 total_tx_pkts += tx_delta;
1359 total_rx_pkts += rx_delta;
1360 total_tx_drops += drops_delta;
1366 if (nr_valid_core > 1) {
1367 printf("%6s %16s %16s %16s\n", "total",
1368 pretty_number(total_tx_pkts, buf[0]),
1369 pretty_number(total_tx_drops, buf[1]),
1370 pretty_number(total_rx_pkts, buf[2]));
1374 memcpy(old, lcore_infos,
1375 sizeof(struct lcore_info) * RTE_MAX_LCORE);
1380 start_forwarding(void *data __rte_unused)
1382 int lcore = rte_lcore_id();
1385 struct lcore_info *li = &lcore_infos[lcore];
1390 if (li->mode == LCORE_MODE_STATS) {
1391 printf(":: started stats on lcore %u\n", lcore);
1392 packet_per_second_stats();
1397 for (stream_id = 0; stream_id < MAX_STREAMS; stream_id++) {
1398 if (li->streams[stream_id].rx_port == -1)
1402 li->streams[stream_id].rx_port,
1403 li->streams[stream_id].rx_queue);
1406 li->streams[stream_id].tx_port,
1407 li->streams[stream_id].tx_queue);
1413 init_lcore_info(void)
1421 int streams_per_core;
1422 int unassigned_streams;
1424 nr_port = rte_eth_dev_count_avail();
1426 /* First logical core is reserved for stats printing */
1427 lcore = rte_get_next_lcore(-1, 0, 0);
1428 lcore_infos[lcore].mode = LCORE_MODE_STATS;
1431 * Initialize all cores
1432 * All cores at first must have -1 value in all streams
1433 * This means that this stream is not used, or not set
1436 for (i = 0; i < RTE_MAX_LCORE; i++)
1437 for (j = 0; j < MAX_STREAMS; j++) {
1438 lcore_infos[i].streams[j].tx_port = -1;
1439 lcore_infos[i].streams[j].rx_port = -1;
1440 lcore_infos[i].streams[j].tx_queue = -1;
1441 lcore_infos[i].streams[j].rx_queue = -1;
1442 lcore_infos[i].streams_nb = 0;
1446 * Calculate the total streams count.
1447 * Also distribute those streams count between the available
1448 * logical cores except first core, since it's reserved for
1451 nb_fwd_streams = nr_port * RXQ_NUM;
1452 if ((int)(nb_lcores - 1) >= nb_fwd_streams)
1453 for (i = 0; i < (int)(nb_lcores - 1); i++) {
1454 lcore = rte_get_next_lcore(lcore, 0, 0);
1455 lcore_infos[lcore].streams_nb = 1;
1458 streams_per_core = nb_fwd_streams / (nb_lcores - 1);
1459 unassigned_streams = nb_fwd_streams % (nb_lcores - 1);
1460 for (i = 0; i < (int)(nb_lcores - 1); i++) {
1461 lcore = rte_get_next_lcore(lcore, 0, 0);
1462 lcore_infos[lcore].streams_nb = streams_per_core;
1463 if (unassigned_streams) {
1464 lcore_infos[lcore].streams_nb++;
1465 unassigned_streams--;
1471 * Set the streams for the cores according to each logical
1472 * core stream count.
1473 * The streams is built on the design of what received should
1474 * forward as well, this means that if you received packets on
1475 * port 0 queue 0 then the same queue should forward the
1476 * packets, using the same logical core.
1478 lcore = rte_get_next_lcore(-1, 0, 0);
1479 for (port = 0; port < nr_port; port++) {
1480 /* Create FWD stream */
1481 for (queue = 0; queue < RXQ_NUM; queue++) {
1482 if (!lcore_infos[lcore].streams_nb ||
1483 !(stream_id % lcore_infos[lcore].streams_nb)) {
1484 lcore = rte_get_next_lcore(lcore, 0, 0);
1485 lcore_infos[lcore].mode = LCORE_MODE_PKT;
1488 lcore_infos[lcore].streams[stream_id].rx_queue = queue;
1489 lcore_infos[lcore].streams[stream_id].tx_queue = queue;
1490 lcore_infos[lcore].streams[stream_id].rx_port = port;
1491 lcore_infos[lcore].streams[stream_id].tx_port = port;
1496 /* Print all streams */
1497 printf(":: Stream -> core id[N]: (rx_port, rx_queue)->(tx_port, tx_queue)\n");
1498 for (i = 0; i < RTE_MAX_LCORE; i++)
1499 for (j = 0; j < MAX_STREAMS; j++) {
1500 /* No streams for this core */
1501 if (lcore_infos[i].streams[j].tx_port == -1)
1503 printf("Stream -> core id[%d]: (%d,%d)->(%d,%d)\n",
1505 lcore_infos[i].streams[j].rx_port,
1506 lcore_infos[i].streams[j].rx_queue,
1507 lcore_infos[i].streams[j].tx_port,
1508 lcore_infos[i].streams[j].tx_queue);
1517 uint16_t hairpin_queue;
1521 struct rte_eth_hairpin_conf hairpin_conf = {
1524 struct rte_eth_conf port_conf = {
1530 struct rte_eth_txconf txq_conf;
1531 struct rte_eth_rxconf rxq_conf;
1532 struct rte_eth_dev_info dev_info;
1534 nr_queues = RXQ_NUM;
1535 if (hairpin_queues_num != 0)
1536 nr_queues = RXQ_NUM + hairpin_queues_num;
1538 nr_ports = rte_eth_dev_count_avail();
1540 rte_exit(EXIT_FAILURE, "Error: no port detected\n");
1542 mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool",
1543 TOTAL_MBUF_NUM, MBUF_CACHE_SIZE,
1546 if (mbuf_mp == NULL)
1547 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n");
1549 for (port_id = 0; port_id < nr_ports; port_id++) {
1550 ret = rte_eth_dev_info_get(port_id, &dev_info);
1552 rte_exit(EXIT_FAILURE,
1553 "Error during getting device"
1554 " (port %u) info: %s\n",
1555 port_id, strerror(-ret));
1557 port_conf.txmode.offloads &= dev_info.tx_offload_capa;
1558 port_conf.rxmode.offloads &= dev_info.rx_offload_capa;
1560 printf(":: initializing port: %d\n", port_id);
1562 ret = rte_eth_dev_configure(port_id, nr_queues,
1563 nr_queues, &port_conf);
1565 rte_exit(EXIT_FAILURE,
1566 ":: cannot configure device: err=%d, port=%u\n",
1569 rxq_conf = dev_info.default_rxconf;
1570 for (std_queue = 0; std_queue < RXQ_NUM; std_queue++) {
1571 ret = rte_eth_rx_queue_setup(port_id, std_queue, NR_RXD,
1572 rte_eth_dev_socket_id(port_id),
1576 rte_exit(EXIT_FAILURE,
1577 ":: Rx queue setup failed: err=%d, port=%u\n",
1581 txq_conf = dev_info.default_txconf;
1582 for (std_queue = 0; std_queue < TXQ_NUM; std_queue++) {
1583 ret = rte_eth_tx_queue_setup(port_id, std_queue, NR_TXD,
1584 rte_eth_dev_socket_id(port_id),
1587 rte_exit(EXIT_FAILURE,
1588 ":: Tx queue setup failed: err=%d, port=%u\n",
1592 /* Catch all packets from traffic generator. */
1593 ret = rte_eth_promiscuous_enable(port_id);
1595 rte_exit(EXIT_FAILURE,
1596 ":: promiscuous mode enable failed: err=%s, port=%u\n",
1597 rte_strerror(-ret), port_id);
1599 if (hairpin_queues_num != 0) {
1601 * Configure peer which represents hairpin Tx.
1602 * Hairpin queue numbers start after standard queues
1603 * (RXQ_NUM and TXQ_NUM).
1605 for (hairpin_queue = RXQ_NUM, std_queue = 0;
1606 hairpin_queue < nr_queues;
1607 hairpin_queue++, std_queue++) {
1608 hairpin_conf.peers[0].port = port_id;
1609 hairpin_conf.peers[0].queue =
1610 std_queue + TXQ_NUM;
1611 ret = rte_eth_rx_hairpin_queue_setup(
1612 port_id, hairpin_queue,
1613 NR_RXD, &hairpin_conf);
1615 rte_exit(EXIT_FAILURE,
1616 ":: Hairpin rx queue setup failed: err=%d, port=%u\n",
1620 for (hairpin_queue = TXQ_NUM, std_queue = 0;
1621 hairpin_queue < nr_queues;
1622 hairpin_queue++, std_queue++) {
1623 hairpin_conf.peers[0].port = port_id;
1624 hairpin_conf.peers[0].queue =
1625 std_queue + RXQ_NUM;
1626 ret = rte_eth_tx_hairpin_queue_setup(
1627 port_id, hairpin_queue,
1628 NR_TXD, &hairpin_conf);
1630 rte_exit(EXIT_FAILURE,
1631 ":: Hairpin tx queue setup failed: err=%d, port=%u\n",
1636 ret = rte_eth_dev_start(port_id);
1638 rte_exit(EXIT_FAILURE,
1639 "rte_eth_dev_start:err=%d, port=%u\n",
1642 printf(":: initializing port: %d done\n", port_id);
1647 main(int argc, char **argv)
1651 struct rte_flow_error error;
1653 ret = rte_eal_init(argc, argv);
1655 rte_exit(EXIT_FAILURE, "EAL init failed\n");
1658 dump_iterations = false;
1659 rules_count = DEFAULT_RULES_COUNT;
1660 rules_batch = DEFAULT_RULES_BATCH;
1661 delete_flag = false;
1662 dump_socket_mem_flag = false;
1663 flow_group = DEFAULT_GROUP;
1665 signal(SIGINT, signal_handler);
1666 signal(SIGTERM, signal_handler);
1671 args_parse(argc, argv);
1675 nb_lcores = rte_lcore_count();
1677 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n");
1680 printf(":: Flows Count per port: %d\n\n", rules_count);
1682 rte_eal_mp_remote_launch(run_rte_flow_handler_cores, NULL, CALL_MAIN);
1686 rte_eal_mp_remote_launch(start_forwarding, NULL, CALL_MAIN);
1689 RTE_ETH_FOREACH_DEV(port) {
1690 rte_flow_flush(port, &error);
1691 if (rte_eth_dev_stop(port) != 0)
1692 printf("Failed to stop device on port %u\n", port);
1693 rte_eth_dev_close(port);
1695 printf("\nBye ...\n");