app/testpmd: fix metering and policing command for RFC4115
[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                 { 0, 0, 0, 0 },
719         };
720
721         RTE_ETH_FOREACH_DEV(i)
722                 ports_mask |= 1 << i;
723
724         for (i = 0; i < RTE_MAX_ETHPORTS; i++)
725                 dst_ports[i] = PORT_ID_DST;
726
727         hairpin_queues_num = 0;
728         argvopt = argv;
729
730         printf(":: Flow -> ");
731         while ((opt = getopt_long(argc, argvopt, "",
732                                 lgopts, &opt_idx)) != EOF) {
733                 switch (opt) {
734                 case 0:
735                         if (strcmp(lgopts[opt_idx].name, "help") == 0) {
736                                 usage(argv[0]);
737                                 exit(EXIT_SUCCESS);
738                         }
739
740                         if (strcmp(lgopts[opt_idx].name, "group") == 0) {
741                                 n = atoi(optarg);
742                                 if (n >= 0)
743                                         flow_group = n;
744                                 else
745                                         rte_exit(EXIT_FAILURE,
746                                                 "flow group should be >= 0\n");
747                                 printf("group %d / ", flow_group);
748                         }
749
750                         for (i = 0; i < RTE_DIM(flow_options); i++)
751                                 if (strcmp(lgopts[opt_idx].name,
752                                                 flow_options[i].str) == 0) {
753                                         flow_options[i].map[
754                                         (*flow_options[i].map_idx)++] =
755                                                 flow_options[i].mask;
756                                         printf("%s / ", flow_options[i].str);
757                                 }
758
759                         if (strcmp(lgopts[opt_idx].name,
760                                         "hairpin-rss") == 0) {
761                                 n = atoi(optarg);
762                                 if (n > 0)
763                                         hairpin_queues_num = n;
764                                 else
765                                         rte_exit(EXIT_FAILURE,
766                                                 "Hairpin queues should be > 0\n");
767
768                                 flow_actions[actions_idx++] =
769                                         HAIRPIN_RSS_ACTION;
770                                 printf("hairpin-rss / ");
771                         }
772                         if (strcmp(lgopts[opt_idx].name,
773                                         "hairpin-queue") == 0) {
774                                 n = atoi(optarg);
775                                 if (n > 0)
776                                         hairpin_queues_num = n;
777                                 else
778                                         rte_exit(EXIT_FAILURE,
779                                                 "Hairpin queues should be > 0\n");
780
781                                 flow_actions[actions_idx++] =
782                                         HAIRPIN_QUEUE_ACTION;
783                                 printf("hairpin-queue / ");
784                         }
785
786                         if (strcmp(lgopts[opt_idx].name, "raw-encap") == 0) {
787                                 printf("raw-encap ");
788                                 flow_actions[actions_idx++] =
789                                         FLOW_ITEM_MASK(
790                                                 RTE_FLOW_ACTION_TYPE_RAW_ENCAP
791                                         );
792
793                                 token = strtok(optarg, ",");
794                                 while (token != NULL) {
795                                         for (i = 0; i < RTE_DIM(flow_options); i++) {
796                                                 if (strcmp(flow_options[i].str, token) == 0) {
797                                                         printf("%s,", token);
798                                                         encap_data |= flow_options[i].mask;
799                                                         break;
800                                                 }
801                                                 /* Reached last item with no match */
802                                                 if (i == (RTE_DIM(flow_options) - 1))
803                                                         rte_exit(EXIT_FAILURE,
804                                                                 "Invalid encap item: %s\n", token);
805                                         }
806                                         token = strtok(NULL, ",");
807                                 }
808                                 printf(" / ");
809                         }
810                         if (strcmp(lgopts[opt_idx].name, "raw-decap") == 0) {
811                                 printf("raw-decap ");
812                                 flow_actions[actions_idx++] =
813                                         FLOW_ITEM_MASK(
814                                                 RTE_FLOW_ACTION_TYPE_RAW_DECAP
815                                         );
816
817                                 token = strtok(optarg, ",");
818                                 while (token != NULL) {
819                                         for (i = 0; i < RTE_DIM(flow_options); i++) {
820                                                 if (strcmp(flow_options[i].str, token) == 0) {
821                                                         printf("%s,", token);
822                                                         decap_data |= flow_options[i].mask;
823                                                         break;
824                                                 }
825                                                 /* Reached last item with no match */
826                                                 if (i == (RTE_DIM(flow_options) - 1))
827                                                         rte_exit(EXIT_FAILURE,
828                                                                 "Invalid decap item %s\n", token);
829                                         }
830                                         token = strtok(NULL, ",");
831                                 }
832                                 printf(" / ");
833                         }
834                         /* Control */
835                         if (strcmp(lgopts[opt_idx].name,
836                                         "rules-batch") == 0) {
837                                 rules_batch = atoi(optarg);
838                         }
839                         if (strcmp(lgopts[opt_idx].name,
840                                         "rules-count") == 0) {
841                                 rules_count = atoi(optarg);
842                         }
843                         if (strcmp(lgopts[opt_idx].name, "random-priority") ==
844                             0) {
845                                 end = NULL;
846                                 prio = strtol(optarg, &end, 10);
847                                 if ((optarg[0] == '\0') || (end == NULL))
848                                         rte_exit(EXIT_FAILURE,
849                                                  "Invalid value for random-priority\n");
850                                 max_priority = prio;
851                                 token = end + 1;
852                                 seed = strtoll(token, &end, 10);
853                                 if ((token[0] == '\0') || (*end != '\0'))
854                                         rte_exit(EXIT_FAILURE,
855                                                  "Invalid value for random-priority\n");
856                                 rand_seed = seed;
857                         }
858                         if (strcmp(lgopts[opt_idx].name,
859                                         "dump-iterations") == 0)
860                                 dump_iterations = true;
861                         if (strcmp(lgopts[opt_idx].name,
862                                         "unique-data") == 0)
863                                 unique_data = true;
864                         if (strcmp(lgopts[opt_idx].name,
865                                         "deletion-rate") == 0)
866                                 delete_flag = true;
867                         if (strcmp(lgopts[opt_idx].name,
868                                         "dump-socket-mem") == 0)
869                                 dump_socket_mem_flag = true;
870                         if (strcmp(lgopts[opt_idx].name,
871                                         "enable-fwd") == 0)
872                                 enable_fwd = true;
873                         if (strcmp(lgopts[opt_idx].name,
874                                         "portmask") == 0) {
875                                 /* parse hexadecimal string */
876                                 end = NULL;
877                                 pm = strtoull(optarg, &end, 16);
878                                 if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0'))
879                                         rte_exit(EXIT_FAILURE, "Invalid fwd port mask\n");
880                                 ports_mask = pm;
881                         }
882                         if (strcmp(lgopts[opt_idx].name,
883                                         "port-id") == 0) {
884                                 uint16_t port_idx = 0;
885                                 char *token;
886
887                                 token = strtok(optarg, ",");
888                                 while (token != NULL) {
889                                         dst_ports[port_idx++] = atoi(token);
890                                         token = strtok(NULL, ",");
891                                 }
892                         }
893                         if (strcmp(lgopts[opt_idx].name, "rxq") == 0) {
894                                 n = atoi(optarg);
895                                 rx_queues_count = (uint8_t) n;
896                         }
897                         if (strcmp(lgopts[opt_idx].name, "txq") == 0) {
898                                 n = atoi(optarg);
899                                 tx_queues_count = (uint8_t) n;
900                         }
901                         if (strcmp(lgopts[opt_idx].name, "rxd") == 0) {
902                                 n = atoi(optarg);
903                                 rxd_count = (uint8_t) n;
904                         }
905                         if (strcmp(lgopts[opt_idx].name, "txd") == 0) {
906                                 n = atoi(optarg);
907                                 txd_count = (uint8_t) n;
908                         }
909                         if (strcmp(lgopts[opt_idx].name, "mbuf-size") == 0) {
910                                 n = atoi(optarg);
911                                 mbuf_size = (uint32_t) n;
912                         }
913                         if (strcmp(lgopts[opt_idx].name, "mbuf-cache-size") == 0) {
914                                 n = atoi(optarg);
915                                 mbuf_cache_size = (uint32_t) n;
916                         }
917                         if (strcmp(lgopts[opt_idx].name, "total-mbuf-count") == 0) {
918                                 n = atoi(optarg);
919                                 total_mbuf_num = (uint32_t) n;
920                         }
921                         if (strcmp(lgopts[opt_idx].name, "cores") == 0) {
922                                 n = atoi(optarg);
923                                 if ((int) rte_lcore_count() <= n) {
924                                         rte_exit(EXIT_FAILURE,
925                                                 "Error: you need %d cores to run on multi-cores\n"
926                                                 "Existing cores are: %d\n", n, rte_lcore_count());
927                                 }
928                                 if (n <= RTE_MAX_LCORE && n > 0)
929                                         mc_pool.cores_count = n;
930                                 else {
931                                         rte_exit(EXIT_FAILURE,
932                                                 "Error: cores count must be > 0 and < %d\n",
933                                                 RTE_MAX_LCORE);
934                                 }
935                         }
936                         if (strcmp(lgopts[opt_idx].name, "policy-mtr") == 0)
937                                 read_meter_policy(argv[0], optarg);
938                         if (strcmp(lgopts[opt_idx].name,
939                                                 "meter-profile") == 0) {
940                                 i = 0;
941                                 token = strsep(&optarg, ",\0");
942                                 while (token != NULL && i < sizeof(
943                                                 meter_profile_values) /
944                                                 sizeof(uint64_t)) {
945                                         meter_profile_values[i++] = atol(token);
946                                         token = strsep(&optarg, ",\0");
947                                 }
948                         }
949                         if (strcmp(lgopts[opt_idx].name, "packet-mode") == 0)
950                                 packet_mode = true;
951                         break;
952                 default:
953                         usage(argv[0]);
954                         rte_exit(EXIT_FAILURE, "Invalid option: %s\n",
955                                         argv[optind - 1]);
956                         break;
957                 }
958         }
959         if (rules_count % rules_batch != 0) {
960                 rte_exit(EXIT_FAILURE,
961                          "rules_count %% rules_batch should be 0\n");
962         }
963         if (rules_count / rules_batch > MAX_BATCHES_COUNT) {
964                 rte_exit(EXIT_FAILURE,
965                          "rules_count / rules_batch should be <= %d\n",
966                          MAX_BATCHES_COUNT);
967         }
968
969         printf("end_flow\n");
970 }
971
972 /* Dump the socket memory statistics on console */
973 static size_t
974 dump_socket_mem(FILE *f)
975 {
976         struct rte_malloc_socket_stats socket_stats;
977         unsigned int i = 0;
978         size_t total = 0;
979         size_t alloc = 0;
980         size_t free = 0;
981         unsigned int n_alloc = 0;
982         unsigned int n_free = 0;
983         bool active_nodes = false;
984
985
986         for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
987                 if (rte_malloc_get_socket_stats(i, &socket_stats) ||
988                     !socket_stats.heap_totalsz_bytes)
989                         continue;
990                 active_nodes = true;
991                 total += socket_stats.heap_totalsz_bytes;
992                 alloc += socket_stats.heap_allocsz_bytes;
993                 free += socket_stats.heap_freesz_bytes;
994                 n_alloc += socket_stats.alloc_count;
995                 n_free += socket_stats.free_count;
996                 if (dump_socket_mem_flag) {
997                         fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
998                         fprintf(f,
999                                 "\nSocket %u:\nsize(M) total: %.6lf\nalloc:"
1000                                 " %.6lf(%.3lf%%)\nfree: %.6lf"
1001                                 "\nmax: %.6lf"
1002                                 "\ncount alloc: %u\nfree: %u\n",
1003                                 i,
1004                                 socket_stats.heap_totalsz_bytes / 1.0e6,
1005                                 socket_stats.heap_allocsz_bytes / 1.0e6,
1006                                 (double)socket_stats.heap_allocsz_bytes * 100 /
1007                                 (double)socket_stats.heap_totalsz_bytes,
1008                                 socket_stats.heap_freesz_bytes / 1.0e6,
1009                                 socket_stats.greatest_free_size / 1.0e6,
1010                                 socket_stats.alloc_count,
1011                                 socket_stats.free_count);
1012                                 fprintf(f, "::::::::::::::::::::::::::::::::::::::::");
1013                 }
1014         }
1015         if (dump_socket_mem_flag && active_nodes) {
1016                 fprintf(f,
1017                         "\nTotal: size(M)\ntotal: %.6lf"
1018                         "\nalloc: %.6lf(%.3lf%%)\nfree: %.6lf"
1019                         "\ncount alloc: %u\nfree: %u\n",
1020                         total / 1.0e6, alloc / 1.0e6,
1021                         (double)alloc * 100 / (double)total, free / 1.0e6,
1022                         n_alloc, n_free);
1023                 fprintf(f, "::::::::::::::::::::::::::::::::::::::::\n");
1024         }
1025         return alloc;
1026 }
1027
1028 static void
1029 print_flow_error(struct rte_flow_error error)
1030 {
1031         printf("Flow can't be created %d message: %s\n",
1032                 error.type,
1033                 error.message ? error.message : "(no stated reason)");
1034 }
1035
1036 static inline void
1037 print_rules_batches(double *cpu_time_per_batch)
1038 {
1039         uint8_t idx;
1040         double delta;
1041         double rate;
1042
1043         for (idx = 0; idx < MAX_BATCHES_COUNT; idx++) {
1044                 if (!cpu_time_per_batch[idx])
1045                         break;
1046                 delta = (double)(rules_batch / cpu_time_per_batch[idx]);
1047                 rate = delta / 1000; /* Save rate in K unit. */
1048                 printf(":: Rules batch #%d: %d rules "
1049                         "in %f sec[ Rate = %f K Rule/Sec ]\n",
1050                         idx, rules_batch,
1051                         cpu_time_per_batch[idx], rate);
1052         }
1053 }
1054
1055 static inline int
1056 has_meter(void)
1057 {
1058         int i;
1059
1060         for (i = 0; i < MAX_ACTIONS_NUM; i++) {
1061                 if (flow_actions[i] == 0)
1062                         break;
1063                 if (flow_actions[i]
1064                                 & FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_METER))
1065                         return 1;
1066         }
1067         return 0;
1068 }
1069
1070 static void
1071 create_meter_policy(void)
1072 {
1073         struct rte_mtr_error error;
1074         int ret, port_id;
1075         struct rte_mtr_meter_policy_params policy;
1076         uint16_t nr_ports;
1077         struct rte_flow_action actions[RTE_COLORS][MAX_ACTIONS_NUM];
1078         int i;
1079
1080         memset(actions, 0, sizeof(actions));
1081         memset(&policy, 0, sizeof(policy));
1082         nr_ports = rte_eth_dev_count_avail();
1083         for (port_id = 0; port_id < nr_ports; port_id++) {
1084                 for (i = 0; i < RTE_COLORS; i++)
1085                         fill_actions(actions[i], all_actions[i], 0, 0, 0,
1086                                      0, 0, 0, unique_data, rx_queues_count,
1087                                      dst_ports[port_id]);
1088                 policy.actions[RTE_COLOR_GREEN] = actions[RTE_COLOR_GREEN];
1089                 policy.actions[RTE_COLOR_YELLOW] = actions[RTE_COLOR_YELLOW];
1090                 policy.actions[RTE_COLOR_RED] = actions[RTE_COLOR_RED];
1091                 policy_id[port_id] = port_id + 10;
1092                 ret = rte_mtr_meter_policy_add(port_id, policy_id[port_id],
1093                                                &policy, &error);
1094                 if (ret) {
1095                         fprintf(stderr, "port %d: failed to create meter policy\n",
1096                                 port_id);
1097                         policy_id[port_id] = UINT32_MAX;
1098                 }
1099                 memset(actions, 0, sizeof(actions));
1100         }
1101 }
1102
1103 static void
1104 destroy_meter_policy(void)
1105 {
1106         struct rte_mtr_error error;
1107         uint16_t nr_ports;
1108         int port_id;
1109
1110         nr_ports = rte_eth_dev_count_avail();
1111         for (port_id = 0; port_id < nr_ports; port_id++) {
1112                 /* If port outside portmask */
1113                 if (!((ports_mask >> port_id) & 0x1))
1114                         continue;
1115
1116                 if (rte_mtr_meter_policy_delete
1117                         (port_id, policy_id[port_id], &error)) {
1118                         fprintf(stderr, "port %u:  failed to  delete meter policy\n",
1119                                 port_id);
1120                         rte_exit(EXIT_FAILURE, "Error: Failed to delete meter policy.\n");
1121                 }
1122         }
1123 }
1124
1125 static void
1126 create_meter_rule(int port_id, uint32_t counter)
1127 {
1128         int ret;
1129         struct rte_mtr_params params;
1130         struct rte_mtr_error error;
1131
1132         memset(&params, 0, sizeof(struct rte_mtr_params));
1133         params.meter_enable = 1;
1134         params.stats_mask = 0xffff;
1135         params.use_prev_mtr_color = 0;
1136         params.dscp_table = NULL;
1137
1138         /*create meter*/
1139         params.meter_profile_id = DEFAULT_METER_PROF_ID;
1140
1141         if (!policy_mtr) {
1142                 ret = rte_mtr_create(port_id, counter, &params, 1, &error);
1143         } else {
1144                 params.meter_policy_id = policy_id[port_id];
1145                 ret = rte_mtr_create(port_id, counter, &params, 0, &error);
1146         }
1147
1148         if (ret != 0) {
1149                 printf("Port %u create meter idx(%d) error(%d) message: %s\n",
1150                         port_id, counter, error.type,
1151                         error.message ? error.message : "(no stated reason)");
1152                 rte_exit(EXIT_FAILURE, "Error in creating meter\n");
1153         }
1154 }
1155
1156 static void
1157 destroy_meter_rule(int port_id, uint32_t counter)
1158 {
1159         struct rte_mtr_error error;
1160
1161         if (policy_mtr && policy_id[port_id] != UINT32_MAX) {
1162                 if (rte_mtr_meter_policy_delete(port_id, policy_id[port_id],
1163                                         &error))
1164                         fprintf(stderr, "Error: Failed to delete meter policy\n");
1165                 policy_id[port_id] = UINT32_MAX;
1166         }
1167         if (rte_mtr_destroy(port_id, counter, &error)) {
1168                 fprintf(stderr, "Port %d: Failed to delete meter.\n",
1169                                 port_id);
1170                 rte_exit(EXIT_FAILURE, "Error in deleting meter rule");
1171         }
1172 }
1173
1174 static void
1175 meters_handler(int port_id, uint8_t core_id, uint8_t ops)
1176 {
1177         uint64_t start_batch;
1178         double cpu_time_used, insertion_rate;
1179         int rules_count_per_core, rules_batch_idx;
1180         uint32_t counter, start_counter = 0, end_counter;
1181         double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 };
1182
1183         rules_count_per_core = rules_count / mc_pool.cores_count;
1184
1185         if (core_id)
1186                 start_counter = core_id * rules_count_per_core;
1187         end_counter = (core_id + 1) * rules_count_per_core;
1188
1189         cpu_time_used = 0;
1190         start_batch = rte_get_timer_cycles();
1191         for (counter = start_counter; counter < end_counter; counter++) {
1192                 if (ops == METER_CREATE)
1193                         create_meter_rule(port_id, counter);
1194                 else
1195                         destroy_meter_rule(port_id, counter);
1196                 /*
1197                  * Save the insertion rate for rules batch.
1198                  * Check if the insertion reached the rules
1199                  * patch counter, then save the insertion rate
1200                  * for this batch.
1201                  */
1202                 if (!((counter + 1) % rules_batch)) {
1203                         rules_batch_idx = ((counter + 1) / rules_batch) - 1;
1204                         cpu_time_per_batch[rules_batch_idx] =
1205                                 ((double)(rte_get_timer_cycles() - start_batch))
1206                                 / rte_get_timer_hz();
1207                         cpu_time_used += cpu_time_per_batch[rules_batch_idx];
1208                         start_batch = rte_get_timer_cycles();
1209                 }
1210         }
1211
1212         /* Print insertion rates for all batches */
1213         if (dump_iterations)
1214                 print_rules_batches(cpu_time_per_batch);
1215
1216         insertion_rate =
1217                 ((double) (rules_count_per_core / cpu_time_used) / 1000);
1218
1219         /* Insertion rate for all rules in one core */
1220         printf(":: Port %d :: Core %d Meter %s :: start @[%d] - end @[%d],"
1221                 " use:%.02fs, rate:%.02fk Rule/Sec\n",
1222                 port_id, core_id, ops == METER_CREATE ? "create" : "delete",
1223                 start_counter, end_counter - 1,
1224                 cpu_time_used, insertion_rate);
1225
1226         if (ops == METER_CREATE)
1227                 mc_pool.meters_record.insertion[port_id][core_id]
1228                         = cpu_time_used;
1229         else
1230                 mc_pool.meters_record.deletion[port_id][core_id]
1231                         = cpu_time_used;
1232 }
1233
1234 static void
1235 destroy_meter_profile(void)
1236 {
1237         struct rte_mtr_error error;
1238         uint16_t nr_ports;
1239         int port_id;
1240
1241         nr_ports = rte_eth_dev_count_avail();
1242         for (port_id = 0; port_id < nr_ports; port_id++) {
1243                 /* If port outside portmask */
1244                 if (!((ports_mask >> port_id) & 0x1))
1245                         continue;
1246
1247                 if (rte_mtr_meter_profile_delete
1248                         (port_id, DEFAULT_METER_PROF_ID, &error)) {
1249                         printf("Port %u del profile error(%d) message: %s\n",
1250                                 port_id, error.type,
1251                                 error.message ? error.message : "(no stated reason)");
1252                         rte_exit(EXIT_FAILURE, "Error: Destroy meter profile Failed!\n");
1253                 }
1254         }
1255 }
1256
1257 static void
1258 create_meter_profile(void)
1259 {
1260         uint16_t nr_ports;
1261         int ret, port_id;
1262         struct rte_mtr_meter_profile mp;
1263         struct rte_mtr_error error;
1264
1265         /*
1266          *currently , only create one meter file for one port
1267          *1 meter profile -> N meter rules -> N rte flows
1268          */
1269         memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
1270         nr_ports = rte_eth_dev_count_avail();
1271         for (port_id = 0; port_id < nr_ports; port_id++) {
1272                 /* If port outside portmask */
1273                 if (!((ports_mask >> port_id) & 0x1))
1274                         continue;
1275                 mp.alg = RTE_MTR_SRTCM_RFC2697;
1276                 mp.srtcm_rfc2697.cir = meter_profile_values[0] ?
1277                         meter_profile_values[0] : METER_CIR;
1278                 mp.srtcm_rfc2697.cbs = meter_profile_values[1] ?
1279                         meter_profile_values[1] : METER_CIR / 8;
1280                 mp.srtcm_rfc2697.ebs = meter_profile_values[2];
1281                 mp.packet_mode = packet_mode;
1282                 ret = rte_mtr_meter_profile_add
1283                         (port_id, DEFAULT_METER_PROF_ID, &mp, &error);
1284                 if (ret != 0) {
1285                         printf("Port %u create Profile error(%d) message: %s\n",
1286                                 port_id, error.type,
1287                                 error.message ? error.message : "(no stated reason)");
1288                         rte_exit(EXIT_FAILURE, "Error: Creation meter profile Failed!\n");
1289                 }
1290         }
1291 }
1292
1293 static inline void
1294 destroy_flows(int port_id, uint8_t core_id, struct rte_flow **flows_list)
1295 {
1296         struct rte_flow_error error;
1297         clock_t start_batch, end_batch;
1298         double cpu_time_used = 0;
1299         double deletion_rate;
1300         double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 };
1301         double delta;
1302         uint32_t i;
1303         int rules_batch_idx;
1304         int rules_count_per_core;
1305
1306         rules_count_per_core = rules_count / mc_pool.cores_count;
1307         /* If group > 0 , should add 1 flow which created in group 0 */
1308         if (flow_group > 0 && core_id == 0)
1309                 rules_count_per_core++;
1310
1311         start_batch = rte_get_timer_cycles();
1312         for (i = 0; i < (uint32_t) rules_count_per_core; i++) {
1313                 if (flows_list[i] == 0)
1314                         break;
1315
1316                 memset(&error, 0x33, sizeof(error));
1317                 if (rte_flow_destroy(port_id, flows_list[i], &error)) {
1318                         print_flow_error(error);
1319                         rte_exit(EXIT_FAILURE, "Error in deleting flow\n");
1320                 }
1321
1322                 /*
1323                  * Save the deletion rate for rules batch.
1324                  * Check if the deletion reached the rules
1325                  * patch counter, then save the deletion rate
1326                  * for this batch.
1327                  */
1328                 if (!((i + 1) % rules_batch)) {
1329                         end_batch = rte_get_timer_cycles();
1330                         delta = (double) (end_batch - start_batch);
1331                         rules_batch_idx = ((i + 1) / rules_batch) - 1;
1332                         cpu_time_per_batch[rules_batch_idx] = delta / rte_get_timer_hz();
1333                         cpu_time_used += cpu_time_per_batch[rules_batch_idx];
1334                         start_batch = rte_get_timer_cycles();
1335                 }
1336         }
1337
1338         /* Print deletion rates for all batches */
1339         if (dump_iterations)
1340                 print_rules_batches(cpu_time_per_batch);
1341
1342         /* Deletion rate for all rules */
1343         deletion_rate = ((double) (rules_count_per_core / cpu_time_used) / 1000);
1344         printf(":: Port %d :: Core %d :: Rules deletion rate -> %f K Rule/Sec\n",
1345                 port_id, core_id, deletion_rate);
1346         printf(":: Port %d :: Core %d :: The time for deleting %d rules is %f seconds\n",
1347                 port_id, core_id, rules_count_per_core, cpu_time_used);
1348
1349         mc_pool.flows_record.deletion[port_id][core_id] = cpu_time_used;
1350 }
1351
1352 static struct rte_flow **
1353 insert_flows(int port_id, uint8_t core_id, uint16_t dst_port_id)
1354 {
1355         struct rte_flow **flows_list;
1356         struct rte_flow_error error;
1357         clock_t start_batch, end_batch;
1358         double first_flow_latency;
1359         double cpu_time_used;
1360         double insertion_rate;
1361         double cpu_time_per_batch[MAX_BATCHES_COUNT] = { 0 };
1362         double delta;
1363         uint32_t flow_index;
1364         uint32_t counter, start_counter = 0, end_counter;
1365         uint64_t global_items[MAX_ITEMS_NUM] = { 0 };
1366         uint64_t global_actions[MAX_ACTIONS_NUM] = { 0 };
1367         int rules_batch_idx;
1368         int rules_count_per_core;
1369
1370         rules_count_per_core = rules_count / mc_pool.cores_count;
1371
1372         /* Set boundaries of rules for each core. */
1373         if (core_id)
1374                 start_counter = core_id * rules_count_per_core;
1375         end_counter = (core_id + 1) * rules_count_per_core;
1376
1377         global_items[0] = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH);
1378         global_actions[0] = FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP);
1379
1380         flows_list = rte_zmalloc("flows_list",
1381                 (sizeof(struct rte_flow *) * rules_count_per_core) + 1, 0);
1382         if (flows_list == NULL)
1383                 rte_exit(EXIT_FAILURE, "No Memory available!\n");
1384
1385         cpu_time_used = 0;
1386         flow_index = 0;
1387         if (flow_group > 0 && core_id == 0) {
1388                 /*
1389                  * Create global rule to jump into flow_group,
1390                  * this way the app will avoid the default rules.
1391                  *
1392                  * This rule will be created only once.
1393                  *
1394                  * Global rule:
1395                  * group 0 eth / end actions jump group <flow_group>
1396                  */
1397                 flow = generate_flow(port_id, 0, flow_attrs,
1398                         global_items, global_actions,
1399                         flow_group, 0, 0, 0, 0, dst_port_id, core_id,
1400                         rx_queues_count, unique_data, max_priority, &error);
1401
1402                 if (flow == NULL) {
1403                         print_flow_error(error);
1404                         rte_exit(EXIT_FAILURE, "Error in creating flow\n");
1405                 }
1406                 flows_list[flow_index++] = flow;
1407         }
1408
1409         start_batch = rte_get_timer_cycles();
1410         for (counter = start_counter; counter < end_counter; counter++) {
1411                 flow = generate_flow(port_id, flow_group,
1412                         flow_attrs, flow_items, flow_actions,
1413                         JUMP_ACTION_TABLE, counter,
1414                         hairpin_queues_num, encap_data,
1415                         decap_data, dst_port_id,
1416                         core_id, rx_queues_count,
1417                         unique_data, max_priority, &error);
1418
1419                 if (!counter) {
1420                         first_flow_latency = (double) (rte_get_timer_cycles() - start_batch);
1421                         first_flow_latency /= rte_get_timer_hz();
1422                         /* In millisecond */
1423                         first_flow_latency *= 1000;
1424                         printf(":: First Flow Latency :: Port %d :: First flow "
1425                                 "installed in %f milliseconds\n",
1426                                 port_id, first_flow_latency);
1427                 }
1428
1429                 if (force_quit)
1430                         counter = end_counter;
1431
1432                 if (!flow) {
1433                         print_flow_error(error);
1434                         rte_exit(EXIT_FAILURE, "Error in creating flow\n");
1435                 }
1436
1437                 flows_list[flow_index++] = flow;
1438
1439                 /*
1440                  * Save the insertion rate for rules batch.
1441                  * Check if the insertion reached the rules
1442                  * patch counter, then save the insertion rate
1443                  * for this batch.
1444                  */
1445                 if (!((counter + 1) % rules_batch)) {
1446                         end_batch = rte_get_timer_cycles();
1447                         delta = (double) (end_batch - start_batch);
1448                         rules_batch_idx = ((counter + 1) / rules_batch) - 1;
1449                         cpu_time_per_batch[rules_batch_idx] = delta / rte_get_timer_hz();
1450                         cpu_time_used += cpu_time_per_batch[rules_batch_idx];
1451                         start_batch = rte_get_timer_cycles();
1452                 }
1453         }
1454
1455         /* Print insertion rates for all batches */
1456         if (dump_iterations)
1457                 print_rules_batches(cpu_time_per_batch);
1458
1459         printf(":: Port %d :: Core %d boundaries :: start @[%d] - end @[%d]\n",
1460                 port_id, core_id, start_counter, end_counter - 1);
1461
1462         /* Insertion rate for all rules in one core */
1463         insertion_rate = ((double) (rules_count_per_core / cpu_time_used) / 1000);
1464         printf(":: Port %d :: Core %d :: Rules insertion rate -> %f K Rule/Sec\n",
1465                 port_id, core_id, insertion_rate);
1466         printf(":: Port %d :: Core %d :: The time for creating %d in rules %f seconds\n",
1467                 port_id, core_id, rules_count_per_core, cpu_time_used);
1468
1469         mc_pool.flows_record.insertion[port_id][core_id] = cpu_time_used;
1470         return flows_list;
1471 }
1472
1473 static void
1474 flows_handler(uint8_t core_id)
1475 {
1476         struct rte_flow **flows_list;
1477         uint16_t port_idx = 0;
1478         uint16_t nr_ports;
1479         int port_id;
1480
1481         nr_ports = rte_eth_dev_count_avail();
1482
1483         if (rules_batch > rules_count)
1484                 rules_batch = rules_count;
1485
1486         printf(":: Rules Count per port: %d\n\n", rules_count);
1487
1488         for (port_id = 0; port_id < nr_ports; port_id++) {
1489                 /* If port outside portmask */
1490                 if (!((ports_mask >> port_id) & 0x1))
1491                         continue;
1492
1493                 /* Insertion part. */
1494                 mc_pool.last_alloc[core_id] = (int64_t)dump_socket_mem(stdout);
1495                 if (has_meter())
1496                         meters_handler(port_id, core_id, METER_CREATE);
1497                 flows_list = insert_flows(port_id, core_id,
1498                                                 dst_ports[port_idx++]);
1499                 if (flows_list == NULL)
1500                         rte_exit(EXIT_FAILURE, "Error: Insertion Failed!\n");
1501                 mc_pool.current_alloc[core_id] = (int64_t)dump_socket_mem(stdout);
1502
1503                 /* Deletion part. */
1504                 if (delete_flag) {
1505                         destroy_flows(port_id, core_id, flows_list);
1506                         if (has_meter())
1507                                 meters_handler(port_id, core_id, METER_DELETE);
1508                 }
1509         }
1510 }
1511
1512 static void
1513 dump_used_cpu_time(const char *item,
1514                 uint16_t port, struct used_cpu_time *used_time)
1515 {
1516         uint32_t i;
1517         /* Latency: total count of rte rules divided
1518          * over max time used by thread between all
1519          * threads time.
1520          *
1521          * Throughput: total count of rte rules divided
1522          * over the average of the time consumed by all
1523          * threads time.
1524          */
1525         double insertion_latency_time;
1526         double insertion_throughput_time;
1527         double deletion_latency_time;
1528         double deletion_throughput_time;
1529         double insertion_latency, insertion_throughput;
1530         double deletion_latency, deletion_throughput;
1531
1532         /* Save first insertion/deletion rates from first thread.
1533          * Start comparing with all threads, if any thread used
1534          * time more than current saved, replace it.
1535          *
1536          * Thus in the end we will have the max time used for
1537          * insertion/deletion by one thread.
1538          *
1539          * As for memory consumption, save the min of all threads
1540          * of last alloc, and save the max for all threads for
1541          * current alloc.
1542          */
1543
1544         insertion_latency_time = used_time->insertion[port][0];
1545         deletion_latency_time = used_time->deletion[port][0];
1546         insertion_throughput_time = used_time->insertion[port][0];
1547         deletion_throughput_time = used_time->deletion[port][0];
1548
1549         i = mc_pool.cores_count;
1550         while (i-- > 1) {
1551                 insertion_throughput_time += used_time->insertion[port][i];
1552                 deletion_throughput_time += used_time->deletion[port][i];
1553                 if (insertion_latency_time < used_time->insertion[port][i])
1554                         insertion_latency_time = used_time->insertion[port][i];
1555                 if (deletion_latency_time < used_time->deletion[port][i])
1556                         deletion_latency_time = used_time->deletion[port][i];
1557         }
1558
1559         insertion_latency = ((double) (mc_pool.rules_count
1560                                 / insertion_latency_time) / 1000);
1561         deletion_latency = ((double) (mc_pool.rules_count
1562                                 / deletion_latency_time) / 1000);
1563
1564         insertion_throughput_time /= mc_pool.cores_count;
1565         deletion_throughput_time /= mc_pool.cores_count;
1566         insertion_throughput = ((double) (mc_pool.rules_count
1567                                 / insertion_throughput_time) / 1000);
1568         deletion_throughput = ((double) (mc_pool.rules_count
1569                                 / deletion_throughput_time) / 1000);
1570
1571         /* Latency stats */
1572         printf("\n%s\n:: [Latency | Insertion] All Cores :: Port %d :: ",
1573                 item, port);
1574         printf("Total flows insertion rate -> %f K Rules/Sec\n",
1575                 insertion_latency);
1576         printf(":: [Latency | Insertion] All Cores :: Port %d :: ", port);
1577         printf("The time for creating %d rules is %f seconds\n",
1578                 mc_pool.rules_count, insertion_latency_time);
1579
1580         /* Throughput stats */
1581         printf(":: [Throughput | Insertion] All Cores :: Port %d :: ", port);
1582         printf("Total flows insertion rate -> %f K Rules/Sec\n",
1583                 insertion_throughput);
1584         printf(":: [Throughput | Insertion] All Cores :: Port %d :: ", port);
1585         printf("The average time for creating %d rules is %f seconds\n",
1586                 mc_pool.rules_count, insertion_throughput_time);
1587
1588         if (delete_flag) {
1589         /* Latency stats */
1590                 printf(":: [Latency | Deletion] All Cores :: Port %d :: Total "
1591                         "deletion rate -> %f K Rules/Sec\n",
1592                         port, deletion_latency);
1593                 printf(":: [Latency | Deletion] All Cores :: Port %d :: ",
1594                         port);
1595                 printf("The time for deleting %d rules is %f seconds\n",
1596                         mc_pool.rules_count, deletion_latency_time);
1597
1598                 /* Throughput stats */
1599                 printf(":: [Throughput | Deletion] All Cores :: Port %d :: Total "
1600                         "deletion rate -> %f K Rules/Sec\n",
1601                         port, deletion_throughput);
1602                 printf(":: [Throughput | Deletion] All Cores :: Port %d :: ",
1603                         port);
1604                 printf("The average time for deleting %d rules is %f seconds\n",
1605                         mc_pool.rules_count, deletion_throughput_time);
1606         }
1607 }
1608
1609 static void
1610 dump_used_mem(uint16_t port)
1611 {
1612         uint32_t i;
1613         int64_t last_alloc, current_alloc;
1614         int flow_size_in_bytes;
1615
1616         last_alloc = mc_pool.last_alloc[0];
1617         current_alloc = mc_pool.current_alloc[0];
1618
1619         i = mc_pool.cores_count;
1620         while (i-- > 1) {
1621                 if (last_alloc > mc_pool.last_alloc[i])
1622                         last_alloc = mc_pool.last_alloc[i];
1623                 if (current_alloc < mc_pool.current_alloc[i])
1624                         current_alloc = mc_pool.current_alloc[i];
1625         }
1626
1627         flow_size_in_bytes = (current_alloc - last_alloc) / mc_pool.rules_count;
1628         printf("\n:: Port %d :: rte_flow size in DPDK layer: %d Bytes\n",
1629                 port, flow_size_in_bytes);
1630 }
1631
1632 static int
1633 run_rte_flow_handler_cores(void *data __rte_unused)
1634 {
1635         uint16_t port;
1636         int lcore_counter = 0;
1637         int lcore_id = rte_lcore_id();
1638         int i;
1639
1640         RTE_LCORE_FOREACH(i) {
1641                 /*  If core not needed return. */
1642                 if (lcore_id == i) {
1643                         printf(":: lcore %d mapped with index %d\n", lcore_id, lcore_counter);
1644                         if (lcore_counter >= (int) mc_pool.cores_count)
1645                                 return 0;
1646                         break;
1647                 }
1648                 lcore_counter++;
1649         }
1650         lcore_id = lcore_counter;
1651
1652         if (lcore_id >= (int) mc_pool.cores_count)
1653                 return 0;
1654
1655         mc_pool.rules_count = rules_count;
1656
1657         flows_handler(lcore_id);
1658
1659         /* Only main core to print total results. */
1660         if (lcore_id != 0)
1661                 return 0;
1662
1663         /* Make sure all cores finished insertion/deletion process. */
1664         rte_eal_mp_wait_lcore();
1665
1666         RTE_ETH_FOREACH_DEV(port) {
1667                 /* If port outside portmask */
1668                 if (!((ports_mask >> port) & 0x1))
1669                         continue;
1670                 if (has_meter())
1671                         dump_used_cpu_time("Meters:",
1672                                 port, &mc_pool.meters_record);
1673                 dump_used_cpu_time("Flows:",
1674                         port, &mc_pool.flows_record);
1675                 dump_used_mem(port);
1676         }
1677
1678         return 0;
1679 }
1680
1681 static void
1682 signal_handler(int signum)
1683 {
1684         if (signum == SIGINT || signum == SIGTERM) {
1685                 printf("\n\nSignal %d received, preparing to exit...\n",
1686                                         signum);
1687                 printf("Error: Stats are wrong due to sudden signal!\n\n");
1688                 force_quit = true;
1689         }
1690 }
1691
1692 static inline uint16_t
1693 do_rx(struct lcore_info *li, uint16_t rx_port, uint16_t rx_queue)
1694 {
1695         uint16_t cnt = 0;
1696         cnt = rte_eth_rx_burst(rx_port, rx_queue, li->pkts, MAX_PKT_BURST);
1697         li->rx_pkts += cnt;
1698         return cnt;
1699 }
1700
1701 static inline void
1702 do_tx(struct lcore_info *li, uint16_t cnt, uint16_t tx_port,
1703                         uint16_t tx_queue)
1704 {
1705         uint16_t nr_tx = 0;
1706         uint16_t i;
1707
1708         nr_tx = rte_eth_tx_burst(tx_port, tx_queue, li->pkts, cnt);
1709         li->tx_pkts  += nr_tx;
1710         li->tx_drops += cnt - nr_tx;
1711
1712         for (i = nr_tx; i < cnt; i++)
1713                 rte_pktmbuf_free(li->pkts[i]);
1714 }
1715
1716 /*
1717  * Method to convert numbers into pretty numbers that easy
1718  * to read. The design here is to add comma after each three
1719  * digits and set all of this inside buffer.
1720  *
1721  * For example if n = 1799321, the output will be
1722  * 1,799,321 after this method which is easier to read.
1723  */
1724 static char *
1725 pretty_number(uint64_t n, char *buf)
1726 {
1727         char p[6][4];
1728         int i = 0;
1729         int off = 0;
1730
1731         while (n > 1000) {
1732                 sprintf(p[i], "%03d", (int)(n % 1000));
1733                 n /= 1000;
1734                 i += 1;
1735         }
1736
1737         sprintf(p[i++], "%d", (int)n);
1738
1739         while (i--)
1740                 off += sprintf(buf + off, "%s,", p[i]);
1741         buf[strlen(buf) - 1] = '\0';
1742
1743         return buf;
1744 }
1745
1746 static void
1747 packet_per_second_stats(void)
1748 {
1749         struct lcore_info *old;
1750         struct lcore_info *li, *oli;
1751         int nr_lines = 0;
1752         int i;
1753
1754         old = rte_zmalloc("old",
1755                 sizeof(struct lcore_info) * RTE_MAX_LCORE, 0);
1756         if (old == NULL)
1757                 rte_exit(EXIT_FAILURE, "No Memory available!\n");
1758
1759         memcpy(old, lcore_infos,
1760                 sizeof(struct lcore_info) * RTE_MAX_LCORE);
1761
1762         while (!force_quit) {
1763                 uint64_t total_tx_pkts = 0;
1764                 uint64_t total_rx_pkts = 0;
1765                 uint64_t total_tx_drops = 0;
1766                 uint64_t tx_delta, rx_delta, drops_delta;
1767                 char buf[3][32];
1768                 int nr_valid_core = 0;
1769
1770                 sleep(1);
1771
1772                 if (nr_lines) {
1773                         char go_up_nr_lines[16];
1774
1775                         sprintf(go_up_nr_lines, "%c[%dA\r", 27, nr_lines);
1776                         printf("%s\r", go_up_nr_lines);
1777                 }
1778
1779                 printf("\n%6s %16s %16s %16s\n", "core", "tx", "tx drops", "rx");
1780                 printf("%6s %16s %16s %16s\n", "------", "----------------",
1781                         "----------------", "----------------");
1782                 nr_lines = 3;
1783                 for (i = 0; i < RTE_MAX_LCORE; i++) {
1784                         li  = &lcore_infos[i];
1785                         oli = &old[i];
1786                         if (li->mode != LCORE_MODE_PKT)
1787                                 continue;
1788
1789                         tx_delta    = li->tx_pkts  - oli->tx_pkts;
1790                         rx_delta    = li->rx_pkts  - oli->rx_pkts;
1791                         drops_delta = li->tx_drops - oli->tx_drops;
1792                         printf("%6d %16s %16s %16s\n", i,
1793                                 pretty_number(tx_delta,    buf[0]),
1794                                 pretty_number(drops_delta, buf[1]),
1795                                 pretty_number(rx_delta,    buf[2]));
1796
1797                         total_tx_pkts  += tx_delta;
1798                         total_rx_pkts  += rx_delta;
1799                         total_tx_drops += drops_delta;
1800
1801                         nr_valid_core++;
1802                         nr_lines += 1;
1803                 }
1804
1805                 if (nr_valid_core > 1) {
1806                         printf("%6s %16s %16s %16s\n", "total",
1807                                 pretty_number(total_tx_pkts,  buf[0]),
1808                                 pretty_number(total_tx_drops, buf[1]),
1809                                 pretty_number(total_rx_pkts,  buf[2]));
1810                         nr_lines += 1;
1811                 }
1812
1813                 memcpy(old, lcore_infos,
1814                         sizeof(struct lcore_info) * RTE_MAX_LCORE);
1815         }
1816 }
1817
1818 static int
1819 start_forwarding(void *data __rte_unused)
1820 {
1821         int lcore = rte_lcore_id();
1822         int stream_id;
1823         uint16_t cnt;
1824         struct lcore_info *li = &lcore_infos[lcore];
1825
1826         if (!li->mode)
1827                 return 0;
1828
1829         if (li->mode == LCORE_MODE_STATS) {
1830                 printf(":: started stats on lcore %u\n", lcore);
1831                 packet_per_second_stats();
1832                 return 0;
1833         }
1834
1835         while (!force_quit)
1836                 for (stream_id = 0; stream_id < MAX_STREAMS; stream_id++) {
1837                         if (li->streams[stream_id].rx_port == -1)
1838                                 continue;
1839
1840                         cnt = do_rx(li,
1841                                         li->streams[stream_id].rx_port,
1842                                         li->streams[stream_id].rx_queue);
1843                         if (cnt)
1844                                 do_tx(li, cnt,
1845                                         li->streams[stream_id].tx_port,
1846                                         li->streams[stream_id].tx_queue);
1847                 }
1848         return 0;
1849 }
1850
1851 static void
1852 init_lcore_info(void)
1853 {
1854         int i, j;
1855         unsigned int lcore;
1856         uint16_t nr_port;
1857         uint16_t queue;
1858         int port;
1859         int stream_id = 0;
1860         int streams_per_core;
1861         int unassigned_streams;
1862         int nb_fwd_streams;
1863         nr_port = rte_eth_dev_count_avail();
1864
1865         /* First logical core is reserved for stats printing */
1866         lcore = rte_get_next_lcore(-1, 0, 0);
1867         lcore_infos[lcore].mode = LCORE_MODE_STATS;
1868
1869         /*
1870          * Initialize all cores
1871          * All cores at first must have -1 value in all streams
1872          * This means that this stream is not used, or not set
1873          * yet.
1874          */
1875         for (i = 0; i < RTE_MAX_LCORE; i++)
1876                 for (j = 0; j < MAX_STREAMS; j++) {
1877                         lcore_infos[i].streams[j].tx_port = -1;
1878                         lcore_infos[i].streams[j].rx_port = -1;
1879                         lcore_infos[i].streams[j].tx_queue = -1;
1880                         lcore_infos[i].streams[j].rx_queue = -1;
1881                         lcore_infos[i].streams_nb = 0;
1882                 }
1883
1884         /*
1885          * Calculate the total streams count.
1886          * Also distribute those streams count between the available
1887          * logical cores except first core, since it's reserved for
1888          * stats prints.
1889          */
1890         nb_fwd_streams = nr_port * rx_queues_count;
1891         if ((int)(nb_lcores - 1) >= nb_fwd_streams)
1892                 for (i = 0; i < (int)(nb_lcores - 1); i++) {
1893                         lcore = rte_get_next_lcore(lcore, 0, 0);
1894                         lcore_infos[lcore].streams_nb = 1;
1895                 }
1896         else {
1897                 streams_per_core = nb_fwd_streams / (nb_lcores - 1);
1898                 unassigned_streams = nb_fwd_streams % (nb_lcores - 1);
1899                 for (i = 0; i < (int)(nb_lcores - 1); i++) {
1900                         lcore = rte_get_next_lcore(lcore, 0, 0);
1901                         lcore_infos[lcore].streams_nb = streams_per_core;
1902                         if (unassigned_streams) {
1903                                 lcore_infos[lcore].streams_nb++;
1904                                 unassigned_streams--;
1905                         }
1906                 }
1907         }
1908
1909         /*
1910          * Set the streams for the cores according to each logical
1911          * core stream count.
1912          * The streams is built on the design of what received should
1913          * forward as well, this means that if you received packets on
1914          * port 0 queue 0 then the same queue should forward the
1915          * packets, using the same logical core.
1916          */
1917         lcore = rte_get_next_lcore(-1, 0, 0);
1918         for (port = 0; port < nr_port; port++) {
1919                 /* Create FWD stream */
1920                 for (queue = 0; queue < rx_queues_count; queue++) {
1921                         if (!lcore_infos[lcore].streams_nb ||
1922                                 !(stream_id % lcore_infos[lcore].streams_nb)) {
1923                                 lcore = rte_get_next_lcore(lcore, 0, 0);
1924                                 lcore_infos[lcore].mode = LCORE_MODE_PKT;
1925                                 stream_id = 0;
1926                         }
1927                         lcore_infos[lcore].streams[stream_id].rx_queue = queue;
1928                         lcore_infos[lcore].streams[stream_id].tx_queue = queue;
1929                         lcore_infos[lcore].streams[stream_id].rx_port = port;
1930                         lcore_infos[lcore].streams[stream_id].tx_port = port;
1931                         stream_id++;
1932                 }
1933         }
1934
1935         /* Print all streams */
1936         printf(":: Stream -> core id[N]: (rx_port, rx_queue)->(tx_port, tx_queue)\n");
1937         for (i = 0; i < RTE_MAX_LCORE; i++)
1938                 for (j = 0; j < MAX_STREAMS; j++) {
1939                         /* No streams for this core */
1940                         if (lcore_infos[i].streams[j].tx_port == -1)
1941                                 break;
1942                         printf("Stream -> core id[%d]: (%d,%d)->(%d,%d)\n",
1943                                 i,
1944                                 lcore_infos[i].streams[j].rx_port,
1945                                 lcore_infos[i].streams[j].rx_queue,
1946                                 lcore_infos[i].streams[j].tx_port,
1947                                 lcore_infos[i].streams[j].tx_queue);
1948                 }
1949 }
1950
1951 static void
1952 init_port(void)
1953 {
1954         int ret;
1955         uint16_t std_queue;
1956         uint16_t hairpin_queue;
1957         uint16_t port_id;
1958         uint16_t nr_ports;
1959         uint16_t nr_queues;
1960         struct rte_eth_hairpin_conf hairpin_conf = {
1961                 .peer_count = 1,
1962         };
1963         struct rte_eth_conf port_conf = {
1964                 .rx_adv_conf = {
1965                         .rss_conf.rss_hf =
1966                                 GET_RSS_HF(),
1967                 }
1968         };
1969         struct rte_eth_txconf txq_conf;
1970         struct rte_eth_rxconf rxq_conf;
1971         struct rte_eth_dev_info dev_info;
1972
1973         nr_queues = rx_queues_count;
1974         if (hairpin_queues_num != 0)
1975                 nr_queues = rx_queues_count + hairpin_queues_num;
1976
1977         nr_ports = rte_eth_dev_count_avail();
1978         if (nr_ports == 0)
1979                 rte_exit(EXIT_FAILURE, "Error: no port detected\n");
1980
1981         mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool",
1982                                         total_mbuf_num, mbuf_cache_size,
1983                                         0, mbuf_size,
1984                                         rte_socket_id());
1985         if (mbuf_mp == NULL)
1986                 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n");
1987
1988         for (port_id = 0; port_id < nr_ports; port_id++) {
1989                 uint64_t rx_metadata = 0;
1990
1991                 rx_metadata |= RTE_ETH_RX_METADATA_USER_FLAG;
1992                 rx_metadata |= RTE_ETH_RX_METADATA_USER_MARK;
1993
1994                 ret = rte_eth_rx_metadata_negotiate(port_id, &rx_metadata);
1995                 if (ret == 0) {
1996                         if (!(rx_metadata & RTE_ETH_RX_METADATA_USER_FLAG)) {
1997                                 printf(":: flow action FLAG will not affect Rx mbufs on port=%u\n",
1998                                        port_id);
1999                         }
2000
2001                         if (!(rx_metadata & RTE_ETH_RX_METADATA_USER_MARK)) {
2002                                 printf(":: flow action MARK will not affect Rx mbufs on port=%u\n",
2003                                        port_id);
2004                         }
2005                 } else if (ret != -ENOTSUP) {
2006                         rte_exit(EXIT_FAILURE, "Error when negotiating Rx meta features on port=%u: %s\n",
2007                                  port_id, rte_strerror(-ret));
2008                 }
2009
2010                 ret = rte_eth_dev_info_get(port_id, &dev_info);
2011                 if (ret != 0)
2012                         rte_exit(EXIT_FAILURE,
2013                                 "Error during getting device"
2014                                 " (port %u) info: %s\n",
2015                                 port_id, strerror(-ret));
2016
2017                 port_conf.txmode.offloads &= dev_info.tx_offload_capa;
2018                 port_conf.rxmode.offloads &= dev_info.rx_offload_capa;
2019
2020                 printf(":: initializing port: %d\n", port_id);
2021
2022                 ret = rte_eth_dev_configure(port_id, nr_queues,
2023                                 nr_queues, &port_conf);
2024                 if (ret < 0)
2025                         rte_exit(EXIT_FAILURE,
2026                                 ":: cannot configure device: err=%d, port=%u\n",
2027                                 ret, port_id);
2028
2029                 rxq_conf = dev_info.default_rxconf;
2030                 for (std_queue = 0; std_queue < rx_queues_count; std_queue++) {
2031                         ret = rte_eth_rx_queue_setup(port_id, std_queue, rxd_count,
2032                                         rte_eth_dev_socket_id(port_id),
2033                                         &rxq_conf,
2034                                         mbuf_mp);
2035                         if (ret < 0)
2036                                 rte_exit(EXIT_FAILURE,
2037                                         ":: Rx queue setup failed: err=%d, port=%u\n",
2038                                         ret, port_id);
2039                 }
2040
2041                 txq_conf = dev_info.default_txconf;
2042                 for (std_queue = 0; std_queue < tx_queues_count; std_queue++) {
2043                         ret = rte_eth_tx_queue_setup(port_id, std_queue, txd_count,
2044                                         rte_eth_dev_socket_id(port_id),
2045                                         &txq_conf);
2046                         if (ret < 0)
2047                                 rte_exit(EXIT_FAILURE,
2048                                         ":: Tx queue setup failed: err=%d, port=%u\n",
2049                                         ret, port_id);
2050                 }
2051
2052                 /* Catch all packets from traffic generator. */
2053                 ret = rte_eth_promiscuous_enable(port_id);
2054                 if (ret != 0)
2055                         rte_exit(EXIT_FAILURE,
2056                                 ":: promiscuous mode enable failed: err=%s, port=%u\n",
2057                                 rte_strerror(-ret), port_id);
2058
2059                 if (hairpin_queues_num != 0) {
2060                         /*
2061                          * Configure peer which represents hairpin Tx.
2062                          * Hairpin queue numbers start after standard queues
2063                          * (rx_queues_count and tx_queues_count).
2064                          */
2065                         for (hairpin_queue = rx_queues_count, std_queue = 0;
2066                                         hairpin_queue < nr_queues;
2067                                         hairpin_queue++, std_queue++) {
2068                                 hairpin_conf.peers[0].port = port_id;
2069                                 hairpin_conf.peers[0].queue =
2070                                         std_queue + tx_queues_count;
2071                                 ret = rte_eth_rx_hairpin_queue_setup(
2072                                                 port_id, hairpin_queue,
2073                                                 rxd_count, &hairpin_conf);
2074                                 if (ret != 0)
2075                                         rte_exit(EXIT_FAILURE,
2076                                                 ":: Hairpin rx queue setup failed: err=%d, port=%u\n",
2077                                                 ret, port_id);
2078                         }
2079
2080                         for (hairpin_queue = tx_queues_count, std_queue = 0;
2081                                         hairpin_queue < nr_queues;
2082                                         hairpin_queue++, std_queue++) {
2083                                 hairpin_conf.peers[0].port = port_id;
2084                                 hairpin_conf.peers[0].queue =
2085                                         std_queue + rx_queues_count;
2086                                 ret = rte_eth_tx_hairpin_queue_setup(
2087                                                 port_id, hairpin_queue,
2088                                                 txd_count, &hairpin_conf);
2089                                 if (ret != 0)
2090                                         rte_exit(EXIT_FAILURE,
2091                                                 ":: Hairpin tx queue setup failed: err=%d, port=%u\n",
2092                                                 ret, port_id);
2093                         }
2094                 }
2095
2096                 ret = rte_eth_dev_start(port_id);
2097                 if (ret < 0)
2098                         rte_exit(EXIT_FAILURE,
2099                                 "rte_eth_dev_start:err=%d, port=%u\n",
2100                                 ret, port_id);
2101
2102                 printf(":: initializing port: %d done\n", port_id);
2103         }
2104 }
2105
2106 int
2107 main(int argc, char **argv)
2108 {
2109         int ret;
2110         uint16_t port;
2111         struct rte_flow_error error;
2112
2113         ret = rte_eal_init(argc, argv);
2114         if (ret < 0)
2115                 rte_exit(EXIT_FAILURE, "EAL init failed\n");
2116
2117         force_quit = false;
2118         dump_iterations = false;
2119         rules_count = DEFAULT_RULES_COUNT;
2120         rules_batch = DEFAULT_RULES_BATCH;
2121         delete_flag = false;
2122         dump_socket_mem_flag = false;
2123         flow_group = DEFAULT_GROUP;
2124         unique_data = false;
2125
2126         rx_queues_count = (uint8_t) RXQ_NUM;
2127         tx_queues_count = (uint8_t) TXQ_NUM;
2128         rxd_count = (uint8_t) NR_RXD;
2129         txd_count = (uint8_t) NR_TXD;
2130         mbuf_size = (uint32_t) MBUF_SIZE;
2131         mbuf_cache_size = (uint32_t) MBUF_CACHE_SIZE;
2132         total_mbuf_num = (uint32_t) TOTAL_MBUF_NUM;
2133
2134         signal(SIGINT, signal_handler);
2135         signal(SIGTERM, signal_handler);
2136
2137         argc -= ret;
2138         argv += ret;
2139         if (argc > 1)
2140                 args_parse(argc, argv);
2141
2142         init_port();
2143
2144         nb_lcores = rte_lcore_count();
2145         if (nb_lcores <= 1)
2146                 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n");
2147
2148         printf(":: Flows Count per port: %d\n\n", rules_count);
2149
2150         rte_srand(rand_seed);
2151
2152         if (has_meter()) {
2153                 create_meter_profile();
2154                 if (policy_mtr)
2155                         create_meter_policy();
2156         }
2157         rte_eal_mp_remote_launch(run_rte_flow_handler_cores, NULL, CALL_MAIN);
2158
2159         if (enable_fwd) {
2160                 init_lcore_info();
2161                 rte_eal_mp_remote_launch(start_forwarding, NULL, CALL_MAIN);
2162         }
2163         if (has_meter() && delete_flag) {
2164                 destroy_meter_profile();
2165                 if (policy_mtr)
2166                         destroy_meter_policy();
2167         }
2168
2169         RTE_ETH_FOREACH_DEV(port) {
2170                 rte_flow_flush(port, &error);
2171                 if (rte_eth_dev_stop(port) != 0)
2172                         printf("Failed to stop device on port %u\n", port);
2173                 rte_eth_dev_close(port);
2174         }
2175         printf("\nBye ...\n");
2176         return 0;
2177 }