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