xref: /dpdk/app/test-flow-perf/main.c (revision f8dbaebbf1c9efcbb2e2354b341ed62175466a57)
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 cosumed 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 }
2178