0a030a462cfaac3ca72b0d8ab9484ac62bb4e0eb
[dpdk.git] / app / test-flow-perf / main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2020 Mellanox Technologies, Ltd
3  *
4  * This file contain the application main file
5  * This application provides the user the ability to test the
6  * insertion rate for specific rte_flow rule under stress state ~4M rule/
7  *
8  * Then it will also provide packet per second measurement after installing
9  * all rules, the user may send traffic to test the PPS that match the rules
10  * after all rules are installed, to check performance or functionality after
11  * the stress.
12  *
13  * The flows insertion will go for all ports first, then it will print the
14  * results, after that the application will go into forwarding packets mode
15  * it will start receiving traffic if any and then forwarding it back and
16  * gives packet per second measurement.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
23 #include <inttypes.h>
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <getopt.h>
27 #include <stdbool.h>
28 #include <sys/time.h>
29 #include <signal.h>
30 #include <unistd.h>
31
32 #include <rte_malloc.h>
33 #include <rte_mempool.h>
34 #include <rte_mbuf.h>
35 #include <rte_ethdev.h>
36 #include <rte_flow.h>
37
38 #include "config.h"
39 #include "flow_gen.h"
40
41 #define MAX_ITERATIONS             100
42 #define DEFAULT_RULES_COUNT    4000000
43 #define DEFAULT_ITERATION       100000
44
45 struct rte_flow *flow;
46 static uint8_t flow_group;
47
48 static uint64_t encap_data;
49 static uint64_t decap_data;
50
51 static uint64_t flow_items[MAX_ITEMS_NUM];
52 static uint64_t flow_actions[MAX_ACTIONS_NUM];
53 static uint64_t flow_attrs[MAX_ATTRS_NUM];
54 static uint8_t items_idx, actions_idx, attrs_idx;
55
56 static volatile bool force_quit;
57 static bool dump_iterations;
58 static bool delete_flag;
59 static bool dump_socket_mem_flag;
60 static bool enable_fwd;
61
62 static struct rte_mempool *mbuf_mp;
63 static uint32_t nb_lcores;
64 static uint32_t flows_count;
65 static uint32_t iterations_number;
66 static uint32_t hairpin_queues_num; /* total hairpin q number - default: 0 */
67 static uint32_t nb_lcores;
68
69 #define MAX_PKT_BURST    32
70 #define LCORE_MODE_PKT    1
71 #define LCORE_MODE_STATS  2
72 #define MAX_STREAMS      64
73 #define MAX_LCORES       64
74
75 struct stream {
76         int tx_port;
77         int tx_queue;
78         int rx_port;
79         int rx_queue;
80 };
81
82 struct lcore_info {
83         int mode;
84         int streams_nb;
85         struct stream streams[MAX_STREAMS];
86         /* stats */
87         uint64_t tx_pkts;
88         uint64_t tx_drops;
89         uint64_t rx_pkts;
90         struct rte_mbuf *pkts[MAX_PKT_BURST];
91 } __rte_cache_aligned;
92
93 static struct lcore_info lcore_infos[MAX_LCORES];
94
95 static void
96 usage(char *progname)
97 {
98         printf("\nusage: %s\n", progname);
99         printf("\nControl configurations:\n");
100         printf("  --flows-count=N: to set the number of needed"
101                 " flows to insert, default is 4,000,000\n");
102         printf("  --dump-iterations: To print rates for each"
103                 " iteration\n");
104         printf("  --deletion-rate: Enable deletion rate"
105                 " calculations\n");
106         printf("  --dump-socket-mem: To dump all socket memory\n");
107         printf("  --enable-fwd: To enable packets forwarding"
108                 " after insertion\n");
109
110         printf("To set flow attributes:\n");
111         printf("  --ingress: set ingress attribute in flows\n");
112         printf("  --egress: set egress attribute in flows\n");
113         printf("  --transfer: set transfer attribute in flows\n");
114         printf("  --group=N: set group for all flows,"
115                 " default is 0\n");
116
117         printf("To set flow items:\n");
118         printf("  --ether: add ether layer in flow items\n");
119         printf("  --vlan: add vlan layer in flow items\n");
120         printf("  --ipv4: add ipv4 layer in flow items\n");
121         printf("  --ipv6: add ipv6 layer in flow items\n");
122         printf("  --tcp: add tcp layer in flow items\n");
123         printf("  --udp: add udp layer in flow items\n");
124         printf("  --vxlan: add vxlan layer in flow items\n");
125         printf("  --vxlan-gpe: add vxlan-gpe layer in flow items\n");
126         printf("  --gre: add gre layer in flow items\n");
127         printf("  --geneve: add geneve layer in flow items\n");
128         printf("  --gtp: add gtp layer in flow items\n");
129         printf("  --meta: add meta layer in flow items\n");
130         printf("  --tag: add tag layer in flow items\n");
131
132         printf("To set flow actions:\n");
133         printf("  --port-id: add port-id action in flow actions\n");
134         printf("  --rss: add rss action in flow actions\n");
135         printf("  --queue: add queue action in flow actions\n");
136         printf("  --jump: add jump action in flow actions\n");
137         printf("  --mark: add mark action in flow actions\n");
138         printf("  --count: add count action in flow actions\n");
139         printf("  --set-meta: add set meta action in flow actions\n");
140         printf("  --set-tag: add set tag action in flow actions\n");
141         printf("  --drop: add drop action in flow actions\n");
142         printf("  --hairpin-queue=N: add hairpin-queue action in flow actions\n");
143         printf("  --hairpin-rss=N: add hairpin-rss action in flow actions\n");
144         printf("  --set-src-mac: add set src mac action to flow actions\n"
145                 "Src mac to be set is random each flow\n");
146         printf("  --set-dst-mac: add set dst mac action to flow actions\n"
147                  "Dst mac to be set is random each flow\n");
148         printf("  --set-src-ipv4: add set src ipv4 action to flow actions\n"
149                 "Src ipv4 to be set is random each flow\n");
150         printf("  --set-dst-ipv4 add set dst ipv4 action to flow actions\n"
151                 "Dst ipv4 to be set is random each flow\n");
152         printf("  --set-src-ipv6: add set src ipv6 action to flow actions\n"
153                 "Src ipv6 to be set is random each flow\n");
154         printf("  --set-dst-ipv6: add set dst ipv6 action to flow actions\n"
155                 "Dst ipv6 to be set is random each flow\n");
156         printf("  --set-src-tp: add set src tp action to flow actions\n"
157                 "Src tp to be set is random each flow\n");
158         printf("  --set-dst-tp: add set dst tp action to flow actions\n"
159                 "Dst tp to be set is random each flow\n");
160         printf("  --inc-tcp-ack: add inc tcp ack action to flow actions\n"
161                 "tcp ack will be increments by 1\n");
162         printf("  --dec-tcp-ack: add dec tcp ack action to flow actions\n"
163                 "tcp ack will be decrements by 1\n");
164         printf("  --inc-tcp-seq: add inc tcp seq action to flow actions\n"
165                 "tcp seq will be increments by 1\n");
166         printf("  --dec-tcp-seq: add dec tcp seq action to flow actions\n"
167                 "tcp seq will be decrements by 1\n");
168         printf("  --set-ttl: add set ttl action to flow actions\n"
169                 "L3 ttl to be set is random each flow\n");
170         printf("  --dec-ttl: add dec ttl action to flow actions\n"
171                 "L3 ttl will be decrements by 1\n");
172         printf("  --set-ipv4-dscp: add set ipv4 dscp action to flow actions\n"
173                 "ipv4 dscp value to be set is random each flow\n");
174         printf("  --set-ipv6-dscp: add set ipv6 dscp action to flow actions\n"
175                 "ipv6 dscp value to be set is random each flow\n");
176         printf("  --flag: add flag action to flow actions\n");
177         printf("  --raw-encap=<data>: add raw encap action to flow actions\n"
178                 "Data is the data needed to be encaped\n"
179                 "Example: raw-encap=ether,ipv4,udp,vxlan\n");
180         printf("  --raw-decap=<data>: add raw decap action to flow actions\n"
181                 "Data is the data needed to be decaped\n"
182                 "Example: raw-decap=ether,ipv4,udp,vxlan\n");
183         printf("  --vxlan-encap: add vxlan-encap action to flow actions\n"
184                 "Encapped data is fixed with pattern: ether,ipv4,udp,vxlan\n"
185                 "With fixed values\n");
186         printf("  --vxlan-decap: add vxlan_decap action to flow actions\n");
187 }
188
189 static void
190 args_parse(int argc, char **argv)
191 {
192         char **argvopt;
193         char *token;
194         int n, opt;
195         int opt_idx;
196         size_t i;
197
198         static const struct option_dict {
199                 const char *str;
200                 const uint64_t mask;
201                 uint64_t *map;
202                 uint8_t *map_idx;
203
204         } flow_options[] = {
205                 {
206                         .str = "ether",
207                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH),
208                         .map = &flow_items[0],
209                         .map_idx = &items_idx
210                 },
211                 {
212                         .str = "ipv4",
213                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV4),
214                         .map = &flow_items[0],
215                         .map_idx = &items_idx
216                 },
217                 {
218                         .str = "ipv6",
219                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV6),
220                         .map = &flow_items[0],
221                         .map_idx = &items_idx
222                 },
223                 {
224                         .str = "vlan",
225                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VLAN),
226                         .map = &flow_items[0],
227                         .map_idx = &items_idx
228                 },
229                 {
230                         .str = "tcp",
231                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TCP),
232                         .map = &flow_items[0],
233                         .map_idx = &items_idx
234                 },
235                 {
236                         .str = "udp",
237                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_UDP),
238                         .map = &flow_items[0],
239                         .map_idx = &items_idx
240                 },
241                 {
242                         .str = "vxlan",
243                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN),
244                         .map = &flow_items[0],
245                         .map_idx = &items_idx
246                 },
247                 {
248                         .str = "vxlan-gpe",
249                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN_GPE),
250                         .map = &flow_items[0],
251                         .map_idx = &items_idx
252                 },
253                 {
254                         .str = "gre",
255                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GRE),
256                         .map = &flow_items[0],
257                         .map_idx = &items_idx
258                 },
259                 {
260                         .str = "geneve",
261                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GENEVE),
262                         .map = &flow_items[0],
263                         .map_idx = &items_idx
264                 },
265                 {
266                         .str = "gtp",
267                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GTP),
268                         .map = &flow_items[0],
269                         .map_idx = &items_idx
270                 },
271                 {
272                         .str = "meta",
273                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_META),
274                         .map = &flow_items[0],
275                         .map_idx = &items_idx
276                 },
277                 {
278                         .str = "tag",
279                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TAG),
280                         .map = &flow_items[0],
281                         .map_idx = &items_idx
282                 },
283                 {
284                         .str = "ingress",
285                         .mask = INGRESS,
286                         .map = &flow_attrs[0],
287                         .map_idx = &attrs_idx
288                 },
289                 {
290                         .str = "egress",
291                         .mask = EGRESS,
292                         .map = &flow_attrs[0],
293                         .map_idx = &attrs_idx
294                 },
295                 {
296                         .str = "transfer",
297                         .mask = TRANSFER,
298                         .map = &flow_attrs[0],
299                         .map_idx = &attrs_idx
300                 },
301                 {
302                         .str = "port-id",
303                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_PORT_ID),
304                         .map = &flow_actions[0],
305                         .map_idx = &actions_idx
306                 },
307                 {
308                         .str = "rss",
309                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_RSS),
310                         .map = &flow_actions[0],
311                         .map_idx = &actions_idx
312                 },
313                 {
314                         .str = "queue",
315                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_QUEUE),
316                         .map = &flow_actions[0],
317                         .map_idx = &actions_idx
318                 },
319                 {
320                         .str = "jump",
321                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_JUMP),
322                         .map = &flow_actions[0],
323                         .map_idx = &actions_idx
324                 },
325                 {
326                         .str = "mark",
327                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_MARK),
328                         .map = &flow_actions[0],
329                         .map_idx = &actions_idx
330                 },
331                 {
332                         .str = "count",
333                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_COUNT),
334                         .map = &flow_actions[0],
335                         .map_idx = &actions_idx
336                 },
337                 {
338                         .str = "set-meta",
339                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_META),
340                         .map = &flow_actions[0],
341                         .map_idx = &actions_idx
342                 },
343                 {
344                         .str = "set-tag",
345                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_TAG),
346                         .map = &flow_actions[0],
347                         .map_idx = &actions_idx
348                 },
349                 {
350                         .str = "drop",
351                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_DROP),
352                         .map = &flow_actions[0],
353                         .map_idx = &actions_idx
354                 },
355                 {
356                         .str = "set-src-mac",
357                         .mask = FLOW_ACTION_MASK(
358                                 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC
359                         ),
360                         .map = &flow_actions[0],
361                         .map_idx = &actions_idx
362                 },
363                 {
364                         .str = "set-dst-mac",
365                         .mask = FLOW_ACTION_MASK(
366                                 RTE_FLOW_ACTION_TYPE_SET_MAC_DST
367                         ),
368                         .map = &flow_actions[0],
369                         .map_idx = &actions_idx
370                 },
371                 {
372                         .str = "set-src-ipv4",
373                         .mask = FLOW_ACTION_MASK(
374                                 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC
375                         ),
376                         .map = &flow_actions[0],
377                         .map_idx = &actions_idx
378                 },
379                 {
380                         .str = "set-dst-ipv4",
381                         .mask = FLOW_ACTION_MASK(
382                                 RTE_FLOW_ACTION_TYPE_SET_IPV4_DST
383                         ),
384                         .map = &flow_actions[0],
385                         .map_idx = &actions_idx
386                 },
387                 {
388                         .str = "set-src-ipv6",
389                         .mask = FLOW_ACTION_MASK(
390                                 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC
391                         ),
392                         .map = &flow_actions[0],
393                         .map_idx = &actions_idx
394                 },
395                 {
396                         .str = "set-dst-ipv6",
397                         .mask = FLOW_ACTION_MASK(
398                                 RTE_FLOW_ACTION_TYPE_SET_IPV6_DST
399                         ),
400                         .map = &flow_actions[0],
401                         .map_idx = &actions_idx
402                 },
403                 {
404                         .str = "set-src-tp",
405                         .mask = FLOW_ACTION_MASK(
406                                 RTE_FLOW_ACTION_TYPE_SET_TP_SRC
407                         ),
408                         .map = &flow_actions[0],
409                         .map_idx = &actions_idx
410                 },
411                 {
412                         .str = "set-dst-tp",
413                         .mask = FLOW_ACTION_MASK(
414                                 RTE_FLOW_ACTION_TYPE_SET_TP_DST
415                         ),
416                         .map = &flow_actions[0],
417                         .map_idx = &actions_idx
418                 },
419                 {
420                         .str = "inc-tcp-ack",
421                         .mask = FLOW_ACTION_MASK(
422                                 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK
423                         ),
424                         .map = &flow_actions[0],
425                         .map_idx = &actions_idx
426                 },
427                 {
428                         .str = "dec-tcp-ack",
429                         .mask = FLOW_ACTION_MASK(
430                                 RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK
431                         ),
432                         .map = &flow_actions[0],
433                         .map_idx = &actions_idx
434                 },
435                 {
436                         .str = "inc-tcp-seq",
437                         .mask = FLOW_ACTION_MASK(
438                                 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ
439                         ),
440                         .map = &flow_actions[0],
441                         .map_idx = &actions_idx
442                 },
443                 {
444                         .str = "dec-tcp-seq",
445                         .mask = FLOW_ACTION_MASK(
446                                 RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ
447                         ),
448                         .map = &flow_actions[0],
449                         .map_idx = &actions_idx
450                 },
451                 {
452                         .str = "set-ttl",
453                         .mask = FLOW_ACTION_MASK(
454                                 RTE_FLOW_ACTION_TYPE_SET_TTL
455                         ),
456                         .map = &flow_actions[0],
457                         .map_idx = &actions_idx
458                 },
459                 {
460                         .str = "dec-ttl",
461                         .mask = FLOW_ACTION_MASK(
462                                 RTE_FLOW_ACTION_TYPE_DEC_TTL
463                         ),
464                         .map = &flow_actions[0],
465                         .map_idx = &actions_idx
466                 },
467                 {
468                         .str = "set-ipv4-dscp",
469                         .mask = FLOW_ACTION_MASK(
470                                 RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP
471                         ),
472                         .map = &flow_actions[0],
473                         .map_idx = &actions_idx
474                 },
475                 {
476                         .str = "set-ipv6-dscp",
477                         .mask = FLOW_ACTION_MASK(
478                                 RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP
479                         ),
480                         .map = &flow_actions[0],
481                         .map_idx = &actions_idx
482                 },
483                 {
484                         .str = "flag",
485                         .mask = FLOW_ACTION_MASK(
486                                 RTE_FLOW_ACTION_TYPE_FLAG
487                         ),
488                         .map = &flow_actions[0],
489                         .map_idx = &actions_idx
490                 },
491                 {
492                         .str = "vxlan-encap",
493                         .mask = FLOW_ACTION_MASK(
494                                 RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP
495                         ),
496                         .map = &flow_actions[0],
497                         .map_idx = &actions_idx
498                 },
499                 {
500                         .str = "vxlan-decap",
501                         .mask = FLOW_ACTION_MASK(
502                                 RTE_FLOW_ACTION_TYPE_VXLAN_DECAP
503                         ),
504                         .map = &flow_actions[0],
505                         .map_idx = &actions_idx
506                 },
507         };
508
509         static const struct option lgopts[] = {
510                 /* Control */
511                 { "help",                       0, 0, 0 },
512                 { "flows-count",                1, 0, 0 },
513                 { "dump-iterations",            0, 0, 0 },
514                 { "deletion-rate",              0, 0, 0 },
515                 { "dump-socket-mem",            0, 0, 0 },
516                 { "enable-fwd",                 0, 0, 0 },
517                 /* Attributes */
518                 { "ingress",                    0, 0, 0 },
519                 { "egress",                     0, 0, 0 },
520                 { "transfer",                   0, 0, 0 },
521                 { "group",                      1, 0, 0 },
522                 /* Items */
523                 { "ether",                      0, 0, 0 },
524                 { "vlan",                       0, 0, 0 },
525                 { "ipv4",                       0, 0, 0 },
526                 { "ipv6",                       0, 0, 0 },
527                 { "tcp",                        0, 0, 0 },
528                 { "udp",                        0, 0, 0 },
529                 { "vxlan",                      0, 0, 0 },
530                 { "vxlan-gpe",                  0, 0, 0 },
531                 { "gre",                        0, 0, 0 },
532                 { "geneve",                     0, 0, 0 },
533                 { "gtp",                        0, 0, 0 },
534                 { "meta",                       0, 0, 0 },
535                 { "tag",                        0, 0, 0 },
536                 /* Actions */
537                 { "port-id",                    0, 0, 0 },
538                 { "rss",                        0, 0, 0 },
539                 { "queue",                      0, 0, 0 },
540                 { "jump",                       0, 0, 0 },
541                 { "mark",                       0, 0, 0 },
542                 { "count",                      0, 0, 0 },
543                 { "set-meta",                   0, 0, 0 },
544                 { "set-tag",                    0, 0, 0 },
545                 { "drop",                       0, 0, 0 },
546                 { "hairpin-queue",              1, 0, 0 },
547                 { "hairpin-rss",                1, 0, 0 },
548                 { "set-src-mac",                0, 0, 0 },
549                 { "set-dst-mac",                0, 0, 0 },
550                 { "set-src-ipv4",               0, 0, 0 },
551                 { "set-dst-ipv4",               0, 0, 0 },
552                 { "set-src-ipv6",               0, 0, 0 },
553                 { "set-dst-ipv6",               0, 0, 0 },
554                 { "set-src-tp",                 0, 0, 0 },
555                 { "set-dst-tp",                 0, 0, 0 },
556                 { "inc-tcp-ack",                0, 0, 0 },
557                 { "dec-tcp-ack",                0, 0, 0 },
558                 { "inc-tcp-seq",                0, 0, 0 },
559                 { "dec-tcp-seq",                0, 0, 0 },
560                 { "set-ttl",                    0, 0, 0 },
561                 { "dec-ttl",                    0, 0, 0 },
562                 { "set-ipv4-dscp",              0, 0, 0 },
563                 { "set-ipv6-dscp",              0, 0, 0 },
564                 { "flag",                       0, 0, 0 },
565                 { "raw-encap",                  1, 0, 0 },
566                 { "raw-decap",                  1, 0, 0 },
567                 { "vxlan-encap",                0, 0, 0 },
568                 { "vxlan-decap",                0, 0, 0 },
569         };
570
571         hairpin_queues_num = 0;
572         argvopt = argv;
573
574         printf(":: Flow -> ");
575         while ((opt = getopt_long(argc, argvopt, "",
576                                 lgopts, &opt_idx)) != EOF) {
577                 switch (opt) {
578                 case 0:
579                         if (strcmp(lgopts[opt_idx].name, "help") == 0) {
580                                 usage(argv[0]);
581                                 rte_exit(EXIT_SUCCESS, "Displayed help\n");
582                         }
583
584                         if (strcmp(lgopts[opt_idx].name, "group") == 0) {
585                                 n = atoi(optarg);
586                                 if (n >= 0)
587                                         flow_group = n;
588                                 else
589                                         rte_exit(EXIT_SUCCESS,
590                                                 "flow group should be >= 0\n");
591                                 printf("group %d / ", flow_group);
592                         }
593
594                         for (i = 0; i < RTE_DIM(flow_options); i++)
595                                 if (strcmp(lgopts[opt_idx].name,
596                                                 flow_options[i].str) == 0) {
597                                         flow_options[i].map[
598                                         (*flow_options[i].map_idx)++] =
599                                                 flow_options[i].mask;
600                                         printf("%s / ", flow_options[i].str);
601                                 }
602
603                         if (strcmp(lgopts[opt_idx].name,
604                                         "hairpin-rss") == 0) {
605                                 n = atoi(optarg);
606                                 if (n > 0)
607                                         hairpin_queues_num = n;
608                                 else
609                                         rte_exit(EXIT_SUCCESS,
610                                                 "Hairpin queues should be > 0\n");
611
612                                 flow_actions[actions_idx++] =
613                                         HAIRPIN_RSS_ACTION;
614                                 printf("hairpin-rss / ");
615                         }
616                         if (strcmp(lgopts[opt_idx].name,
617                                         "hairpin-queue") == 0) {
618                                 n = atoi(optarg);
619                                 if (n > 0)
620                                         hairpin_queues_num = n;
621                                 else
622                                         rte_exit(EXIT_SUCCESS,
623                                                 "Hairpin queues should be > 0\n");
624
625                                 flow_actions[actions_idx++] =
626                                         HAIRPIN_QUEUE_ACTION;
627                                 printf("hairpin-queue / ");
628                         }
629
630                         if (strcmp(lgopts[opt_idx].name, "raw-encap") == 0) {
631                                 printf("raw-encap ");
632                                 flow_actions[actions_idx++] =
633                                         FLOW_ITEM_MASK(
634                                                 RTE_FLOW_ACTION_TYPE_RAW_ENCAP
635                                         );
636
637                                 token = strtok(optarg, ",");
638                                 while (token != NULL) {
639                                         for (i = 0; i < RTE_DIM(flow_options); i++) {
640                                                 if (strcmp(flow_options[i].str, token) == 0) {
641                                                         printf("%s,", token);
642                                                         encap_data |= flow_options[i].mask;
643                                                         break;
644                                                 }
645                                                 /* Reached last item with no match */
646                                                 if (i == (RTE_DIM(flow_options) - 1)) {
647                                                         fprintf(stderr, "Invalid encap item: %s\n", token);
648                                                         usage(argv[0]);
649                                                         rte_exit(EXIT_SUCCESS, "Invalid encap item\n");
650                                                 }
651                                         }
652                                         token = strtok(NULL, ",");
653                                 }
654                                 printf(" / ");
655                         }
656                         if (strcmp(lgopts[opt_idx].name, "raw-decap") == 0) {
657                                 printf("raw-decap ");
658                                 flow_actions[actions_idx++] =
659                                         FLOW_ITEM_MASK(
660                                                 RTE_FLOW_ACTION_TYPE_RAW_DECAP
661                                         );
662
663                                 token = strtok(optarg, ",");
664                                 while (token != NULL) {
665                                         for (i = 0; i < RTE_DIM(flow_options); i++) {
666                                                 if (strcmp(flow_options[i].str, token) == 0) {
667                                                         printf("%s,", token);
668                                                         encap_data |= flow_options[i].mask;
669                                                         break;
670                                                 }
671                                                 /* Reached last item with no match */
672                                                 if (i == (RTE_DIM(flow_options) - 1)) {
673                                                         fprintf(stderr, "Invalid decap item: %s\n", token);
674                                                         usage(argv[0]);
675                                                         rte_exit(EXIT_SUCCESS, "Invalid decap item\n");
676                                                 }
677                                         }
678                                         token = strtok(NULL, ",");
679                                 }
680                                 printf(" / ");
681                         }
682                         /* Control */
683                         if (strcmp(lgopts[opt_idx].name,
684                                         "flows-count") == 0) {
685                                 n = atoi(optarg);
686                                 if (n > (int) iterations_number)
687                                         flows_count = n;
688                                 else {
689                                         printf("\n\nflows_count should be > %d\n",
690                                                 iterations_number);
691                                         rte_exit(EXIT_SUCCESS, " ");
692                                 }
693                         }
694                         if (strcmp(lgopts[opt_idx].name,
695                                         "dump-iterations") == 0)
696                                 dump_iterations = true;
697                         if (strcmp(lgopts[opt_idx].name,
698                                         "deletion-rate") == 0)
699                                 delete_flag = true;
700                         if (strcmp(lgopts[opt_idx].name,
701                                         "dump-socket-mem") == 0)
702                                 dump_socket_mem_flag = true;
703                         if (strcmp(lgopts[opt_idx].name,
704                                         "enable-fwd") == 0)
705                                 enable_fwd = true;
706                         break;
707                 default:
708                         fprintf(stderr, "Invalid option: %s\n", argv[optind]);
709                         usage(argv[0]);
710                         rte_exit(EXIT_SUCCESS, "Invalid option\n");
711                         break;
712                 }
713         }
714         printf("end_flow\n");
715 }
716
717 /* Dump the socket memory statistics on console */
718 static size_t
719 dump_socket_mem(FILE *f)
720 {
721         struct rte_malloc_socket_stats socket_stats;
722         unsigned int i = 0;
723         size_t total = 0;
724         size_t alloc = 0;
725         size_t free = 0;
726         unsigned int n_alloc = 0;
727         unsigned int n_free = 0;
728         bool active_nodes = false;
729
730
731         for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
732                 if (rte_malloc_get_socket_stats(i, &socket_stats) ||
733                     !socket_stats.heap_totalsz_bytes)
734                         continue;
735                 active_nodes = true;
736                 total += socket_stats.heap_totalsz_bytes;
737                 alloc += socket_stats.heap_allocsz_bytes;
738                 free += socket_stats.heap_freesz_bytes;
739                 n_alloc += socket_stats.alloc_count;
740                 n_free += socket_stats.free_count;
741                 if (dump_socket_mem_flag) {
742                         fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
743                         fprintf(f,
744                                 "\nSocket %u:\nsize(M) total: %.6lf\nalloc:"
745                                 " %.6lf(%.3lf%%)\nfree: %.6lf"
746                                 "\nmax: %.6lf"
747                                 "\ncount alloc: %u\nfree: %u\n",
748                                 i,
749                                 socket_stats.heap_totalsz_bytes / 1.0e6,
750                                 socket_stats.heap_allocsz_bytes / 1.0e6,
751                                 (double)socket_stats.heap_allocsz_bytes * 100 /
752                                 (double)socket_stats.heap_totalsz_bytes,
753                                 socket_stats.heap_freesz_bytes / 1.0e6,
754                                 socket_stats.greatest_free_size / 1.0e6,
755                                 socket_stats.alloc_count,
756                                 socket_stats.free_count);
757                                 fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
758                 }
759         }
760         if (dump_socket_mem_flag && active_nodes) {
761                 fprintf(f,
762                         "\nTotal: size(M)\ntotal: %.6lf"
763                         "\nalloc: %.6lf(%.3lf%%)\nfree: %.6lf"
764                         "\ncount alloc: %u\nfree: %u\n",
765                         total / 1.0e6, alloc / 1.0e6,
766                         (double)alloc * 100 / (double)total, free / 1.0e6,
767                         n_alloc, n_free);
768                 fprintf(f, "::::::::::::::::::::::::::::::::::::::::\n");
769         }
770         return alloc;
771 }
772
773 static void
774 print_flow_error(struct rte_flow_error error)
775 {
776         printf("Flow can't be created %d message: %s\n",
777                 error.type,
778                 error.message ? error.message : "(no stated reason)");
779 }
780
781 static inline void
782 destroy_flows(int port_id, struct rte_flow **flow_list)
783 {
784         struct rte_flow_error error;
785         clock_t start_iter, end_iter;
786         double cpu_time_used = 0;
787         double flows_rate;
788         double cpu_time_per_iter[MAX_ITERATIONS];
789         double delta;
790         uint32_t i;
791         int iter_id;
792
793         for (i = 0; i < MAX_ITERATIONS; i++)
794                 cpu_time_per_iter[i] = -1;
795
796         if (iterations_number > flows_count)
797                 iterations_number = flows_count;
798
799         /* Deletion Rate */
800         printf("Flows Deletion on port = %d\n", port_id);
801         start_iter = clock();
802         for (i = 0; i < flows_count; i++) {
803                 if (flow_list[i] == 0)
804                         break;
805
806                 memset(&error, 0x33, sizeof(error));
807                 if (rte_flow_destroy(port_id, flow_list[i], &error)) {
808                         print_flow_error(error);
809                         rte_exit(EXIT_FAILURE, "Error in deleting flow");
810                 }
811
812                 if (i && !((i + 1) % iterations_number)) {
813                         /* Save the deletion rate of each iter */
814                         end_iter = clock();
815                         delta = (double) (end_iter - start_iter);
816                         iter_id = ((i + 1) / iterations_number) - 1;
817                         cpu_time_per_iter[iter_id] =
818                                 delta / CLOCKS_PER_SEC;
819                         cpu_time_used += cpu_time_per_iter[iter_id];
820                         start_iter = clock();
821                 }
822         }
823
824         /* Deletion rate per iteration */
825         if (dump_iterations)
826                 for (i = 0; i < MAX_ITERATIONS; i++) {
827                         if (cpu_time_per_iter[i] == -1)
828                                 continue;
829                         delta = (double)(iterations_number /
830                                 cpu_time_per_iter[i]);
831                         flows_rate = delta / 1000;
832                         printf(":: Iteration #%d: %d flows "
833                                 "in %f sec[ Rate = %f K/Sec ]\n",
834                                 i, iterations_number,
835                                 cpu_time_per_iter[i], flows_rate);
836                 }
837
838         /* Deletion rate for all flows */
839         flows_rate = ((double) (flows_count / cpu_time_used) / 1000);
840         printf("\n:: Total flow deletion rate -> %f K/Sec\n",
841                 flows_rate);
842         printf(":: The time for deleting %d in flows %f seconds\n",
843                 flows_count, cpu_time_used);
844 }
845
846 static inline void
847 flows_handler(void)
848 {
849         struct rte_flow **flow_list;
850         struct rte_flow_error error;
851         clock_t start_iter, end_iter;
852         double cpu_time_used;
853         double flows_rate;
854         double cpu_time_per_iter[MAX_ITERATIONS];
855         double delta;
856         uint16_t nr_ports;
857         uint32_t i;
858         int port_id;
859         int iter_id;
860         uint32_t flow_index;
861         uint64_t global_items[MAX_ITEMS_NUM] = { 0 };
862         uint64_t global_actions[MAX_ACTIONS_NUM] = { 0 };
863
864         global_items[0] = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH);
865         global_actions[0] = FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP);
866
867         nr_ports = rte_eth_dev_count_avail();
868
869         for (i = 0; i < MAX_ITERATIONS; i++)
870                 cpu_time_per_iter[i] = -1;
871
872         if (iterations_number > flows_count)
873                 iterations_number = flows_count;
874
875         printf(":: Flows Count per port: %d\n", flows_count);
876
877         flow_list = rte_zmalloc("flow_list",
878                 (sizeof(struct rte_flow *) * flows_count) + 1, 0);
879         if (flow_list == NULL)
880                 rte_exit(EXIT_FAILURE, "No Memory available!");
881
882         for (port_id = 0; port_id < nr_ports; port_id++) {
883                 cpu_time_used = 0;
884                 flow_index = 0;
885                 if (flow_group > 0) {
886                         /*
887                          * Create global rule to jump into flow_group,
888                          * this way the app will avoid the default rules.
889                          *
890                          * Global rule:
891                          * group 0 eth / end actions jump group <flow_group>
892                          *
893                          */
894                         flow = generate_flow(port_id, 0, flow_attrs,
895                                 global_items, global_actions,
896                                 flow_group, 0, 0, 0, 0, &error);
897
898                         if (flow == NULL) {
899                                 print_flow_error(error);
900                                 rte_exit(EXIT_FAILURE, "error in creating flow");
901                         }
902                         flow_list[flow_index++] = flow;
903                 }
904
905                 /* Insertion Rate */
906                 printf("Flows insertion on port = %d\n", port_id);
907                 start_iter = clock();
908                 for (i = 0; i < flows_count; i++) {
909                         flow = generate_flow(port_id, flow_group,
910                                 flow_attrs, flow_items, flow_actions,
911                                 JUMP_ACTION_TABLE, i,
912                                 hairpin_queues_num,
913                                 encap_data, decap_data,
914                                 &error);
915
916                         if (force_quit)
917                                 i = flows_count;
918
919                         if (!flow) {
920                                 print_flow_error(error);
921                                 rte_exit(EXIT_FAILURE, "error in creating flow");
922                         }
923
924                         flow_list[flow_index++] = flow;
925
926                         if (i && !((i + 1) % iterations_number)) {
927                                 /* Save the insertion rate of each iter */
928                                 end_iter = clock();
929                                 delta = (double) (end_iter - start_iter);
930                                 iter_id = ((i + 1) / iterations_number) - 1;
931                                 cpu_time_per_iter[iter_id] =
932                                         delta / CLOCKS_PER_SEC;
933                                 cpu_time_used += cpu_time_per_iter[iter_id];
934                                 start_iter = clock();
935                         }
936                 }
937
938                 /* Iteration rate per iteration */
939                 if (dump_iterations)
940                         for (i = 0; i < MAX_ITERATIONS; i++) {
941                                 if (cpu_time_per_iter[i] == -1)
942                                         continue;
943                                 delta = (double)(iterations_number /
944                                         cpu_time_per_iter[i]);
945                                 flows_rate = delta / 1000;
946                                 printf(":: Iteration #%d: %d flows "
947                                         "in %f sec[ Rate = %f K/Sec ]\n",
948                                         i, iterations_number,
949                                         cpu_time_per_iter[i], flows_rate);
950                         }
951
952                 /* Insertion rate for all flows */
953                 flows_rate = ((double) (flows_count / cpu_time_used) / 1000);
954                 printf("\n:: Total flow insertion rate -> %f K/Sec\n",
955                                                 flows_rate);
956                 printf(":: The time for creating %d in flows %f seconds\n",
957                                                 flows_count, cpu_time_used);
958
959                 if (delete_flag)
960                         destroy_flows(port_id, flow_list);
961         }
962 }
963
964 static void
965 signal_handler(int signum)
966 {
967         if (signum == SIGINT || signum == SIGTERM) {
968                 printf("\n\nSignal %d received, preparing to exit...\n",
969                                         signum);
970                 printf("Error: Stats are wrong due to sudden signal!\n\n");
971                 force_quit = true;
972         }
973 }
974
975 static inline uint16_t
976 do_rx(struct lcore_info *li, uint16_t rx_port, uint16_t rx_queue)
977 {
978         uint16_t cnt = 0;
979         cnt = rte_eth_rx_burst(rx_port, rx_queue, li->pkts, MAX_PKT_BURST);
980         li->rx_pkts += cnt;
981         return cnt;
982 }
983
984 static inline void
985 do_tx(struct lcore_info *li, uint16_t cnt, uint16_t tx_port,
986                         uint16_t tx_queue)
987 {
988         uint16_t nr_tx = 0;
989         uint16_t i;
990
991         nr_tx = rte_eth_tx_burst(tx_port, tx_queue, li->pkts, cnt);
992         li->tx_pkts  += nr_tx;
993         li->tx_drops += cnt - nr_tx;
994
995         for (i = nr_tx; i < cnt; i++)
996                 rte_pktmbuf_free(li->pkts[i]);
997 }
998
999 /*
1000  * Method to convert numbers into pretty numbers that easy
1001  * to read. The design here is to add comma after each three
1002  * digits and set all of this inside buffer.
1003  *
1004  * For example if n = 1799321, the output will be
1005  * 1,799,321 after this method which is easier to read.
1006  */
1007 static char *
1008 pretty_number(uint64_t n, char *buf)
1009 {
1010         char p[6][4];
1011         int i = 0;
1012         int off = 0;
1013
1014         while (n > 1000) {
1015                 sprintf(p[i], "%03d", (int)(n % 1000));
1016                 n /= 1000;
1017                 i += 1;
1018         }
1019
1020         sprintf(p[i++], "%d", (int)n);
1021
1022         while (i--)
1023                 off += sprintf(buf + off, "%s,", p[i]);
1024         buf[strlen(buf) - 1] = '\0';
1025
1026         return buf;
1027 }
1028
1029 static void
1030 packet_per_second_stats(void)
1031 {
1032         struct lcore_info *old;
1033         struct lcore_info *li, *oli;
1034         int nr_lines = 0;
1035         int i;
1036
1037         old = rte_zmalloc("old",
1038                 sizeof(struct lcore_info) * MAX_LCORES, 0);
1039         if (old == NULL)
1040                 rte_exit(EXIT_FAILURE, "No Memory available!");
1041
1042         memcpy(old, lcore_infos,
1043                 sizeof(struct lcore_info) * MAX_LCORES);
1044
1045         while (!force_quit) {
1046                 uint64_t total_tx_pkts = 0;
1047                 uint64_t total_rx_pkts = 0;
1048                 uint64_t total_tx_drops = 0;
1049                 uint64_t tx_delta, rx_delta, drops_delta;
1050                 char buf[3][32];
1051                 int nr_valid_core = 0;
1052
1053                 sleep(1);
1054
1055                 if (nr_lines) {
1056                         char go_up_nr_lines[16];
1057
1058                         sprintf(go_up_nr_lines, "%c[%dA\r", 27, nr_lines);
1059                         printf("%s\r", go_up_nr_lines);
1060                 }
1061
1062                 printf("\n%6s %16s %16s %16s\n", "core", "tx", "tx drops", "rx");
1063                 printf("%6s %16s %16s %16s\n", "------", "----------------",
1064                         "----------------", "----------------");
1065                 nr_lines = 3;
1066                 for (i = 0; i < MAX_LCORES; i++) {
1067                         li  = &lcore_infos[i];
1068                         oli = &old[i];
1069                         if (li->mode != LCORE_MODE_PKT)
1070                                 continue;
1071
1072                         tx_delta    = li->tx_pkts  - oli->tx_pkts;
1073                         rx_delta    = li->rx_pkts  - oli->rx_pkts;
1074                         drops_delta = li->tx_drops - oli->tx_drops;
1075                         printf("%6d %16s %16s %16s\n", i,
1076                                 pretty_number(tx_delta,    buf[0]),
1077                                 pretty_number(drops_delta, buf[1]),
1078                                 pretty_number(rx_delta,    buf[2]));
1079
1080                         total_tx_pkts  += tx_delta;
1081                         total_rx_pkts  += rx_delta;
1082                         total_tx_drops += drops_delta;
1083
1084                         nr_valid_core++;
1085                         nr_lines += 1;
1086                 }
1087
1088                 if (nr_valid_core > 1) {
1089                         printf("%6s %16s %16s %16s\n", "total",
1090                                 pretty_number(total_tx_pkts,  buf[0]),
1091                                 pretty_number(total_tx_drops, buf[1]),
1092                                 pretty_number(total_rx_pkts,  buf[2]));
1093                         nr_lines += 1;
1094                 }
1095
1096                 memcpy(old, lcore_infos,
1097                         sizeof(struct lcore_info) * MAX_LCORES);
1098         }
1099 }
1100
1101 static int
1102 start_forwarding(void *data __rte_unused)
1103 {
1104         int lcore = rte_lcore_id();
1105         int stream_id;
1106         uint16_t cnt;
1107         struct lcore_info *li = &lcore_infos[lcore];
1108
1109         if (!li->mode)
1110                 return 0;
1111
1112         if (li->mode == LCORE_MODE_STATS) {
1113                 printf(":: started stats on lcore %u\n", lcore);
1114                 packet_per_second_stats();
1115                 return 0;
1116         }
1117
1118         while (!force_quit)
1119                 for (stream_id = 0; stream_id < MAX_STREAMS; stream_id++) {
1120                         if (li->streams[stream_id].rx_port == -1)
1121                                 continue;
1122
1123                         cnt = do_rx(li,
1124                                         li->streams[stream_id].rx_port,
1125                                         li->streams[stream_id].rx_queue);
1126                         if (cnt)
1127                                 do_tx(li, cnt,
1128                                         li->streams[stream_id].tx_port,
1129                                         li->streams[stream_id].tx_queue);
1130                 }
1131         return 0;
1132 }
1133
1134 static void
1135 init_lcore_info(void)
1136 {
1137         int i, j;
1138         unsigned int lcore;
1139         uint16_t nr_port;
1140         uint16_t queue;
1141         int port;
1142         int stream_id = 0;
1143         int streams_per_core;
1144         int unassigned_streams;
1145         int nb_fwd_streams;
1146         nr_port = rte_eth_dev_count_avail();
1147
1148         /* First logical core is reserved for stats printing */
1149         lcore = rte_get_next_lcore(-1, 0, 0);
1150         lcore_infos[lcore].mode = LCORE_MODE_STATS;
1151
1152         /*
1153          * Initialize all cores
1154          * All cores at first must have -1 value in all streams
1155          * This means that this stream is not used, or not set
1156          * yet.
1157          */
1158         for (i = 0; i < MAX_LCORES; i++)
1159                 for (j = 0; j < MAX_STREAMS; j++) {
1160                         lcore_infos[i].streams[j].tx_port = -1;
1161                         lcore_infos[i].streams[j].rx_port = -1;
1162                         lcore_infos[i].streams[j].tx_queue = -1;
1163                         lcore_infos[i].streams[j].rx_queue = -1;
1164                         lcore_infos[i].streams_nb = 0;
1165                 }
1166
1167         /*
1168          * Calculate the total streams count.
1169          * Also distribute those streams count between the available
1170          * logical cores except first core, since it's reserved for
1171          * stats prints.
1172          */
1173         nb_fwd_streams = nr_port * RXQ_NUM;
1174         if ((int)(nb_lcores - 1) >= nb_fwd_streams)
1175                 for (i = 0; i < (int)(nb_lcores - 1); i++) {
1176                         lcore = rte_get_next_lcore(lcore, 0, 0);
1177                         lcore_infos[lcore].streams_nb = 1;
1178                 }
1179         else {
1180                 streams_per_core = nb_fwd_streams / (nb_lcores - 1);
1181                 unassigned_streams = nb_fwd_streams % (nb_lcores - 1);
1182                 for (i = 0; i < (int)(nb_lcores - 1); i++) {
1183                         lcore = rte_get_next_lcore(lcore, 0, 0);
1184                         lcore_infos[lcore].streams_nb = streams_per_core;
1185                         if (unassigned_streams) {
1186                                 lcore_infos[lcore].streams_nb++;
1187                                 unassigned_streams--;
1188                         }
1189                 }
1190         }
1191
1192         /*
1193          * Set the streams for the cores according to each logical
1194          * core stream count.
1195          * The streams is built on the design of what received should
1196          * forward as well, this means that if you received packets on
1197          * port 0 queue 0 then the same queue should forward the
1198          * packets, using the same logical core.
1199          */
1200         lcore = rte_get_next_lcore(-1, 0, 0);
1201         for (port = 0; port < nr_port; port++) {
1202                 /* Create FWD stream */
1203                 for (queue = 0; queue < RXQ_NUM; queue++) {
1204                         if (!lcore_infos[lcore].streams_nb ||
1205                                 !(stream_id % lcore_infos[lcore].streams_nb)) {
1206                                 lcore = rte_get_next_lcore(lcore, 0, 0);
1207                                 lcore_infos[lcore].mode = LCORE_MODE_PKT;
1208                                 stream_id = 0;
1209                         }
1210                         lcore_infos[lcore].streams[stream_id].rx_queue = queue;
1211                         lcore_infos[lcore].streams[stream_id].tx_queue = queue;
1212                         lcore_infos[lcore].streams[stream_id].rx_port = port;
1213                         lcore_infos[lcore].streams[stream_id].tx_port = port;
1214                         stream_id++;
1215                 }
1216         }
1217
1218         /* Print all streams */
1219         printf(":: Stream -> core id[N]: (rx_port, rx_queue)->(tx_port, tx_queue)\n");
1220         for (i = 0; i < MAX_LCORES; i++)
1221                 for (j = 0; j < MAX_STREAMS; j++) {
1222                         /* No streams for this core */
1223                         if (lcore_infos[i].streams[j].tx_port == -1)
1224                                 break;
1225                         printf("Stream -> core id[%d]: (%d,%d)->(%d,%d)\n",
1226                                 i,
1227                                 lcore_infos[i].streams[j].rx_port,
1228                                 lcore_infos[i].streams[j].rx_queue,
1229                                 lcore_infos[i].streams[j].tx_port,
1230                                 lcore_infos[i].streams[j].tx_queue);
1231                 }
1232 }
1233
1234 static void
1235 init_port(void)
1236 {
1237         int ret;
1238         uint16_t std_queue;
1239         uint16_t hairpin_queue;
1240         uint16_t port_id;
1241         uint16_t nr_ports;
1242         uint16_t nr_queues;
1243         struct rte_eth_hairpin_conf hairpin_conf = {
1244                 .peer_count = 1,
1245         };
1246         struct rte_eth_conf port_conf = {
1247                 .rx_adv_conf = {
1248                         .rss_conf.rss_hf =
1249                                 GET_RSS_HF(),
1250                 }
1251         };
1252         struct rte_eth_txconf txq_conf;
1253         struct rte_eth_rxconf rxq_conf;
1254         struct rte_eth_dev_info dev_info;
1255
1256         nr_queues = RXQ_NUM;
1257         if (hairpin_queues_num != 0)
1258                 nr_queues = RXQ_NUM + hairpin_queues_num;
1259
1260         nr_ports = rte_eth_dev_count_avail();
1261         if (nr_ports == 0)
1262                 rte_exit(EXIT_FAILURE, "Error: no port detected\n");
1263
1264         mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool",
1265                                         TOTAL_MBUF_NUM, MBUF_CACHE_SIZE,
1266                                         0, MBUF_SIZE,
1267                                         rte_socket_id());
1268         if (mbuf_mp == NULL)
1269                 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n");
1270
1271         for (port_id = 0; port_id < nr_ports; port_id++) {
1272                 ret = rte_eth_dev_info_get(port_id, &dev_info);
1273                 if (ret != 0)
1274                         rte_exit(EXIT_FAILURE,
1275                                 "Error during getting device"
1276                                 " (port %u) info: %s\n",
1277                                 port_id, strerror(-ret));
1278
1279                 port_conf.txmode.offloads &= dev_info.tx_offload_capa;
1280                 port_conf.rxmode.offloads &= dev_info.rx_offload_capa;
1281
1282                 printf(":: initializing port: %d\n", port_id);
1283
1284                 ret = rte_eth_dev_configure(port_id, nr_queues,
1285                                 nr_queues, &port_conf);
1286                 if (ret < 0)
1287                         rte_exit(EXIT_FAILURE,
1288                                 ":: cannot configure device: err=%d, port=%u\n",
1289                                 ret, port_id);
1290
1291                 rxq_conf = dev_info.default_rxconf;
1292                 for (std_queue = 0; std_queue < RXQ_NUM; std_queue++) {
1293                         ret = rte_eth_rx_queue_setup(port_id, std_queue, NR_RXD,
1294                                         rte_eth_dev_socket_id(port_id),
1295                                         &rxq_conf,
1296                                         mbuf_mp);
1297                         if (ret < 0)
1298                                 rte_exit(EXIT_FAILURE,
1299                                         ":: Rx queue setup failed: err=%d, port=%u\n",
1300                                         ret, port_id);
1301                 }
1302
1303                 txq_conf = dev_info.default_txconf;
1304                 for (std_queue = 0; std_queue < TXQ_NUM; std_queue++) {
1305                         ret = rte_eth_tx_queue_setup(port_id, std_queue, NR_TXD,
1306                                         rte_eth_dev_socket_id(port_id),
1307                                         &txq_conf);
1308                         if (ret < 0)
1309                                 rte_exit(EXIT_FAILURE,
1310                                         ":: Tx queue setup failed: err=%d, port=%u\n",
1311                                         ret, port_id);
1312                 }
1313
1314                 /* Catch all packets from traffic generator. */
1315                 ret = rte_eth_promiscuous_enable(port_id);
1316                 if (ret != 0)
1317                         rte_exit(EXIT_FAILURE,
1318                                 ":: promiscuous mode enable failed: err=%s, port=%u\n",
1319                                 rte_strerror(-ret), port_id);
1320
1321                 if (hairpin_queues_num != 0) {
1322                         /*
1323                          * Configure peer which represents hairpin Tx.
1324                          * Hairpin queue numbers start after standard queues
1325                          * (RXQ_NUM and TXQ_NUM).
1326                          */
1327                         for (hairpin_queue = RXQ_NUM, std_queue = 0;
1328                                         hairpin_queue < nr_queues;
1329                                         hairpin_queue++, std_queue++) {
1330                                 hairpin_conf.peers[0].port = port_id;
1331                                 hairpin_conf.peers[0].queue =
1332                                         std_queue + TXQ_NUM;
1333                                 ret = rte_eth_rx_hairpin_queue_setup(
1334                                                 port_id, hairpin_queue,
1335                                                 NR_RXD, &hairpin_conf);
1336                                 if (ret != 0)
1337                                         rte_exit(EXIT_FAILURE,
1338                                                 ":: Hairpin rx queue setup failed: err=%d, port=%u\n",
1339                                                 ret, port_id);
1340                         }
1341
1342                         for (hairpin_queue = TXQ_NUM, std_queue = 0;
1343                                         hairpin_queue < nr_queues;
1344                                         hairpin_queue++, std_queue++) {
1345                                 hairpin_conf.peers[0].port = port_id;
1346                                 hairpin_conf.peers[0].queue =
1347                                         std_queue + RXQ_NUM;
1348                                 ret = rte_eth_tx_hairpin_queue_setup(
1349                                                 port_id, hairpin_queue,
1350                                                 NR_TXD, &hairpin_conf);
1351                                 if (ret != 0)
1352                                         rte_exit(EXIT_FAILURE,
1353                                                 ":: Hairpin tx queue setup failed: err=%d, port=%u\n",
1354                                                 ret, port_id);
1355                         }
1356                 }
1357
1358                 ret = rte_eth_dev_start(port_id);
1359                 if (ret < 0)
1360                         rte_exit(EXIT_FAILURE,
1361                                 "rte_eth_dev_start:err=%d, port=%u\n",
1362                                 ret, port_id);
1363
1364                 printf(":: initializing port: %d done\n", port_id);
1365         }
1366 }
1367
1368 int
1369 main(int argc, char **argv)
1370 {
1371         int ret;
1372         uint16_t port;
1373         struct rte_flow_error error;
1374         int64_t alloc, last_alloc;
1375
1376         ret = rte_eal_init(argc, argv);
1377         if (ret < 0)
1378                 rte_exit(EXIT_FAILURE, "EAL init failed\n");
1379
1380         force_quit = false;
1381         dump_iterations = false;
1382         flows_count = DEFAULT_RULES_COUNT;
1383         iterations_number = DEFAULT_ITERATION;
1384         delete_flag = false;
1385         dump_socket_mem_flag = false;
1386         flow_group = 0;
1387
1388         signal(SIGINT, signal_handler);
1389         signal(SIGTERM, signal_handler);
1390
1391         argc -= ret;
1392         argv += ret;
1393         if (argc > 1)
1394                 args_parse(argc, argv);
1395
1396         init_port();
1397
1398         nb_lcores = rte_lcore_count();
1399         if (nb_lcores <= 1)
1400                 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n");
1401
1402         last_alloc = (int64_t)dump_socket_mem(stdout);
1403         flows_handler();
1404         alloc = (int64_t)dump_socket_mem(stdout);
1405
1406         if (last_alloc)
1407                 fprintf(stdout, ":: Memory allocation change(M): %.6lf\n",
1408                 (alloc - last_alloc) / 1.0e6);
1409
1410         if (enable_fwd) {
1411                 init_lcore_info();
1412                 rte_eal_mp_remote_launch(start_forwarding, NULL, CALL_MASTER);
1413         }
1414
1415         RTE_ETH_FOREACH_DEV(port) {
1416                 rte_flow_flush(port, &error);
1417                 rte_eth_dev_stop(port);
1418                 rte_eth_dev_close(port);
1419         }
1420         return 0;
1421 }