d102ec4d92cb05cc323dd5726dd848b8464e1ae4
[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
31 #include <rte_malloc.h>
32 #include <rte_mempool.h>
33 #include <rte_mbuf.h>
34 #include <rte_ethdev.h>
35 #include <rte_flow.h>
36
37 #include "config.h"
38 #include "flow_gen.h"
39
40 #define MAX_ITERATIONS             100
41 #define DEFAULT_RULES_COUNT    4000000
42 #define DEFAULT_ITERATION       100000
43
44 struct rte_flow *flow;
45 static uint8_t flow_group;
46
47 static uint64_t flow_items;
48 static uint64_t flow_actions;
49 static uint64_t flow_attrs;
50 static volatile bool force_quit;
51 static bool dump_iterations;
52 static bool delete_flag;
53 static bool dump_socket_mem_flag;
54 static struct rte_mempool *mbuf_mp;
55 static uint32_t nb_lcores;
56 static uint32_t flows_count;
57 static uint32_t iterations_number;
58 static uint32_t hairpinq;
59
60 static void
61 usage(char *progname)
62 {
63         printf("\nusage: %s\n", progname);
64         printf("\nControl configurations:\n");
65         printf("  --flows-count=N: to set the number of needed"
66                 " flows to insert, default is 4,000,000\n");
67         printf("  --dump-iterations: To print rates for each"
68                 " iteration\n");
69         printf("  --deletion-rate: Enable deletion rate"
70                 " calculations\n");
71         printf("  --dump-socket-mem: To dump all socket memory\n");
72
73         printf("To set flow attributes:\n");
74         printf("  --ingress: set ingress attribute in flows\n");
75         printf("  --egress: set egress attribute in flows\n");
76         printf("  --transfer: set transfer attribute in flows\n");
77         printf("  --group=N: set group for all flows,"
78                 " default is 0\n");
79
80         printf("To set flow items:\n");
81         printf("  --ether: add ether layer in flow items\n");
82         printf("  --vlan: add vlan layer in flow items\n");
83         printf("  --ipv4: add ipv4 layer in flow items\n");
84         printf("  --ipv6: add ipv6 layer in flow items\n");
85         printf("  --tcp: add tcp layer in flow items\n");
86         printf("  --udp: add udp layer in flow items\n");
87         printf("  --vxlan: add vxlan layer in flow items\n");
88         printf("  --vxlan-gpe: add vxlan-gpe layer in flow items\n");
89         printf("  --gre: add gre layer in flow items\n");
90         printf("  --geneve: add geneve layer in flow items\n");
91         printf("  --gtp: add gtp layer in flow items\n");
92         printf("  --meta: add meta layer in flow items\n");
93         printf("  --tag: add tag layer in flow items\n");
94
95         printf("To set flow actions:\n");
96         printf("  --port-id: add port-id action in flow actions\n");
97         printf("  --rss: add rss action in flow actions\n");
98         printf("  --queue: add queue action in flow actions\n");
99         printf("  --jump: add jump action in flow actions\n");
100         printf("  --mark: add mark action in flow actions\n");
101         printf("  --count: add count action in flow actions\n");
102         printf("  --set-meta: add set meta action in flow actions\n");
103         printf("  --set-tag: add set tag action in flow actions\n");
104         printf("  --drop: add drop action in flow actions\n");
105         printf("  --hairpin-queue=N: add hairpin-queue action in flow actions\n");
106         printf("  --hairpin-rss=N: add hairping-rss action in flow actions\n");
107 }
108
109 static void
110 args_parse(int argc, char **argv)
111 {
112         char **argvopt;
113         int n, opt;
114         int opt_idx;
115         size_t i;
116
117         static const struct option_dict {
118                 const char *str;
119                 const uint64_t mask;
120                 uint64_t *bitmap;
121         } flow_options[] = {
122                 {
123                         .str = "ether",
124                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH),
125                         .bitmap = &flow_items
126                 },
127                 {
128                         .str = "ipv4",
129                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV4),
130                         .bitmap = &flow_items
131                 },
132                 {
133                         .str = "ipv6",
134                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV6),
135                         .bitmap = &flow_items
136                 },
137                 {
138                         .str = "vlan",
139                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VLAN),
140                         .bitmap = &flow_items
141                 },
142                 {
143                         .str = "tcp",
144                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TCP),
145                         .bitmap = &flow_items
146                 },
147                 {
148                         .str = "udp",
149                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_UDP),
150                         .bitmap = &flow_items
151                 },
152                 {
153                         .str = "vxlan",
154                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN),
155                         .bitmap = &flow_items
156                 },
157                 {
158                         .str = "vxlan-gpe",
159                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN_GPE),
160                         .bitmap = &flow_items
161                 },
162                 {
163                         .str = "gre",
164                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GRE),
165                         .bitmap = &flow_items
166                 },
167                 {
168                         .str = "geneve",
169                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GENEVE),
170                         .bitmap = &flow_items
171                 },
172                 {
173                         .str = "gtp",
174                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GTP),
175                         .bitmap = &flow_items
176                 },
177                 {
178                         .str = "meta",
179                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_META),
180                         .bitmap = &flow_items
181                 },
182                 {
183                         .str = "tag",
184                         .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TAG),
185                         .bitmap = &flow_items
186                 },
187                 {
188                         .str = "ingress",
189                         .mask = INGRESS,
190                         .bitmap = &flow_attrs
191                 },
192                 {
193                         .str = "egress",
194                         .mask = EGRESS,
195                         .bitmap = &flow_attrs
196                 },
197                 {
198                         .str = "transfer",
199                         .mask = TRANSFER,
200                         .bitmap = &flow_attrs
201                 },
202                 {
203                         .str = "port-id",
204                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_PORT_ID),
205                         .bitmap = &flow_actions
206                 },
207                 {
208                         .str = "rss",
209                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_RSS),
210                         .bitmap = &flow_actions
211                 },
212                 {
213                         .str = "queue",
214                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_QUEUE),
215                         .bitmap = &flow_actions
216                 },
217                 {
218                         .str = "jump",
219                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_JUMP),
220                         .bitmap = &flow_actions
221                 },
222                 {
223                         .str = "mark",
224                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_MARK),
225                         .bitmap = &flow_actions
226                 },
227                 {
228                         .str = "count",
229                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_COUNT),
230                         .bitmap = &flow_actions
231                 },
232                 {
233                         .str = "set-meta",
234                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_META),
235                         .bitmap = &flow_actions
236                 },
237                 {
238                         .str = "set-tag",
239                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_TAG),
240                         .bitmap = &flow_actions
241                 },
242                 {
243                         .str = "drop",
244                         .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_DROP),
245                         .bitmap = &flow_actions
246                 }
247         };
248
249         static const struct option lgopts[] = {
250                 /* Control */
251                 { "help",                       0, 0, 0 },
252                 { "flows-count",                1, 0, 0 },
253                 { "dump-iterations",            0, 0, 0 },
254                 { "deletion-rate",              0, 0, 0 },
255                 { "dump-socket-mem",            0, 0, 0 },
256                 /* Attributes */
257                 { "ingress",                    0, 0, 0 },
258                 { "egress",                     0, 0, 0 },
259                 { "transfer",                   0, 0, 0 },
260                 { "group",                      1, 0, 0 },
261                 /* Items */
262                 { "ether",                      0, 0, 0 },
263                 { "vlan",                       0, 0, 0 },
264                 { "ipv4",                       0, 0, 0 },
265                 { "ipv6",                       0, 0, 0 },
266                 { "tcp",                        0, 0, 0 },
267                 { "udp",                        0, 0, 0 },
268                 { "vxlan",                      0, 0, 0 },
269                 { "vxlan-gpe",                  0, 0, 0 },
270                 { "gre",                        0, 0, 0 },
271                 { "geneve",                     0, 0, 0 },
272                 { "gtp",                        0, 0, 0 },
273                 { "meta",                       0, 0, 0 },
274                 { "tag",                        0, 0, 0 },
275                 /* Actions */
276                 { "port-id",                    0, 0, 0 },
277                 { "rss",                        0, 0, 0 },
278                 { "queue",                      0, 0, 0 },
279                 { "jump",                       0, 0, 0 },
280                 { "mark",                       0, 0, 0 },
281                 { "count",                      0, 0, 0 },
282                 { "set-meta",                   0, 0, 0 },
283                 { "set-tag",                    0, 0, 0 },
284                 { "drop",                       0, 0, 0 },
285                 { "hairpin-queue",              1, 0, 0 },
286                 { "hairpin-rss",                1, 0, 0 },
287         };
288
289         flow_items = 0;
290         flow_actions = 0;
291         flow_attrs = 0;
292         hairpinq = 0;
293         argvopt = argv;
294
295         printf(":: Flow -> ");
296         while ((opt = getopt_long(argc, argvopt, "",
297                                 lgopts, &opt_idx)) != EOF) {
298                 switch (opt) {
299                 case 0:
300                         if (strcmp(lgopts[opt_idx].name, "help") == 0) {
301                                 usage(argv[0]);
302                                 rte_exit(EXIT_SUCCESS, "Displayed help\n");
303                         }
304
305                         if (strcmp(lgopts[opt_idx].name, "group") == 0) {
306                                 n = atoi(optarg);
307                                 if (n >= 0)
308                                         flow_group = n;
309                                 else
310                                         rte_exit(EXIT_SUCCESS,
311                                                 "flow group should be >= 0\n");
312                                 printf("group %d ", flow_group);
313                         }
314
315                         for (i = 0; i < RTE_DIM(flow_options); i++)
316                                 if (strcmp(lgopts[opt_idx].name,
317                                                 flow_options[i].str) == 0) {
318                                         *flow_options[i].bitmap |=
319                                                 flow_options[i].mask;
320                                         printf("%s / ", flow_options[i].str);
321                                 }
322
323                         if (strcmp(lgopts[opt_idx].name,
324                                         "hairpin-rss") == 0) {
325                                 n = atoi(optarg);
326                                 if (n > 0)
327                                         hairpinq = n;
328                                 else
329                                         rte_exit(EXIT_SUCCESS,
330                                                 "Hairpin queues should be > 0\n");
331
332                                 flow_actions |= HAIRPIN_RSS_ACTION;
333                                 printf("hairpin-rss / ");
334                         }
335                         if (strcmp(lgopts[opt_idx].name,
336                                         "hairpin-queue") == 0) {
337                                 n = atoi(optarg);
338                                 if (n > 0)
339                                         hairpinq = n;
340                                 else
341                                         rte_exit(EXIT_SUCCESS,
342                                                 "Hairpin queues should be > 0\n");
343
344                                 flow_actions |= HAIRPIN_QUEUE_ACTION;
345                                 printf("hairpin-queue / ");
346                         }
347
348                         /* Control */
349                         if (strcmp(lgopts[opt_idx].name,
350                                         "flows-count") == 0) {
351                                 n = atoi(optarg);
352                                 if (n > (int) iterations_number)
353                                         flows_count = n;
354                                 else {
355                                         printf("\n\nflows_count should be > %d\n",
356                                                 iterations_number);
357                                         rte_exit(EXIT_SUCCESS, " ");
358                                 }
359                         }
360                         if (strcmp(lgopts[opt_idx].name,
361                                         "dump-iterations") == 0)
362                                 dump_iterations = true;
363                         if (strcmp(lgopts[opt_idx].name,
364                                         "deletion-rate") == 0)
365                                 delete_flag = true;
366                         if (strcmp(lgopts[opt_idx].name,
367                                         "dump-socket-mem") == 0)
368                                 dump_socket_mem_flag = true;
369                         break;
370                 default:
371                         fprintf(stderr, "Invalid option: %s\n", argv[optind]);
372                         usage(argv[0]);
373                         rte_exit(EXIT_SUCCESS, "Invalid option\n");
374                         break;
375                 }
376         }
377         printf("end_flow\n");
378 }
379
380 /* Dump the socket memory statistics on console */
381 static size_t
382 dump_socket_mem(FILE *f)
383 {
384         struct rte_malloc_socket_stats socket_stats;
385         unsigned int i = 0;
386         size_t total = 0;
387         size_t alloc = 0;
388         size_t free = 0;
389         unsigned int n_alloc = 0;
390         unsigned int n_free = 0;
391         bool active_nodes = false;
392
393
394         for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
395                 if (rte_malloc_get_socket_stats(i, &socket_stats) ||
396                     !socket_stats.heap_totalsz_bytes)
397                         continue;
398                 active_nodes = true;
399                 total += socket_stats.heap_totalsz_bytes;
400                 alloc += socket_stats.heap_allocsz_bytes;
401                 free += socket_stats.heap_freesz_bytes;
402                 n_alloc += socket_stats.alloc_count;
403                 n_free += socket_stats.free_count;
404                 if (dump_socket_mem_flag) {
405                         fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
406                         fprintf(f,
407                                 "\nSocket %u:\nsize(M) total: %.6lf\nalloc:"
408                                 " %.6lf(%.3lf%%)\nfree: %.6lf"
409                                 "\nmax: %.6lf"
410                                 "\ncount alloc: %u\nfree: %u\n",
411                                 i,
412                                 socket_stats.heap_totalsz_bytes / 1.0e6,
413                                 socket_stats.heap_allocsz_bytes / 1.0e6,
414                                 (double)socket_stats.heap_allocsz_bytes * 100 /
415                                 (double)socket_stats.heap_totalsz_bytes,
416                                 socket_stats.heap_freesz_bytes / 1.0e6,
417                                 socket_stats.greatest_free_size / 1.0e6,
418                                 socket_stats.alloc_count,
419                                 socket_stats.free_count);
420                                 fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
421                 }
422         }
423         if (dump_socket_mem_flag && active_nodes) {
424                 fprintf(f,
425                         "\nTotal: size(M)\ntotal: %.6lf"
426                         "\nalloc: %.6lf(%.3lf%%)\nfree: %.6lf"
427                         "\ncount alloc: %u\nfree: %u\n",
428                         total / 1.0e6, alloc / 1.0e6,
429                         (double)alloc * 100 / (double)total, free / 1.0e6,
430                         n_alloc, n_free);
431                 fprintf(f, "::::::::::::::::::::::::::::::::::::::::\n");
432         }
433         return alloc;
434 }
435
436 static void
437 print_flow_error(struct rte_flow_error error)
438 {
439         printf("Flow can't be created %d message: %s\n",
440                 error.type,
441                 error.message ? error.message : "(no stated reason)");
442 }
443
444 static inline void
445 destroy_flows(int port_id, struct rte_flow **flow_list)
446 {
447         struct rte_flow_error error;
448         clock_t start_iter, end_iter;
449         double cpu_time_used = 0;
450         double flows_rate;
451         double cpu_time_per_iter[MAX_ITERATIONS];
452         double delta;
453         uint32_t i;
454         int iter_id;
455
456         for (i = 0; i < MAX_ITERATIONS; i++)
457                 cpu_time_per_iter[i] = -1;
458
459         if (iterations_number > flows_count)
460                 iterations_number = flows_count;
461
462         /* Deletion Rate */
463         printf("Flows Deletion on port = %d\n", port_id);
464         start_iter = clock();
465         for (i = 0; i < flows_count; i++) {
466                 if (flow_list[i] == 0)
467                         break;
468
469                 memset(&error, 0x33, sizeof(error));
470                 if (rte_flow_destroy(port_id, flow_list[i], &error)) {
471                         print_flow_error(error);
472                         rte_exit(EXIT_FAILURE, "Error in deleting flow");
473                 }
474
475                 if (i && !((i + 1) % iterations_number)) {
476                         /* Save the deletion rate of each iter */
477                         end_iter = clock();
478                         delta = (double) (end_iter - start_iter);
479                         iter_id = ((i + 1) / iterations_number) - 1;
480                         cpu_time_per_iter[iter_id] =
481                                 delta / CLOCKS_PER_SEC;
482                         cpu_time_used += cpu_time_per_iter[iter_id];
483                         start_iter = clock();
484                 }
485         }
486
487         /* Deletion rate per iteration */
488         if (dump_iterations)
489                 for (i = 0; i < MAX_ITERATIONS; i++) {
490                         if (cpu_time_per_iter[i] == -1)
491                                 continue;
492                         delta = (double)(iterations_number /
493                                 cpu_time_per_iter[i]);
494                         flows_rate = delta / 1000;
495                         printf(":: Iteration #%d: %d flows "
496                                 "in %f sec[ Rate = %f K/Sec ]\n",
497                                 i, iterations_number,
498                                 cpu_time_per_iter[i], flows_rate);
499                 }
500
501         /* Deletion rate for all flows */
502         flows_rate = ((double) (flows_count / cpu_time_used) / 1000);
503         printf("\n:: Total flow deletion rate -> %f K/Sec\n",
504                 flows_rate);
505         printf(":: The time for deleting %d in flows %f seconds\n",
506                 flows_count, cpu_time_used);
507 }
508
509 static inline void
510 flows_handler(void)
511 {
512         struct rte_flow **flow_list;
513         struct rte_flow_error error;
514         clock_t start_iter, end_iter;
515         double cpu_time_used;
516         double flows_rate;
517         double cpu_time_per_iter[MAX_ITERATIONS];
518         double delta;
519         uint16_t nr_ports;
520         uint32_t i;
521         int port_id;
522         int iter_id;
523         uint32_t flow_index;
524
525         nr_ports = rte_eth_dev_count_avail();
526
527         for (i = 0; i < MAX_ITERATIONS; i++)
528                 cpu_time_per_iter[i] = -1;
529
530         if (iterations_number > flows_count)
531                 iterations_number = flows_count;
532
533         printf(":: Flows Count per port: %d\n", flows_count);
534
535         flow_list = rte_zmalloc("flow_list",
536                 (sizeof(struct rte_flow *) * flows_count) + 1, 0);
537         if (flow_list == NULL)
538                 rte_exit(EXIT_FAILURE, "No Memory available!");
539
540         for (port_id = 0; port_id < nr_ports; port_id++) {
541                 cpu_time_used = 0;
542                 flow_index = 0;
543                 if (flow_group > 0) {
544                         /*
545                          * Create global rule to jump into flow_group,
546                          * this way the app will avoid the default rules.
547                          *
548                          * Global rule:
549                          * group 0 eth / end actions jump group <flow_group>
550                          *
551                          */
552                         flow = generate_flow(port_id, 0, flow_attrs,
553                                 FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH),
554                                 FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP),
555                                 flow_group, 0, 0, &error);
556
557                         if (flow == NULL) {
558                                 print_flow_error(error);
559                                 rte_exit(EXIT_FAILURE, "error in creating flow");
560                         }
561                         flow_list[flow_index++] = flow;
562                 }
563
564                 /* Insertion Rate */
565                 printf("Flows insertion on port = %d\n", port_id);
566                 start_iter = clock();
567                 for (i = 0; i < flows_count; i++) {
568                         flow = generate_flow(port_id, flow_group,
569                                 flow_attrs, flow_items, flow_actions,
570                                 JUMP_ACTION_TABLE, i, hairpinq, &error);
571
572                         if (force_quit)
573                                 i = flows_count;
574
575                         if (!flow) {
576                                 print_flow_error(error);
577                                 rte_exit(EXIT_FAILURE, "error in creating flow");
578                         }
579
580                         flow_list[flow_index++] = flow;
581
582                         if (i && !((i + 1) % iterations_number)) {
583                                 /* Save the insertion rate of each iter */
584                                 end_iter = clock();
585                                 delta = (double) (end_iter - start_iter);
586                                 iter_id = ((i + 1) / iterations_number) - 1;
587                                 cpu_time_per_iter[iter_id] =
588                                         delta / CLOCKS_PER_SEC;
589                                 cpu_time_used += cpu_time_per_iter[iter_id];
590                                 start_iter = clock();
591                         }
592                 }
593
594                 /* Iteration rate per iteration */
595                 if (dump_iterations)
596                         for (i = 0; i < MAX_ITERATIONS; i++) {
597                                 if (cpu_time_per_iter[i] == -1)
598                                         continue;
599                                 delta = (double)(iterations_number /
600                                         cpu_time_per_iter[i]);
601                                 flows_rate = delta / 1000;
602                                 printf(":: Iteration #%d: %d flows "
603                                         "in %f sec[ Rate = %f K/Sec ]\n",
604                                         i, iterations_number,
605                                         cpu_time_per_iter[i], flows_rate);
606                         }
607
608                 /* Insertion rate for all flows */
609                 flows_rate = ((double) (flows_count / cpu_time_used) / 1000);
610                 printf("\n:: Total flow insertion rate -> %f K/Sec\n",
611                                                 flows_rate);
612                 printf(":: The time for creating %d in flows %f seconds\n",
613                                                 flows_count, cpu_time_used);
614
615                 if (delete_flag)
616                         destroy_flows(port_id, flow_list);
617         }
618 }
619
620 static void
621 signal_handler(int signum)
622 {
623         if (signum == SIGINT || signum == SIGTERM) {
624                 printf("\n\nSignal %d received, preparing to exit...\n",
625                                         signum);
626                 printf("Error: Stats are wrong due to sudden signal!\n\n");
627                 force_quit = true;
628         }
629 }
630
631 static void
632 init_port(void)
633 {
634         int ret;
635         uint16_t std_queue;
636         uint16_t hairpin_q;
637         uint16_t port_id;
638         uint16_t nr_ports;
639         uint16_t nr_queues;
640         struct rte_eth_hairpin_conf hairpin_conf = {
641                 .peer_count = 1,
642         };
643         struct rte_eth_conf port_conf = {
644                 .rx_adv_conf = {
645                         .rss_conf.rss_hf =
646                                 GET_RSS_HF(),
647                 }
648         };
649         struct rte_eth_txconf txq_conf;
650         struct rte_eth_rxconf rxq_conf;
651         struct rte_eth_dev_info dev_info;
652
653         nr_queues = RXQ_NUM;
654         if (hairpinq != 0)
655                 nr_queues = RXQ_NUM + hairpinq;
656
657         nr_ports = rte_eth_dev_count_avail();
658         if (nr_ports == 0)
659                 rte_exit(EXIT_FAILURE, "Error: no port detected\n");
660
661         mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool",
662                                         TOTAL_MBUF_NUM, MBUF_CACHE_SIZE,
663                                         0, MBUF_SIZE,
664                                         rte_socket_id());
665         if (mbuf_mp == NULL)
666                 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n");
667
668         for (port_id = 0; port_id < nr_ports; port_id++) {
669                 ret = rte_eth_dev_info_get(port_id, &dev_info);
670                 if (ret != 0)
671                         rte_exit(EXIT_FAILURE,
672                                 "Error during getting device"
673                                 " (port %u) info: %s\n",
674                                 port_id, strerror(-ret));
675
676                 port_conf.txmode.offloads &= dev_info.tx_offload_capa;
677                 port_conf.rxmode.offloads &= dev_info.rx_offload_capa;
678
679                 printf(":: initializing port: %d\n", port_id);
680
681                 ret = rte_eth_dev_configure(port_id, nr_queues,
682                                 nr_queues, &port_conf);
683                 if (ret < 0)
684                         rte_exit(EXIT_FAILURE,
685                                 ":: cannot configure device: err=%d, port=%u\n",
686                                 ret, port_id);
687
688                 rxq_conf = dev_info.default_rxconf;
689                 for (std_queue = 0; std_queue < RXQ_NUM; std_queue++) {
690                         ret = rte_eth_rx_queue_setup(port_id, std_queue, NR_RXD,
691                                         rte_eth_dev_socket_id(port_id),
692                                         &rxq_conf,
693                                         mbuf_mp);
694                         if (ret < 0)
695                                 rte_exit(EXIT_FAILURE,
696                                         ":: Rx queue setup failed: err=%d, port=%u\n",
697                                         ret, port_id);
698                 }
699
700                 txq_conf = dev_info.default_txconf;
701                 for (std_queue = 0; std_queue < TXQ_NUM; std_queue++) {
702                         ret = rte_eth_tx_queue_setup(port_id, std_queue, NR_TXD,
703                                         rte_eth_dev_socket_id(port_id),
704                                         &txq_conf);
705                         if (ret < 0)
706                                 rte_exit(EXIT_FAILURE,
707                                         ":: Tx queue setup failed: err=%d, port=%u\n",
708                                         ret, port_id);
709                 }
710
711                 /* Catch all packets from traffic generator. */
712                 ret = rte_eth_promiscuous_enable(port_id);
713                 if (ret != 0)
714                         rte_exit(EXIT_FAILURE,
715                                 ":: promiscuous mode enable failed: err=%s, port=%u\n",
716                                 rte_strerror(-ret), port_id);
717
718                 if (hairpinq != 0) {
719                         for (hairpin_q = RXQ_NUM, std_queue = 0;
720                                         std_queue < nr_queues;
721                                         hairpin_q++, std_queue++) {
722                                 hairpin_conf.peers[0].port = port_id;
723                                 hairpin_conf.peers[0].queue =
724                                         std_queue + TXQ_NUM;
725                                 ret = rte_eth_rx_hairpin_queue_setup(
726                                                 port_id, hairpin_q,
727                                                 NR_RXD, &hairpin_conf);
728                                 if (ret != 0)
729                                         rte_exit(EXIT_FAILURE,
730                                                 ":: Hairpin rx queue setup failed: err=%d, port=%u\n",
731                                                 ret, port_id);
732                         }
733
734                         for (hairpin_q = TXQ_NUM, std_queue = 0;
735                                         std_queue < nr_queues;
736                                         hairpin_q++, std_queue++) {
737                                 hairpin_conf.peers[0].port = port_id;
738                                 hairpin_conf.peers[0].queue =
739                                         std_queue + RXQ_NUM;
740                                 ret = rte_eth_tx_hairpin_queue_setup(
741                                                 port_id, hairpin_q,
742                                                 NR_TXD, &hairpin_conf);
743                                 if (ret != 0)
744                                         rte_exit(EXIT_FAILURE,
745                                                 ":: Hairpin tx queue setup failed: err=%d, port=%u\n",
746                                                 ret, port_id);
747                         }
748                 }
749
750                 ret = rte_eth_dev_start(port_id);
751                 if (ret < 0)
752                         rte_exit(EXIT_FAILURE,
753                                 "rte_eth_dev_start:err=%d, port=%u\n",
754                                 ret, port_id);
755
756                 printf(":: initializing port: %d done\n", port_id);
757         }
758 }
759
760 int
761 main(int argc, char **argv)
762 {
763         int ret;
764         uint16_t port;
765         struct rte_flow_error error;
766         int64_t alloc, last_alloc;
767
768         ret = rte_eal_init(argc, argv);
769         if (ret < 0)
770                 rte_exit(EXIT_FAILURE, "EAL init failed\n");
771
772         force_quit = false;
773         dump_iterations = false;
774         flows_count = DEFAULT_RULES_COUNT;
775         iterations_number = DEFAULT_ITERATION;
776         delete_flag = false;
777         dump_socket_mem_flag = false;
778         flow_group = 0;
779
780         signal(SIGINT, signal_handler);
781         signal(SIGTERM, signal_handler);
782
783         argc -= ret;
784         argv += ret;
785         if (argc > 1)
786                 args_parse(argc, argv);
787
788         init_port();
789
790         nb_lcores = rte_lcore_count();
791         if (nb_lcores <= 1)
792                 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n");
793
794         last_alloc = (int64_t)dump_socket_mem(stdout);
795         flows_handler();
796         alloc = (int64_t)dump_socket_mem(stdout);
797
798         if (last_alloc)
799                 fprintf(stdout, ":: Memory allocation change(M): %.6lf\n",
800                 (alloc - last_alloc) / 1.0e6);
801
802         RTE_ETH_FOREACH_DEV(port) {
803                 rte_flow_flush(port, &error);
804                 rte_eth_dev_stop(port);
805                 rte_eth_dev_close(port);
806         }
807         return 0;
808 }