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