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