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