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