1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020 Mellanox Technologies, Ltd
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/
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
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.
31 #include <rte_malloc.h>
32 #include <rte_mempool.h>
34 #include <rte_ethdev.h>
40 #define MAX_ITERATIONS 100
41 #define DEFAULT_RULES_COUNT 4000000
42 #define DEFAULT_ITERATION 100000
44 struct rte_flow *flow;
45 static uint8_t flow_group;
47 static uint64_t flow_items;
48 static uint64_t flow_actions;
49 static uint64_t flow_attrs;
50 static volatile bool force_quit;
51 static bool dump_iterations;
52 static struct rte_mempool *mbuf_mp;
53 static uint32_t nb_lcores;
54 static uint32_t flows_count;
55 static uint32_t iterations_number;
56 static uint32_t hairpinq;
61 printf("\nusage: %s\n", progname);
62 printf("\nControl configurations:\n");
63 printf(" --flows-count=N: to set the number of needed"
64 " flows to insert, default is 4,000,000\n");
65 printf(" --dump-iterations: To print rates for each"
68 printf("To set flow attributes:\n");
69 printf(" --ingress: set ingress attribute in flows\n");
70 printf(" --egress: set egress attribute in flows\n");
71 printf(" --transfer: set transfer attribute in flows\n");
72 printf(" --group=N: set group for all flows,"
75 printf("To set flow items:\n");
76 printf(" --ether: add ether layer in flow items\n");
77 printf(" --vlan: add vlan layer in flow items\n");
78 printf(" --ipv4: add ipv4 layer in flow items\n");
79 printf(" --ipv6: add ipv6 layer in flow items\n");
80 printf(" --tcp: add tcp layer in flow items\n");
81 printf(" --udp: add udp layer in flow items\n");
82 printf(" --vxlan: add vxlan layer in flow items\n");
83 printf(" --vxlan-gpe: add vxlan-gpe layer in flow items\n");
84 printf(" --gre: add gre layer in flow items\n");
85 printf(" --geneve: add geneve layer in flow items\n");
86 printf(" --gtp: add gtp layer in flow items\n");
87 printf(" --meta: add meta layer in flow items\n");
88 printf(" --tag: add tag layer in flow items\n");
90 printf("To set flow actions:\n");
91 printf(" --port-id: add port-id action in flow actions\n");
92 printf(" --rss: add rss action in flow actions\n");
93 printf(" --queue: add queue action in flow actions\n");
94 printf(" --jump: add jump action in flow actions\n");
95 printf(" --mark: add mark action in flow actions\n");
96 printf(" --count: add count action in flow actions\n");
97 printf(" --set-meta: add set meta action in flow actions\n");
98 printf(" --set-tag: add set tag action in flow actions\n");
99 printf(" --drop: add drop action in flow actions\n");
100 printf(" --hairpin-queue=N: add hairpin-queue action in flow actions\n");
101 printf(" --hairpin-rss=N: add hairping-rss action in flow actions\n");
105 args_parse(int argc, char **argv)
112 static const struct option_dict {
119 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH),
120 .bitmap = &flow_items
124 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV4),
125 .bitmap = &flow_items
129 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_IPV6),
130 .bitmap = &flow_items
134 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VLAN),
135 .bitmap = &flow_items
139 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TCP),
140 .bitmap = &flow_items
144 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_UDP),
145 .bitmap = &flow_items
149 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN),
150 .bitmap = &flow_items
154 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_VXLAN_GPE),
155 .bitmap = &flow_items
159 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GRE),
160 .bitmap = &flow_items
164 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GENEVE),
165 .bitmap = &flow_items
169 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_GTP),
170 .bitmap = &flow_items
174 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_META),
175 .bitmap = &flow_items
179 .mask = FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_TAG),
180 .bitmap = &flow_items
185 .bitmap = &flow_attrs
190 .bitmap = &flow_attrs
195 .bitmap = &flow_attrs
199 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_PORT_ID),
200 .bitmap = &flow_actions
204 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_RSS),
205 .bitmap = &flow_actions
209 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_QUEUE),
210 .bitmap = &flow_actions
214 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_JUMP),
215 .bitmap = &flow_actions
219 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_MARK),
220 .bitmap = &flow_actions
224 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_COUNT),
225 .bitmap = &flow_actions
229 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_META),
230 .bitmap = &flow_actions
234 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_SET_TAG),
235 .bitmap = &flow_actions
239 .mask = FLOW_ACTION_MASK(RTE_FLOW_ACTION_TYPE_DROP),
240 .bitmap = &flow_actions
244 static const struct option lgopts[] = {
247 { "flows-count", 1, 0, 0 },
248 { "dump-iterations", 0, 0, 0 },
250 { "ingress", 0, 0, 0 },
251 { "egress", 0, 0, 0 },
252 { "transfer", 0, 0, 0 },
253 { "group", 1, 0, 0 },
255 { "ether", 0, 0, 0 },
261 { "vxlan", 0, 0, 0 },
262 { "vxlan-gpe", 0, 0, 0 },
264 { "geneve", 0, 0, 0 },
269 { "port-id", 0, 0, 0 },
271 { "queue", 0, 0, 0 },
274 { "count", 0, 0, 0 },
275 { "set-meta", 0, 0, 0 },
276 { "set-tag", 0, 0, 0 },
278 { "hairpin-queue", 1, 0, 0 },
279 { "hairpin-rss", 1, 0, 0 },
288 printf(":: Flow -> ");
289 while ((opt = getopt_long(argc, argvopt, "",
290 lgopts, &opt_idx)) != EOF) {
293 if (strcmp(lgopts[opt_idx].name, "help") == 0) {
295 rte_exit(EXIT_SUCCESS, "Displayed help\n");
298 if (strcmp(lgopts[opt_idx].name, "group") == 0) {
303 rte_exit(EXIT_SUCCESS,
304 "flow group should be >= 0\n");
305 printf("group %d ", flow_group);
308 for (i = 0; i < RTE_DIM(flow_options); i++)
309 if (strcmp(lgopts[opt_idx].name,
310 flow_options[i].str) == 0) {
311 *flow_options[i].bitmap |=
312 flow_options[i].mask;
313 printf("%s / ", flow_options[i].str);
316 if (strcmp(lgopts[opt_idx].name,
317 "hairpin-rss") == 0) {
322 rte_exit(EXIT_SUCCESS,
323 "Hairpin queues should be > 0\n");
325 flow_actions |= HAIRPIN_RSS_ACTION;
326 printf("hairpin-rss / ");
328 if (strcmp(lgopts[opt_idx].name,
329 "hairpin-queue") == 0) {
334 rte_exit(EXIT_SUCCESS,
335 "Hairpin queues should be > 0\n");
337 flow_actions |= HAIRPIN_QUEUE_ACTION;
338 printf("hairpin-queue / ");
342 if (strcmp(lgopts[opt_idx].name,
343 "flows-count") == 0) {
345 if (n > (int) iterations_number)
348 printf("\n\nflows_count should be > %d\n",
350 rte_exit(EXIT_SUCCESS, " ");
353 if (strcmp(lgopts[opt_idx].name,
354 "dump-iterations") == 0)
355 dump_iterations = true;
358 fprintf(stderr, "Invalid option: %s\n", argv[optind]);
360 rte_exit(EXIT_SUCCESS, "Invalid option\n");
364 printf("end_flow\n");
368 print_flow_error(struct rte_flow_error error)
370 printf("Flow can't be created %d message: %s\n",
372 error.message ? error.message : "(no stated reason)");
378 struct rte_flow_error error;
379 clock_t start_iter, end_iter;
380 double cpu_time_used;
382 double cpu_time_per_iter[MAX_ITERATIONS];
389 nr_ports = rte_eth_dev_count_avail();
391 for (i = 0; i < MAX_ITERATIONS; i++)
392 cpu_time_per_iter[i] = -1;
394 if (iterations_number > flows_count)
395 iterations_number = flows_count;
397 printf(":: Flows Count per port: %d\n", flows_count);
399 for (port_id = 0; port_id < nr_ports; port_id++) {
401 if (flow_group > 0) {
403 * Create global rule to jump into flow_group,
404 * this way the app will avoid the default rules.
407 * group 0 eth / end actions jump group <flow_group>
410 flow = generate_flow(port_id, 0, flow_attrs,
411 FLOW_ITEM_MASK(RTE_FLOW_ITEM_TYPE_ETH),
412 FLOW_ITEM_MASK(RTE_FLOW_ACTION_TYPE_JUMP),
413 flow_group, 0, 0, &error);
416 print_flow_error(error);
417 rte_exit(EXIT_FAILURE, "error in creating flow");
422 printf("Flows insertion on port = %d\n", port_id);
423 start_iter = clock();
424 for (i = 0; i < flows_count; i++) {
425 flow = generate_flow(port_id, flow_group,
426 flow_attrs, flow_items, flow_actions,
427 JUMP_ACTION_TABLE, i, hairpinq, &error);
433 print_flow_error(error);
434 rte_exit(EXIT_FAILURE, "error in creating flow");
437 if (i && !((i + 1) % iterations_number)) {
438 /* Save the insertion rate of each iter */
440 delta = (double) (end_iter - start_iter);
441 iter_id = ((i + 1) / iterations_number) - 1;
442 cpu_time_per_iter[iter_id] =
443 delta / CLOCKS_PER_SEC;
444 cpu_time_used += cpu_time_per_iter[iter_id];
445 start_iter = clock();
449 /* Iteration rate per iteration */
451 for (i = 0; i < MAX_ITERATIONS; i++) {
452 if (cpu_time_per_iter[i] == -1)
454 delta = (double)(iterations_number /
455 cpu_time_per_iter[i]);
456 flows_rate = delta / 1000;
457 printf(":: Iteration #%d: %d flows "
458 "in %f sec[ Rate = %f K/Sec ]\n",
459 i, iterations_number,
460 cpu_time_per_iter[i], flows_rate);
463 /* Insertion rate for all flows */
464 flows_rate = ((double) (flows_count / cpu_time_used) / 1000);
465 printf("\n:: Total flow insertion rate -> %f K/Sec\n",
467 printf(":: The time for creating %d in flows %f seconds\n",
468 flows_count, cpu_time_used);
473 signal_handler(int signum)
475 if (signum == SIGINT || signum == SIGTERM) {
476 printf("\n\nSignal %d received, preparing to exit...\n",
478 printf("Error: Stats are wrong due to sudden signal!\n\n");
492 struct rte_eth_hairpin_conf hairpin_conf = {
495 struct rte_eth_conf port_conf = {
501 struct rte_eth_txconf txq_conf;
502 struct rte_eth_rxconf rxq_conf;
503 struct rte_eth_dev_info dev_info;
507 nr_queues = RXQ_NUM + hairpinq;
509 nr_ports = rte_eth_dev_count_avail();
511 rte_exit(EXIT_FAILURE, "Error: no port detected\n");
513 mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool",
514 TOTAL_MBUF_NUM, MBUF_CACHE_SIZE,
518 rte_exit(EXIT_FAILURE, "Error: can't init mbuf pool\n");
520 for (port_id = 0; port_id < nr_ports; port_id++) {
521 ret = rte_eth_dev_info_get(port_id, &dev_info);
523 rte_exit(EXIT_FAILURE,
524 "Error during getting device"
525 " (port %u) info: %s\n",
526 port_id, strerror(-ret));
528 port_conf.txmode.offloads &= dev_info.tx_offload_capa;
529 port_conf.rxmode.offloads &= dev_info.rx_offload_capa;
531 printf(":: initializing port: %d\n", port_id);
533 ret = rte_eth_dev_configure(port_id, nr_queues,
534 nr_queues, &port_conf);
536 rte_exit(EXIT_FAILURE,
537 ":: cannot configure device: err=%d, port=%u\n",
540 rxq_conf = dev_info.default_rxconf;
541 for (std_queue = 0; std_queue < RXQ_NUM; std_queue++) {
542 ret = rte_eth_rx_queue_setup(port_id, std_queue, NR_RXD,
543 rte_eth_dev_socket_id(port_id),
547 rte_exit(EXIT_FAILURE,
548 ":: Rx queue setup failed: err=%d, port=%u\n",
552 txq_conf = dev_info.default_txconf;
553 for (std_queue = 0; std_queue < TXQ_NUM; std_queue++) {
554 ret = rte_eth_tx_queue_setup(port_id, std_queue, NR_TXD,
555 rte_eth_dev_socket_id(port_id),
558 rte_exit(EXIT_FAILURE,
559 ":: Tx queue setup failed: err=%d, port=%u\n",
563 /* Catch all packets from traffic generator. */
564 ret = rte_eth_promiscuous_enable(port_id);
566 rte_exit(EXIT_FAILURE,
567 ":: promiscuous mode enable failed: err=%s, port=%u\n",
568 rte_strerror(-ret), port_id);
571 for (hairpin_q = RXQ_NUM, std_queue = 0;
572 std_queue < nr_queues;
573 hairpin_q++, std_queue++) {
574 hairpin_conf.peers[0].port = port_id;
575 hairpin_conf.peers[0].queue =
577 ret = rte_eth_rx_hairpin_queue_setup(
579 NR_RXD, &hairpin_conf);
581 rte_exit(EXIT_FAILURE,
582 ":: Hairpin rx queue setup failed: err=%d, port=%u\n",
586 for (hairpin_q = TXQ_NUM, std_queue = 0;
587 std_queue < nr_queues;
588 hairpin_q++, std_queue++) {
589 hairpin_conf.peers[0].port = port_id;
590 hairpin_conf.peers[0].queue =
592 ret = rte_eth_tx_hairpin_queue_setup(
594 NR_TXD, &hairpin_conf);
596 rte_exit(EXIT_FAILURE,
597 ":: Hairpin tx queue setup failed: err=%d, port=%u\n",
602 ret = rte_eth_dev_start(port_id);
604 rte_exit(EXIT_FAILURE,
605 "rte_eth_dev_start:err=%d, port=%u\n",
608 printf(":: initializing port: %d done\n", port_id);
613 main(int argc, char **argv)
617 struct rte_flow_error error;
619 ret = rte_eal_init(argc, argv);
621 rte_exit(EXIT_FAILURE, "EAL init failed\n");
624 dump_iterations = false;
625 flows_count = DEFAULT_RULES_COUNT;
626 iterations_number = DEFAULT_ITERATION;
629 signal(SIGINT, signal_handler);
630 signal(SIGTERM, signal_handler);
635 args_parse(argc, argv);
639 nb_lcores = rte_lcore_count();
641 rte_exit(EXIT_FAILURE, "This app needs at least two cores\n");
645 RTE_ETH_FOREACH_DEV(port) {
646 rte_flow_flush(port, &error);
647 rte_eth_dev_stop(port);
648 rte_eth_dev_close(port);