1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  * Copyright(c) 2010-2014 Intel Corporation
3a9643ea8Slogwang  */
4a9643ea8Slogwang 
5a9643ea8Slogwang #include <stdint.h>
6a9643ea8Slogwang #include <stdio.h>
7a9643ea8Slogwang #include <string.h>
8a9643ea8Slogwang #include <sys/queue.h>
9a9643ea8Slogwang #include <errno.h>
10a9643ea8Slogwang #include <stdarg.h>
11a9643ea8Slogwang #include <inttypes.h>
12a9643ea8Slogwang 
13a9643ea8Slogwang #include <rte_common.h>
14a9643ea8Slogwang #include <rte_memory.h>
15a9643ea8Slogwang #include <rte_memzone.h>
16a9643ea8Slogwang #include <rte_eal.h>
17a9643ea8Slogwang #include <rte_byteorder.h>
18a9643ea8Slogwang #include <rte_atomic.h>
19a9643ea8Slogwang #include <rte_launch.h>
20a9643ea8Slogwang #include <rte_per_lcore.h>
21a9643ea8Slogwang #include <rte_lcore.h>
22a9643ea8Slogwang #include <rte_branch_prediction.h>
23a9643ea8Slogwang #include <rte_debug.h>
24a9643ea8Slogwang #include <rte_ring.h>
25a9643ea8Slogwang #include <rte_log.h>
26a9643ea8Slogwang #include <rte_mempool.h>
27a9643ea8Slogwang #include <rte_memcpy.h>
28a9643ea8Slogwang #include <rte_mbuf.h>
29a9643ea8Slogwang #include <rte_interrupts.h>
30a9643ea8Slogwang #include <rte_ether.h>
31a9643ea8Slogwang #include <rte_ethdev.h>
32a9643ea8Slogwang #include <rte_malloc.h>
33a9643ea8Slogwang #include <rte_string_fns.h>
34a9643ea8Slogwang #include <rte_cycles.h>
35a9643ea8Slogwang 
36a9643ea8Slogwang #include "common.h"
37a9643ea8Slogwang #include "args.h"
38a9643ea8Slogwang #include "init.h"
39a9643ea8Slogwang 
40a9643ea8Slogwang #define MBUF_CACHE_SIZE 512
41a9643ea8Slogwang 
42d30ea906Sjfb8856606 #define RTE_MP_RX_DESC_DEFAULT 1024
43d30ea906Sjfb8856606 #define RTE_MP_TX_DESC_DEFAULT 1024
44a9643ea8Slogwang #define CLIENT_QUEUE_RINGSIZE 128
45a9643ea8Slogwang 
46a9643ea8Slogwang #define NO_FLAGS 0
47a9643ea8Slogwang 
48a9643ea8Slogwang /* The mbuf pool for packet rx */
49a9643ea8Slogwang struct rte_mempool *pktmbuf_pool;
50a9643ea8Slogwang 
51a9643ea8Slogwang /* array of info/queues for clients */
52a9643ea8Slogwang struct client *clients = NULL;
53a9643ea8Slogwang 
54a9643ea8Slogwang /* the port details */
55a9643ea8Slogwang struct port_info *ports;
56a9643ea8Slogwang 
57a9643ea8Slogwang /**
58a9643ea8Slogwang  * Initialise the mbuf pool for packet reception for the NIC, and any other
59a9643ea8Slogwang  * buffer pools needed by the app - currently none.
60a9643ea8Slogwang  */
61a9643ea8Slogwang static int
init_mbuf_pools(void)62a9643ea8Slogwang init_mbuf_pools(void)
63a9643ea8Slogwang {
641646932aSjfb8856606 	const unsigned int num_mbufs_server =
651646932aSjfb8856606 		RTE_MP_RX_DESC_DEFAULT * ports->num_ports;
661646932aSjfb8856606 	const unsigned int num_mbufs_client =
671646932aSjfb8856606 		num_clients * (CLIENT_QUEUE_RINGSIZE +
681646932aSjfb8856606 			       RTE_MP_TX_DESC_DEFAULT * ports->num_ports);
691646932aSjfb8856606 	const unsigned int num_mbufs_mp_cache =
701646932aSjfb8856606 		(num_clients + 1) * MBUF_CACHE_SIZE;
711646932aSjfb8856606 	const unsigned int num_mbufs =
721646932aSjfb8856606 		num_mbufs_server + num_mbufs_client + num_mbufs_mp_cache;
73a9643ea8Slogwang 
74a9643ea8Slogwang 	/* don't pass single-producer/single-consumer flags to mbuf create as it
75a9643ea8Slogwang 	 * seems faster to use a cache instead */
76a9643ea8Slogwang 	printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
77a9643ea8Slogwang 			PKTMBUF_POOL_NAME, num_mbufs);
78a9643ea8Slogwang 	pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
79a9643ea8Slogwang 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
80a9643ea8Slogwang 
81a9643ea8Slogwang 	return pktmbuf_pool == NULL; /* 0  on success */
82a9643ea8Slogwang }
83a9643ea8Slogwang 
84a9643ea8Slogwang /**
85a9643ea8Slogwang  * Initialise an individual port:
86a9643ea8Slogwang  * - configure number of rx and tx rings
87a9643ea8Slogwang  * - set up each rx ring, to pull from the main mbuf pool
88a9643ea8Slogwang  * - set up each tx ring
89a9643ea8Slogwang  * - start the port and report its status to stdout
90a9643ea8Slogwang  */
91a9643ea8Slogwang static int
init_port(uint16_t port_num)922bfe3f2eSlogwang init_port(uint16_t port_num)
93a9643ea8Slogwang {
94a9643ea8Slogwang 	/* for port configuration all features are off by default */
95a9643ea8Slogwang 	const struct rte_eth_conf port_conf = {
96a9643ea8Slogwang 		.rxmode = {
97a9643ea8Slogwang 			.mq_mode = ETH_MQ_RX_RSS
98a9643ea8Slogwang 		}
99a9643ea8Slogwang 	};
100a9643ea8Slogwang 	const uint16_t rx_rings = 1, tx_rings = num_clients;
1012bfe3f2eSlogwang 	uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
1022bfe3f2eSlogwang 	uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
103a9643ea8Slogwang 
104a9643ea8Slogwang 	uint16_t q;
105a9643ea8Slogwang 	int retval;
106a9643ea8Slogwang 
1072bfe3f2eSlogwang 	printf("Port %u init ... ", port_num);
108a9643ea8Slogwang 	fflush(stdout);
109a9643ea8Slogwang 
110a9643ea8Slogwang 	/* Standard DPDK port initialisation - config port, then set up
111a9643ea8Slogwang 	 * rx and tx rings */
112a9643ea8Slogwang 	if ((retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings,
113a9643ea8Slogwang 		&port_conf)) != 0)
114a9643ea8Slogwang 		return retval;
115a9643ea8Slogwang 
1162bfe3f2eSlogwang 	retval = rte_eth_dev_adjust_nb_rx_tx_desc(port_num, &rx_ring_size,
1172bfe3f2eSlogwang 			&tx_ring_size);
1182bfe3f2eSlogwang 	if (retval != 0)
1192bfe3f2eSlogwang 		return retval;
1202bfe3f2eSlogwang 
121a9643ea8Slogwang 	for (q = 0; q < rx_rings; q++) {
122a9643ea8Slogwang 		retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
123a9643ea8Slogwang 				rte_eth_dev_socket_id(port_num),
124a9643ea8Slogwang 				NULL, pktmbuf_pool);
125a9643ea8Slogwang 		if (retval < 0) return retval;
126a9643ea8Slogwang 	}
127a9643ea8Slogwang 
128a9643ea8Slogwang 	for ( q = 0; q < tx_rings; q ++ ) {
129a9643ea8Slogwang 		retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
130a9643ea8Slogwang 				rte_eth_dev_socket_id(port_num),
131a9643ea8Slogwang 				NULL);
132a9643ea8Slogwang 		if (retval < 0) return retval;
133a9643ea8Slogwang 	}
134a9643ea8Slogwang 
1354418919fSjohnjiang 	retval = rte_eth_promiscuous_enable(port_num);
1364418919fSjohnjiang 	if (retval < 0)
1374418919fSjohnjiang 		return retval;
138a9643ea8Slogwang 
139a9643ea8Slogwang 	retval  = rte_eth_dev_start(port_num);
140a9643ea8Slogwang 	if (retval < 0) return retval;
141a9643ea8Slogwang 
142a9643ea8Slogwang 	printf( "done: \n");
143a9643ea8Slogwang 
144a9643ea8Slogwang 	return 0;
145a9643ea8Slogwang }
146a9643ea8Slogwang 
147a9643ea8Slogwang /**
148a9643ea8Slogwang  * Set up the DPDK rings which will be used to pass packets, via
149a9643ea8Slogwang  * pointers, between the multi-process server and client processes.
150a9643ea8Slogwang  * Each client needs one RX queue.
151a9643ea8Slogwang  */
152a9643ea8Slogwang static int
init_shm_rings(void)153a9643ea8Slogwang init_shm_rings(void)
154a9643ea8Slogwang {
155a9643ea8Slogwang 	unsigned i;
156a9643ea8Slogwang 	unsigned socket_id;
157a9643ea8Slogwang 	const char * q_name;
158a9643ea8Slogwang 	const unsigned ringsize = CLIENT_QUEUE_RINGSIZE;
159a9643ea8Slogwang 
160a9643ea8Slogwang 	clients = rte_malloc("client details",
161a9643ea8Slogwang 		sizeof(*clients) * num_clients, 0);
162a9643ea8Slogwang 	if (clients == NULL)
163a9643ea8Slogwang 		rte_exit(EXIT_FAILURE, "Cannot allocate memory for client program details\n");
164a9643ea8Slogwang 
165a9643ea8Slogwang 	for (i = 0; i < num_clients; i++) {
166a9643ea8Slogwang 		/* Create an RX queue for each client */
167a9643ea8Slogwang 		socket_id = rte_socket_id();
168a9643ea8Slogwang 		q_name = get_rx_queue_name(i);
169a9643ea8Slogwang 		clients[i].rx_q = rte_ring_create(q_name,
170a9643ea8Slogwang 				ringsize, socket_id,
171a9643ea8Slogwang 				RING_F_SP_ENQ | RING_F_SC_DEQ ); /* single prod, single cons */
172a9643ea8Slogwang 		if (clients[i].rx_q == NULL)
173a9643ea8Slogwang 			rte_exit(EXIT_FAILURE, "Cannot create rx ring queue for client %u\n", i);
174a9643ea8Slogwang 	}
175a9643ea8Slogwang 	return 0;
176a9643ea8Slogwang }
177a9643ea8Slogwang 
178a9643ea8Slogwang /* Check the link status of all ports in up to 9s, and print them finally */
179a9643ea8Slogwang static void
check_all_ports_link_status(uint16_t port_num,uint32_t port_mask)1802bfe3f2eSlogwang check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
181a9643ea8Slogwang {
182a9643ea8Slogwang #define CHECK_INTERVAL 100 /* 100ms */
183a9643ea8Slogwang #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1842bfe3f2eSlogwang 	uint16_t portid;
1852bfe3f2eSlogwang 	uint8_t count, all_ports_up, print_flag = 0;
186a9643ea8Slogwang 	struct rte_eth_link link;
1874418919fSjohnjiang 	int ret;
188*2d9fd380Sjfb8856606 	char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
189a9643ea8Slogwang 
190a9643ea8Slogwang 	printf("\nChecking link status");
191a9643ea8Slogwang 	fflush(stdout);
192a9643ea8Slogwang 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
193a9643ea8Slogwang 		all_ports_up = 1;
194a9643ea8Slogwang 		for (portid = 0; portid < port_num; portid++) {
195a9643ea8Slogwang 			if ((port_mask & (1 << ports->id[portid])) == 0)
196a9643ea8Slogwang 				continue;
197a9643ea8Slogwang 			memset(&link, 0, sizeof(link));
1984418919fSjohnjiang 			ret = rte_eth_link_get_nowait(ports->id[portid], &link);
1994418919fSjohnjiang 			if (ret < 0) {
2004418919fSjohnjiang 				all_ports_up = 0;
2014418919fSjohnjiang 				if (print_flag == 1)
2024418919fSjohnjiang 					printf("Port %u link get failed: %s\n",
2034418919fSjohnjiang 						portid, rte_strerror(-ret));
2044418919fSjohnjiang 				continue;
2054418919fSjohnjiang 			}
206a9643ea8Slogwang 			/* print link status if flag set */
207a9643ea8Slogwang 			if (print_flag == 1) {
208*2d9fd380Sjfb8856606 				rte_eth_link_to_str(link_status_text,
209*2d9fd380Sjfb8856606 					sizeof(link_status_text), &link);
210*2d9fd380Sjfb8856606 				printf("Port %d %s\n",
211*2d9fd380Sjfb8856606 				       ports->id[portid],
212*2d9fd380Sjfb8856606 				       link_status_text);
213a9643ea8Slogwang 				continue;
214a9643ea8Slogwang 			}
215a9643ea8Slogwang 			/* clear all_ports_up flag if any link down */
216a9643ea8Slogwang 			if (link.link_status == ETH_LINK_DOWN) {
217a9643ea8Slogwang 				all_ports_up = 0;
218a9643ea8Slogwang 				break;
219a9643ea8Slogwang 			}
220a9643ea8Slogwang 		}
221a9643ea8Slogwang 		/* after finally printing all link status, get out */
222a9643ea8Slogwang 		if (print_flag == 1)
223a9643ea8Slogwang 			break;
224a9643ea8Slogwang 
225a9643ea8Slogwang 		if (all_ports_up == 0) {
226a9643ea8Slogwang 			printf(".");
227a9643ea8Slogwang 			fflush(stdout);
228a9643ea8Slogwang 			rte_delay_ms(CHECK_INTERVAL);
229a9643ea8Slogwang 		}
230a9643ea8Slogwang 
231a9643ea8Slogwang 		/* set the print_flag if all ports up or timeout */
232a9643ea8Slogwang 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
233a9643ea8Slogwang 			print_flag = 1;
234a9643ea8Slogwang 			printf("done\n");
235a9643ea8Slogwang 		}
236a9643ea8Slogwang 	}
237a9643ea8Slogwang }
238a9643ea8Slogwang 
239a9643ea8Slogwang /**
240a9643ea8Slogwang  * Main init function for the multi-process server app,
241a9643ea8Slogwang  * calls subfunctions to do each stage of the initialisation.
242a9643ea8Slogwang  */
243a9643ea8Slogwang int
init(int argc,char * argv[])244a9643ea8Slogwang init(int argc, char *argv[])
245a9643ea8Slogwang {
246a9643ea8Slogwang 	int retval;
247a9643ea8Slogwang 	const struct rte_memzone *mz;
2484418919fSjohnjiang 	uint16_t i;
249a9643ea8Slogwang 
250a9643ea8Slogwang 	/* init EAL, parsing EAL args */
251a9643ea8Slogwang 	retval = rte_eal_init(argc, argv);
252a9643ea8Slogwang 	if (retval < 0)
253a9643ea8Slogwang 		return -1;
254a9643ea8Slogwang 	argc -= retval;
255a9643ea8Slogwang 	argv += retval;
256a9643ea8Slogwang 
257a9643ea8Slogwang 	/* set up array for port data */
258a9643ea8Slogwang 	mz = rte_memzone_reserve(MZ_PORT_INFO, sizeof(*ports),
259a9643ea8Slogwang 				rte_socket_id(), NO_FLAGS);
260a9643ea8Slogwang 	if (mz == NULL)
261a9643ea8Slogwang 		rte_exit(EXIT_FAILURE, "Cannot reserve memory zone for port information\n");
262a9643ea8Slogwang 	memset(mz->addr, 0, sizeof(*ports));
263a9643ea8Slogwang 	ports = mz->addr;
264a9643ea8Slogwang 
265a9643ea8Slogwang 	/* parse additional, application arguments */
2664418919fSjohnjiang 	retval = parse_app_args(argc, argv);
267a9643ea8Slogwang 	if (retval != 0)
268a9643ea8Slogwang 		return -1;
269a9643ea8Slogwang 
270a9643ea8Slogwang 	/* initialise mbuf pools */
271a9643ea8Slogwang 	retval = init_mbuf_pools();
272a9643ea8Slogwang 	if (retval != 0)
273a9643ea8Slogwang 		rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
274a9643ea8Slogwang 
275a9643ea8Slogwang 	/* now initialise the ports we will use */
276a9643ea8Slogwang 	for (i = 0; i < ports->num_ports; i++) {
277a9643ea8Slogwang 		retval = init_port(ports->id[i]);
278a9643ea8Slogwang 		if (retval != 0)
279a9643ea8Slogwang 			rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
280a9643ea8Slogwang 					(unsigned)i);
281a9643ea8Slogwang 	}
282a9643ea8Slogwang 
283a9643ea8Slogwang 	check_all_ports_link_status(ports->num_ports, (~0x0));
284a9643ea8Slogwang 
285a9643ea8Slogwang 	/* initialise the client queues/rings for inter-eu comms */
286a9643ea8Slogwang 	init_shm_rings();
287a9643ea8Slogwang 
288a9643ea8Slogwang 	return 0;
289a9643ea8Slogwang }
290