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