xref: /dpdk/examples/flow_filtering/main.c (revision 16158f34900075f2f30b879bf3708e54e07455f4)
1ea9382dcSThomas Monjalon /* SPDX-License-Identifier: BSD-3-Clause
2ea9382dcSThomas Monjalon  * Copyright 2017 Mellanox Technologies, Ltd
34a3ef59aSOri Kam  */
44a3ef59aSOri Kam 
54a3ef59aSOri Kam #include <stdio.h>
64a3ef59aSOri Kam #include <stdlib.h>
74a3ef59aSOri Kam #include <string.h>
84a3ef59aSOri Kam #include <stdint.h>
94a3ef59aSOri Kam #include <inttypes.h>
104a3ef59aSOri Kam #include <sys/types.h>
114a3ef59aSOri Kam #include <sys/queue.h>
124a3ef59aSOri Kam #include <setjmp.h>
134a3ef59aSOri Kam #include <stdarg.h>
144a3ef59aSOri Kam #include <ctype.h>
154a3ef59aSOri Kam #include <errno.h>
164a3ef59aSOri Kam #include <getopt.h>
174a3ef59aSOri Kam #include <signal.h>
184a3ef59aSOri Kam #include <stdbool.h>
194a3ef59aSOri Kam 
204a3ef59aSOri Kam #include <rte_eal.h>
214a3ef59aSOri Kam #include <rte_common.h>
224a3ef59aSOri Kam #include <rte_malloc.h>
234a3ef59aSOri Kam #include <rte_ether.h>
244a3ef59aSOri Kam #include <rte_ethdev.h>
254a3ef59aSOri Kam #include <rte_mempool.h>
264a3ef59aSOri Kam #include <rte_mbuf.h>
274a3ef59aSOri Kam #include <rte_net.h>
284a3ef59aSOri Kam #include <rte_flow.h>
29429cede1SBeilei Xing #include <rte_cycles.h>
30*16158f34SShani Peretz #include <rte_argparse.h>
31*16158f34SShani Peretz 
32*16158f34SShani Peretz #include "common.h"
33*16158f34SShani Peretz 
34*16158f34SShani Peretz /* Template API enabled by default. */
35*16158f34SShani Peretz static int use_template_api = 1;
364a3ef59aSOri Kam 
374a3ef59aSOri Kam static volatile bool force_quit;
386014215aSZhiyong Yang static uint16_t port_id;
394a3ef59aSOri Kam static uint16_t nr_queues = 5;
404a3ef59aSOri Kam struct rte_mempool *mbuf_pool;
414a3ef59aSOri Kam struct rte_flow *flow;
424a3ef59aSOri Kam 
43*16158f34SShani Peretz #define MAX_QUEUE_SIZE 256
444a3ef59aSOri Kam 
454a3ef59aSOri Kam static inline void
466d13ea8eSOlivier Matz print_ether_addr(const char *what, struct rte_ether_addr *eth_addr)
474a3ef59aSOri Kam {
4835b2d13fSOlivier Matz 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
4935b2d13fSOlivier Matz 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
504a3ef59aSOri Kam 	printf("%s%s", what, buf);
514a3ef59aSOri Kam }
524a3ef59aSOri Kam 
53b55efbabSIvan Ilchenko static int
544a3ef59aSOri Kam main_loop(void)
554a3ef59aSOri Kam {
564a3ef59aSOri Kam 	struct rte_mbuf *mbufs[32];
576d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
584a3ef59aSOri Kam 	struct rte_flow_error error;
594a3ef59aSOri Kam 	uint16_t nb_rx;
604a3ef59aSOri Kam 	uint16_t i;
614a3ef59aSOri Kam 	uint16_t j;
62b55efbabSIvan Ilchenko 	int ret;
634a3ef59aSOri Kam 
64*16158f34SShani Peretz 	/* Reading the packets from all queues. */
654a3ef59aSOri Kam 	while (!force_quit) {
664a3ef59aSOri Kam 		for (i = 0; i < nr_queues; i++) {
674a3ef59aSOri Kam 			nb_rx = rte_eth_rx_burst(port_id,
684a3ef59aSOri Kam 						i, mbufs, 32);
694a3ef59aSOri Kam 			if (nb_rx) {
704a3ef59aSOri Kam 				for (j = 0; j < nb_rx; j++) {
714a3ef59aSOri Kam 					struct rte_mbuf *m = mbufs[j];
724a3ef59aSOri Kam 
734a3ef59aSOri Kam 					eth_hdr = rte_pktmbuf_mtod(m,
746d13ea8eSOlivier Matz 							struct rte_ether_hdr *);
754a3ef59aSOri Kam 					print_ether_addr("src=",
7604d43857SDmitry Kozlyuk 							&eth_hdr->src_addr);
774a3ef59aSOri Kam 					print_ether_addr(" - dst=",
7804d43857SDmitry Kozlyuk 							&eth_hdr->dst_addr);
794a3ef59aSOri Kam 					printf(" - queue=0x%x",
804a3ef59aSOri Kam 							(unsigned int)i);
814a3ef59aSOri Kam 					printf("\n");
824a3ef59aSOri Kam 
834a3ef59aSOri Kam 					rte_pktmbuf_free(m);
844a3ef59aSOri Kam 				}
854a3ef59aSOri Kam 			}
864a3ef59aSOri Kam 		}
874a3ef59aSOri Kam 	}
884a3ef59aSOri Kam 
894a3ef59aSOri Kam 	/* closing and releasing resources */
904a3ef59aSOri Kam 	rte_flow_flush(port_id, &error);
91b55efbabSIvan Ilchenko 	ret = rte_eth_dev_stop(port_id);
92b55efbabSIvan Ilchenko 	if (ret < 0)
93b55efbabSIvan Ilchenko 		printf("Failed to stop port %u: %s",
94b55efbabSIvan Ilchenko 			   port_id, rte_strerror(-ret));
954a3ef59aSOri Kam 	rte_eth_dev_close(port_id);
96b55efbabSIvan Ilchenko 	return ret;
974a3ef59aSOri Kam }
984a3ef59aSOri Kam 
99429cede1SBeilei Xing #define CHECK_INTERVAL 1000  /* 100ms */
100429cede1SBeilei Xing #define MAX_REPEAT_TIMES 90  /* 9s (90 * 100ms) in total */
101429cede1SBeilei Xing 
1024a3ef59aSOri Kam static void
1034a3ef59aSOri Kam assert_link_status(void)
1044a3ef59aSOri Kam {
1054a3ef59aSOri Kam 	struct rte_eth_link link;
106429cede1SBeilei Xing 	uint8_t rep_cnt = MAX_REPEAT_TIMES;
10722e5c73bSIgor Romanov 	int link_get_err = -EINVAL;
1084a3ef59aSOri Kam 
1094a3ef59aSOri Kam 	memset(&link, 0, sizeof(link));
110429cede1SBeilei Xing 	do {
11122e5c73bSIgor Romanov 		link_get_err = rte_eth_link_get(port_id, &link);
112295968d1SFerruh Yigit 		if (link_get_err == 0 && link.link_status == RTE_ETH_LINK_UP)
113429cede1SBeilei Xing 			break;
114429cede1SBeilei Xing 		rte_delay_ms(CHECK_INTERVAL);
115429cede1SBeilei Xing 	} while (--rep_cnt);
116429cede1SBeilei Xing 
11722e5c73bSIgor Romanov 	if (link_get_err < 0)
11822e5c73bSIgor Romanov 		rte_exit(EXIT_FAILURE, ":: error: link get is failing: %s\n",
11922e5c73bSIgor Romanov 			 rte_strerror(-link_get_err));
120295968d1SFerruh Yigit 	if (link.link_status == RTE_ETH_LINK_DOWN)
1214a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE, ":: error: link is still down\n");
1224a3ef59aSOri Kam }
1234a3ef59aSOri Kam 
124*16158f34SShani Peretz static void
125*16158f34SShani Peretz configure_port_template(uint16_t port_id)
126*16158f34SShani Peretz {
127*16158f34SShani Peretz 	int ret;
128*16158f34SShani Peretz 	uint16_t std_queue;
129*16158f34SShani Peretz 	struct rte_flow_error error;
130*16158f34SShani Peretz 	struct rte_flow_queue_attr queue_attr[RTE_MAX_LCORE];
131*16158f34SShani Peretz 	const struct rte_flow_queue_attr *attr_list[RTE_MAX_LCORE];
132*16158f34SShani Peretz 	struct rte_flow_port_attr port_attr = { .nb_counters = 1 /* rules count */ };
133*16158f34SShani Peretz 
134*16158f34SShani Peretz 	for (std_queue = 0; std_queue < RTE_MAX_LCORE; std_queue++) {
135*16158f34SShani Peretz 		queue_attr[std_queue].size = MAX_QUEUE_SIZE;
136*16158f34SShani Peretz 		attr_list[std_queue] = &queue_attr[std_queue];
137*16158f34SShani Peretz 	}
138*16158f34SShani Peretz 
139*16158f34SShani Peretz 	ret = rte_flow_configure(port_id, &port_attr,
140*16158f34SShani Peretz 				 1, attr_list, &error);
141*16158f34SShani Peretz 	if (ret != 0)
142*16158f34SShani Peretz 		rte_exit(EXIT_FAILURE,
143*16158f34SShani Peretz 			 "rte_flow_configure:err=%d, port=%u\n",
144*16158f34SShani Peretz 			 ret, port_id);
145*16158f34SShani Peretz 	printf(":: Configuring template port [%d] Done ..\n", port_id);
146*16158f34SShani Peretz }
147*16158f34SShani Peretz 
1484a3ef59aSOri Kam static void
1494a3ef59aSOri Kam init_port(void)
1504a3ef59aSOri Kam {
1514a3ef59aSOri Kam 	int ret;
1524a3ef59aSOri Kam 	uint16_t i;
153*16158f34SShani Peretz 	/* Ethernet port configured with default settings. */
1544a3ef59aSOri Kam 	struct rte_eth_conf port_conf = {
155feca6c42SWei Zhao 		.txmode = {
156feca6c42SWei Zhao 			.offloads =
157295968d1SFerruh Yigit 				RTE_ETH_TX_OFFLOAD_VLAN_INSERT |
158295968d1SFerruh Yigit 				RTE_ETH_TX_OFFLOAD_IPV4_CKSUM  |
159295968d1SFerruh Yigit 				RTE_ETH_TX_OFFLOAD_UDP_CKSUM   |
160295968d1SFerruh Yigit 				RTE_ETH_TX_OFFLOAD_TCP_CKSUM   |
161295968d1SFerruh Yigit 				RTE_ETH_TX_OFFLOAD_SCTP_CKSUM  |
162295968d1SFerruh Yigit 				RTE_ETH_TX_OFFLOAD_TCP_TSO,
163feca6c42SWei Zhao 		},
1644a3ef59aSOri Kam 	};
165feca6c42SWei Zhao 	struct rte_eth_txconf txq_conf;
166e6bb3077SShahaf Shuler 	struct rte_eth_rxconf rxq_conf;
167feca6c42SWei Zhao 	struct rte_eth_dev_info dev_info;
1684a3ef59aSOri Kam 
169d9a66c56SIvan Ilchenko 	ret = rte_eth_dev_info_get(port_id, &dev_info);
170d9a66c56SIvan Ilchenko 	if (ret != 0)
171d9a66c56SIvan Ilchenko 		rte_exit(EXIT_FAILURE,
172d9a66c56SIvan Ilchenko 			"Error during getting device (port %u) info: %s\n",
173d9a66c56SIvan Ilchenko 			port_id, strerror(-ret));
174d9a66c56SIvan Ilchenko 
175a5e7c52dSOri Kam 	port_conf.txmode.offloads &= dev_info.tx_offload_capa;
1764a3ef59aSOri Kam 	printf(":: initializing port: %d\n", port_id);
1774a3ef59aSOri Kam 	ret = rte_eth_dev_configure(port_id,
1784a3ef59aSOri Kam 				nr_queues, nr_queues, &port_conf);
1794a3ef59aSOri Kam 	if (ret < 0) {
1804a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE,
1814a3ef59aSOri Kam 			":: cannot configure device: err=%d, port=%u\n",
1824a3ef59aSOri Kam 			ret, port_id);
1834a3ef59aSOri Kam 	}
1844a3ef59aSOri Kam 
185e6bb3077SShahaf Shuler 	rxq_conf = dev_info.default_rxconf;
186e6bb3077SShahaf Shuler 	rxq_conf.offloads = port_conf.rxmode.offloads;
1879a212dc0SConor Fogarty 
188*16158f34SShani Peretz 	/* Configuring number of RX and TX queues connected to single port. */
1894a3ef59aSOri Kam 	for (i = 0; i < nr_queues; i++) {
1904a3ef59aSOri Kam 		ret = rte_eth_rx_queue_setup(port_id, i, 512,
1914a3ef59aSOri Kam 					 rte_eth_dev_socket_id(port_id),
192e6bb3077SShahaf Shuler 					 &rxq_conf,
1934a3ef59aSOri Kam 					 mbuf_pool);
1944a3ef59aSOri Kam 		if (ret < 0) {
1954a3ef59aSOri Kam 			rte_exit(EXIT_FAILURE,
1964a3ef59aSOri Kam 				":: Rx queue setup failed: err=%d, port=%u\n",
1974a3ef59aSOri Kam 				ret, port_id);
1984a3ef59aSOri Kam 		}
1994a3ef59aSOri Kam 	}
2004a3ef59aSOri Kam 
201feca6c42SWei Zhao 	txq_conf = dev_info.default_txconf;
202feca6c42SWei Zhao 	txq_conf.offloads = port_conf.txmode.offloads;
203feca6c42SWei Zhao 
204feca6c42SWei Zhao 	for (i = 0; i < nr_queues; i++) {
205feca6c42SWei Zhao 		ret = rte_eth_tx_queue_setup(port_id, i, 512,
206feca6c42SWei Zhao 				rte_eth_dev_socket_id(port_id),
207feca6c42SWei Zhao 				&txq_conf);
208feca6c42SWei Zhao 		if (ret < 0) {
209feca6c42SWei Zhao 			rte_exit(EXIT_FAILURE,
210feca6c42SWei Zhao 				":: Tx queue setup failed: err=%d, port=%u\n",
211feca6c42SWei Zhao 				ret, port_id);
212feca6c42SWei Zhao 		}
213feca6c42SWei Zhao 	}
214feca6c42SWei Zhao 
215*16158f34SShani Peretz 	/* Setting the RX port to promiscuous mode. */
216f430bbceSIvan Ilchenko 	ret = rte_eth_promiscuous_enable(port_id);
217f430bbceSIvan Ilchenko 	if (ret != 0)
218f430bbceSIvan Ilchenko 		rte_exit(EXIT_FAILURE,
219f430bbceSIvan Ilchenko 			":: promiscuous mode enable failed: err=%s, port=%u\n",
220f430bbceSIvan Ilchenko 			rte_strerror(-ret), port_id);
221f430bbceSIvan Ilchenko 
2224a3ef59aSOri Kam 	ret = rte_eth_dev_start(port_id);
2234a3ef59aSOri Kam 	if (ret < 0) {
2244a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE,
2254a3ef59aSOri Kam 			"rte_eth_dev_start:err=%d, port=%u\n",
2264a3ef59aSOri Kam 			ret, port_id);
2274a3ef59aSOri Kam 	}
2284a3ef59aSOri Kam 
2294a3ef59aSOri Kam 	assert_link_status();
2304a3ef59aSOri Kam 
2314a3ef59aSOri Kam 	printf(":: initializing port: %d done\n", port_id);
232*16158f34SShani Peretz 
233*16158f34SShani Peretz 	if (use_template_api == 0)
234*16158f34SShani Peretz 		return;
235*16158f34SShani Peretz 
236*16158f34SShani Peretz 	/* Adds rules engine configuration. 8< */
237*16158f34SShani Peretz 	ret = rte_eth_dev_stop(port_id);
238*16158f34SShani Peretz 	if (ret < 0)
239*16158f34SShani Peretz 		rte_exit(EXIT_FAILURE,
240*16158f34SShani Peretz 			"rte_eth_dev_stop:err=%d, port=%u\n",
241*16158f34SShani Peretz 			ret, port_id);
242*16158f34SShani Peretz 
243*16158f34SShani Peretz 	configure_port_template(port_id);
244*16158f34SShani Peretz 	ret = rte_eth_dev_start(port_id);
245*16158f34SShani Peretz 	if (ret < 0)
246*16158f34SShani Peretz 		rte_exit(EXIT_FAILURE,
247*16158f34SShani Peretz 			"rte_eth_dev_start:err=%d, port=%u\n",
248*16158f34SShani Peretz 			ret, port_id);
249*16158f34SShani Peretz 	/* >8 End of adding rules engine configuration. */
2504a3ef59aSOri Kam }
2514a3ef59aSOri Kam 
2524a3ef59aSOri Kam static void
2534a3ef59aSOri Kam signal_handler(int signum)
2544a3ef59aSOri Kam {
2554a3ef59aSOri Kam 	if (signum == SIGINT || signum == SIGTERM) {
2564a3ef59aSOri Kam 		printf("\n\nSignal %d received, preparing to exit...\n",
2574a3ef59aSOri Kam 				signum);
2584a3ef59aSOri Kam 		force_quit = true;
2594a3ef59aSOri Kam 	}
2604a3ef59aSOri Kam }
2614a3ef59aSOri Kam 
262*16158f34SShani Peretz /* Parse the argument given in the command line of the application */
263*16158f34SShani Peretz static int
264*16158f34SShani Peretz flow_filtering_parse_args(int argc, char **argv)
265*16158f34SShani Peretz {
266*16158f34SShani Peretz 	static struct rte_argparse obj = {
267*16158f34SShani Peretz 		.prog_name = "flow_filtering",
268*16158f34SShani Peretz 		.usage = "[EAL options] -- [optional parameters]",
269*16158f34SShani Peretz 		.descriptor = NULL,
270*16158f34SShani Peretz 		.epilog = NULL,
271*16158f34SShani Peretz 		.exit_on_error = false,
272*16158f34SShani Peretz 		.callback = NULL,
273*16158f34SShani Peretz 		.opaque = NULL,
274*16158f34SShani Peretz 		.args = {
275*16158f34SShani Peretz 			{ "--template", NULL, "Enable template API flow",
276*16158f34SShani Peretz 			  &use_template_api, (void *)1,
277*16158f34SShani Peretz 			  RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT,
278*16158f34SShani Peretz 			},
279*16158f34SShani Peretz 			{ "--non-template", NULL, "Enable non template API flow",
280*16158f34SShani Peretz 			  &use_template_api, (void *)0,
281*16158f34SShani Peretz 			  RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT,
282*16158f34SShani Peretz 			},
283*16158f34SShani Peretz 			ARGPARSE_ARG_END(),
284*16158f34SShani Peretz 		},
285*16158f34SShani Peretz 	};
286*16158f34SShani Peretz 
287*16158f34SShani Peretz 	return rte_argparse_parse(&obj, argc, argv);
288*16158f34SShani Peretz }
289*16158f34SShani Peretz 
2904a3ef59aSOri Kam int
2914a3ef59aSOri Kam main(int argc, char **argv)
2924a3ef59aSOri Kam {
2934a3ef59aSOri Kam 	int ret;
294d9a42a69SThomas Monjalon 	uint16_t nr_ports;
2954a3ef59aSOri Kam 	struct rte_flow_error error;
2964a3ef59aSOri Kam 
2979a212dc0SConor Fogarty 	/* Initialize EAL. 8< */
2984a3ef59aSOri Kam 	ret = rte_eal_init(argc, argv);
2994a3ef59aSOri Kam 	if (ret < 0)
3004a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE, ":: invalid EAL arguments\n");
3019a212dc0SConor Fogarty 	/* >8 End of Initialization of EAL. */
302*16158f34SShani Peretz 	argc -= ret;
303*16158f34SShani Peretz 	argv += ret;
3044a3ef59aSOri Kam 
3054a3ef59aSOri Kam 	force_quit = false;
3064a3ef59aSOri Kam 	signal(SIGINT, signal_handler);
3074a3ef59aSOri Kam 	signal(SIGTERM, signal_handler);
3084a3ef59aSOri Kam 
309*16158f34SShani Peretz 	/* Parse application arguments (after the EAL ones) */
310*16158f34SShani Peretz 	ret = flow_filtering_parse_args(argc, argv);
311*16158f34SShani Peretz 	if (ret < 0)
312*16158f34SShani Peretz 		rte_exit(EXIT_FAILURE, "Invalid flow filtering arguments\n");
313*16158f34SShani Peretz 
314d9a42a69SThomas Monjalon 	nr_ports = rte_eth_dev_count_avail();
3154a3ef59aSOri Kam 	if (nr_ports == 0)
3164a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE, ":: no Ethernet ports found\n");
3174a3ef59aSOri Kam 	port_id = 0;
3184a3ef59aSOri Kam 	if (nr_ports != 1) {
3194a3ef59aSOri Kam 		printf(":: warn: %d ports detected, but we use only one: port %u\n",
3204a3ef59aSOri Kam 			nr_ports, port_id);
3214a3ef59aSOri Kam 	}
322*16158f34SShani Peretz 
3239a212dc0SConor Fogarty 	/* Allocates a mempool to hold the mbufs. 8< */
3244a3ef59aSOri Kam 	mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0,
3254a3ef59aSOri Kam 						RTE_MBUF_DEFAULT_BUF_SIZE,
3264a3ef59aSOri Kam 						rte_socket_id());
3279a212dc0SConor Fogarty 	/* >8 End of allocating a mempool to hold the mbufs. */
3284a3ef59aSOri Kam 	if (mbuf_pool == NULL)
3294a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
3304a3ef59aSOri Kam 
3319a212dc0SConor Fogarty 	/* Initializes all the ports using the user defined init_port(). 8< */
3324a3ef59aSOri Kam 	init_port();
3339a212dc0SConor Fogarty 	/* >8 End of Initializing the ports using user defined init_port(). */
3344a3ef59aSOri Kam 
335*16158f34SShani Peretz 	/* Function responsible for creating the flow rule. 8< */
336*16158f34SShani Peretz 	flow = generate_flow_skeleton(port_id, &error, use_template_api);
337*16158f34SShani Peretz 	/* >8 End of function responsible for creating the flow rule. */
338*16158f34SShani Peretz 
3394a3ef59aSOri Kam 	if (!flow) {
3404a3ef59aSOri Kam 		printf("Flow can't be created %d message: %s\n",
3414a3ef59aSOri Kam 			error.type,
3424a3ef59aSOri Kam 			error.message ? error.message : "(no stated reason)");
3434a3ef59aSOri Kam 		rte_exit(EXIT_FAILURE, "error in creating flow");
3444a3ef59aSOri Kam 	}
345*16158f34SShani Peretz 	printf("Flow created!!:\n");
3464a3ef59aSOri Kam 
3479a212dc0SConor Fogarty 	/* Launching main_loop(). 8< */
34810aa3757SChengchang Tang 	ret = main_loop();
3499a212dc0SConor Fogarty 	/* >8 End of launching main_loop(). */
35010aa3757SChengchang Tang 
35110aa3757SChengchang Tang 	/* clean up the EAL */
35210aa3757SChengchang Tang 	rte_eal_cleanup();
35310aa3757SChengchang Tang 
35410aa3757SChengchang Tang 	return ret;
3554a3ef59aSOri Kam }
356