xref: /dpdk/examples/vm_power_manager/main.c (revision 3998e2a07220844d3f3c17f76a781ced3efe0de0)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdint.h>
8 #include <sys/epoll.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <signal.h>
13 #include <errno.h>
14 
15 #include <sys/queue.h>
16 
17 #include <rte_common.h>
18 #include <rte_eal.h>
19 #include <rte_launch.h>
20 #include <rte_log.h>
21 #include <rte_per_lcore.h>
22 #include <rte_lcore.h>
23 #include <rte_ethdev.h>
24 #include <getopt.h>
25 #include <rte_cycles.h>
26 #include <rte_debug.h>
27 
28 #include "channel_manager.h"
29 #include "channel_monitor.h"
30 #include "power_manager.h"
31 #include "vm_power_cli.h"
32 #include <rte_pmd_ixgbe.h>
33 #include <rte_pmd_i40e.h>
34 #include <rte_pmd_bnxt.h>
35 
36 #define RX_RING_SIZE 512
37 #define TX_RING_SIZE 512
38 
39 #define NUM_MBUFS 8191
40 #define MBUF_CACHE_SIZE 250
41 #define BURST_SIZE 32
42 
43 static uint32_t enabled_port_mask;
44 static volatile bool force_quit;
45 
46 /****************/
47 static const struct rte_eth_conf port_conf_default = {
48 	.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
49 };
50 
51 static inline int
52 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
53 {
54 	struct rte_eth_conf port_conf = port_conf_default;
55 	const uint16_t rx_rings = 1, tx_rings = 1;
56 	int retval;
57 	uint16_t q;
58 
59 	if (port >= rte_eth_dev_count())
60 		return -1;
61 
62 	/* Configure the Ethernet device. */
63 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
64 	if (retval != 0)
65 		return retval;
66 
67 	/* Allocate and set up 1 RX queue per Ethernet port. */
68 	for (q = 0; q < rx_rings; q++) {
69 		retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
70 				rte_eth_dev_socket_id(port), NULL, mbuf_pool);
71 		if (retval < 0)
72 			return retval;
73 	}
74 
75 	/* Allocate and set up 1 TX queue per Ethernet port. */
76 	for (q = 0; q < tx_rings; q++) {
77 		retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
78 				rte_eth_dev_socket_id(port), NULL);
79 		if (retval < 0)
80 			return retval;
81 	}
82 
83 	/* Start the Ethernet port. */
84 	retval = rte_eth_dev_start(port);
85 	if (retval < 0)
86 		return retval;
87 
88 	/* Display the port MAC address. */
89 	struct ether_addr addr;
90 	rte_eth_macaddr_get(port, &addr);
91 	printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
92 			   " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
93 			(unsigned int)port,
94 			addr.addr_bytes[0], addr.addr_bytes[1],
95 			addr.addr_bytes[2], addr.addr_bytes[3],
96 			addr.addr_bytes[4], addr.addr_bytes[5]);
97 
98 	/* Enable RX in promiscuous mode for the Ethernet device. */
99 	rte_eth_promiscuous_enable(port);
100 
101 
102 	return 0;
103 }
104 
105 static int
106 parse_portmask(const char *portmask)
107 {
108 	char *end = NULL;
109 	unsigned long pm;
110 
111 	/* parse hexadecimal string */
112 	pm = strtoul(portmask, &end, 16);
113 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
114 		return -1;
115 
116 	if (pm == 0)
117 		return -1;
118 
119 	return pm;
120 }
121 /* Parse the argument given in the command line of the application */
122 static int
123 parse_args(int argc, char **argv)
124 {
125 	int opt, ret;
126 	char **argvopt;
127 	int option_index;
128 	char *prgname = argv[0];
129 	static struct option lgopts[] = {
130 		{ "mac-updating", no_argument, 0, 1},
131 		{ "no-mac-updating", no_argument, 0, 0},
132 		{NULL, 0, 0, 0}
133 	};
134 	argvopt = argv;
135 
136 	while ((opt = getopt_long(argc, argvopt, "p:q:T:",
137 				  lgopts, &option_index)) != EOF) {
138 
139 		switch (opt) {
140 		/* portmask */
141 		case 'p':
142 			enabled_port_mask = parse_portmask(optarg);
143 			if (enabled_port_mask == 0) {
144 				printf("invalid portmask\n");
145 				return -1;
146 			}
147 			break;
148 		/* long options */
149 		case 0:
150 			break;
151 
152 		default:
153 			return -1;
154 		}
155 	}
156 
157 	if (optind >= 0)
158 		argv[optind-1] = prgname;
159 
160 	ret = optind-1;
161 	optind = 0; /* reset getopt lib */
162 	return ret;
163 }
164 
165 static void
166 check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
167 {
168 #define CHECK_INTERVAL 100 /* 100ms */
169 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
170 	uint16_t portid, count, all_ports_up, print_flag = 0;
171 	struct rte_eth_link link;
172 
173 	printf("\nChecking link status");
174 	fflush(stdout);
175 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
176 		if (force_quit)
177 			return;
178 		all_ports_up = 1;
179 		for (portid = 0; portid < port_num; portid++) {
180 			if (force_quit)
181 				return;
182 			if ((port_mask & (1 << portid)) == 0)
183 				continue;
184 			memset(&link, 0, sizeof(link));
185 			rte_eth_link_get_nowait(portid, &link);
186 			/* print link status if flag set */
187 			if (print_flag == 1) {
188 				if (link.link_status)
189 					printf("Port %d Link Up - speed %u "
190 						"Mbps - %s\n", (uint16_t)portid,
191 						(unsigned int)link.link_speed,
192 				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
193 					("full-duplex") : ("half-duplex\n"));
194 				else
195 					printf("Port %d Link Down\n",
196 						(uint16_t)portid);
197 				continue;
198 			}
199 		       /* clear all_ports_up flag if any link down */
200 			if (link.link_status == ETH_LINK_DOWN) {
201 				all_ports_up = 0;
202 				break;
203 			}
204 		}
205 		/* after finally printing all link status, get out */
206 		if (print_flag == 1)
207 			break;
208 
209 		if (all_ports_up == 0) {
210 			printf(".");
211 			fflush(stdout);
212 			rte_delay_ms(CHECK_INTERVAL);
213 		}
214 
215 		/* set the print_flag if all ports up or timeout */
216 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
217 			print_flag = 1;
218 			printf("done\n");
219 		}
220 	}
221 }
222 static int
223 run_monitor(__attribute__((unused)) void *arg)
224 {
225 	if (channel_monitor_init() < 0) {
226 		printf("Unable to initialize channel monitor\n");
227 		return -1;
228 	}
229 	run_channel_monitor();
230 	return 0;
231 }
232 
233 static void
234 sig_handler(int signo)
235 {
236 	printf("Received signal %d, exiting...\n", signo);
237 	channel_monitor_exit();
238 	channel_manager_exit();
239 	power_manager_exit();
240 
241 }
242 
243 int
244 main(int argc, char **argv)
245 {
246 	int ret;
247 	unsigned lcore_id;
248 	unsigned int nb_ports;
249 	struct rte_mempool *mbuf_pool;
250 	uint16_t portid;
251 
252 
253 	ret = rte_eal_init(argc, argv);
254 	if (ret < 0)
255 		rte_panic("Cannot init EAL\n");
256 
257 	signal(SIGINT, sig_handler);
258 	signal(SIGTERM, sig_handler);
259 
260 	argc -= ret;
261 	argv += ret;
262 
263 	/* parse application arguments (after the EAL ones) */
264 	ret = parse_args(argc, argv);
265 	if (ret < 0)
266 		rte_exit(EXIT_FAILURE, "Invalid arguments\n");
267 
268 	nb_ports = rte_eth_dev_count();
269 
270 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
271 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
272 
273 	if (mbuf_pool == NULL)
274 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
275 
276 	/* Initialize ports. */
277 	for (portid = 0; portid < nb_ports; portid++) {
278 		struct ether_addr eth;
279 		int w, j;
280 		int ret = -ENOTSUP;
281 
282 		if ((enabled_port_mask & (1 << portid)) == 0)
283 			continue;
284 
285 		eth.addr_bytes[0] = 0xe0;
286 		eth.addr_bytes[1] = 0xe0;
287 		eth.addr_bytes[2] = 0xe0;
288 		eth.addr_bytes[3] = 0xe0;
289 		eth.addr_bytes[4] = portid + 0xf0;
290 
291 		if (port_init(portid, mbuf_pool) != 0)
292 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
293 					portid);
294 
295 		for (w = 0; w < MAX_VFS; w++) {
296 			eth.addr_bytes[5] = w + 0xf0;
297 
298 			if (ret == -ENOTSUP)
299 				ret = rte_pmd_ixgbe_set_vf_mac_addr(portid,
300 						w, &eth);
301 			if (ret == -ENOTSUP)
302 				ret = rte_pmd_i40e_set_vf_mac_addr(portid,
303 						w, &eth);
304 			if (ret == -ENOTSUP)
305 				ret = rte_pmd_bnxt_set_vf_mac_addr(portid,
306 						w, &eth);
307 
308 			switch (ret) {
309 			case 0:
310 				printf("Port %d VF %d MAC: ",
311 						portid, w);
312 				for (j = 0; j < 6; j++) {
313 					printf("%02x", eth.addr_bytes[j]);
314 					if (j < 5)
315 						printf(":");
316 				}
317 				printf("\n");
318 				break;
319 			}
320 		}
321 	}
322 
323 	lcore_id = rte_get_next_lcore(-1, 1, 0);
324 	if (lcore_id == RTE_MAX_LCORE) {
325 		RTE_LOG(ERR, EAL, "A minimum of two cores are required to run "
326 				"application\n");
327 		return 0;
328 	}
329 
330 	check_all_ports_link_status(nb_ports, enabled_port_mask);
331 	rte_eal_remote_launch(run_monitor, NULL, lcore_id);
332 
333 	if (power_manager_init() < 0) {
334 		printf("Unable to initialize power manager\n");
335 		return -1;
336 	}
337 	if (channel_manager_init(CHANNEL_MGR_DEFAULT_HV_PATH) < 0) {
338 		printf("Unable to initialize channel manager\n");
339 		return -1;
340 	}
341 	run_cli(NULL);
342 
343 	rte_eal_mp_wait_lcore();
344 	return 0;
345 }
346