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 "oob_monitor.h" 33 #include "parse.h" 34 #ifdef RTE_NET_IXGBE 35 #include <rte_pmd_ixgbe.h> 36 #endif 37 #ifdef RTE_NET_I40E 38 #include <rte_pmd_i40e.h> 39 #endif 40 #ifdef RTE_NET_BNXT 41 #include <rte_pmd_bnxt.h> 42 #endif 43 44 #define RX_RING_SIZE 1024 45 #define TX_RING_SIZE 1024 46 47 #define NUM_MBUFS 8191 48 #define MBUF_CACHE_SIZE 250 49 #define BURST_SIZE 32 50 51 static uint32_t enabled_port_mask; 52 static volatile bool force_quit; 53 54 static inline int 55 port_init(uint16_t port, struct rte_mempool *mbuf_pool) 56 { 57 struct rte_eth_conf port_conf; 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 (!rte_eth_dev_is_valid_port(port)) 65 return -1; 66 67 memset(&port_conf, 0, sizeof(struct rte_eth_conf)); 68 69 retval = rte_eth_dev_info_get(port, &dev_info); 70 if (retval != 0) { 71 printf("Error during getting device (port %u) info: %s\n", 72 port, strerror(-retval)); 73 return retval; 74 } 75 76 if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) 77 port_conf.txmode.offloads |= 78 RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; 79 80 /* Configure the Ethernet device. */ 81 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 82 if (retval != 0) 83 return retval; 84 85 /* Allocate and set up 1 RX queue per Ethernet port. */ 86 for (q = 0; q < rx_rings; q++) { 87 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, 88 rte_eth_dev_socket_id(port), NULL, mbuf_pool); 89 if (retval < 0) 90 return retval; 91 } 92 93 txq_conf = dev_info.default_txconf; 94 txq_conf.offloads = port_conf.txmode.offloads; 95 /* Allocate and set up 1 TX queue per Ethernet port. */ 96 for (q = 0; q < tx_rings; q++) { 97 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, 98 rte_eth_dev_socket_id(port), &txq_conf); 99 if (retval < 0) 100 return retval; 101 } 102 103 /* Start the Ethernet port. */ 104 retval = rte_eth_dev_start(port); 105 if (retval < 0) 106 return retval; 107 108 /* Display the port MAC address. */ 109 struct rte_ether_addr addr; 110 retval = rte_eth_macaddr_get(port, &addr); 111 if (retval != 0) { 112 printf("Failed to get device (port %u) MAC address: %s\n", 113 port, rte_strerror(-retval)); 114 return retval; 115 } 116 117 printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 118 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", 119 (unsigned int)port, RTE_ETHER_ADDR_BYTES(&addr)); 120 121 /* Enable RX in promiscuous mode for the Ethernet device. */ 122 retval = rte_eth_promiscuous_enable(port); 123 if (retval != 0) 124 return retval; 125 126 127 return 0; 128 } 129 130 static int 131 parse_portmask(const char *portmask) 132 { 133 char *end = NULL; 134 unsigned long pm; 135 136 /* parse hexadecimal string */ 137 pm = strtoul(portmask, &end, 16); 138 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 139 return 0; 140 141 return pm; 142 } 143 /* Parse the argument given in the command line of the application */ 144 static int 145 parse_args(int argc, char **argv) 146 { 147 int opt, ret, cnt, i; 148 char **argvopt; 149 uint16_t *oob_enable; 150 int option_index; 151 char *prgname = argv[0]; 152 struct core_info *ci; 153 float branch_ratio; 154 static struct option lgopts[] = { 155 { "mac-updating", no_argument, 0, 1}, 156 { "no-mac-updating", no_argument, 0, 0}, 157 { "core-branch-ratio", optional_argument, 0, 'b'}, 158 { "port-list", optional_argument, 0, 'p'}, 159 {NULL, 0, 0, 0} 160 }; 161 argvopt = argv; 162 ci = get_core_info(); 163 164 while ((opt = getopt_long(argc, argvopt, "p:q:T:b:", 165 lgopts, &option_index)) != EOF) { 166 167 switch (opt) { 168 /* portmask */ 169 case 'p': 170 enabled_port_mask = parse_portmask(optarg); 171 if (enabled_port_mask == 0) { 172 printf("invalid portmask\n"); 173 return -1; 174 } 175 break; 176 case 'b': 177 branch_ratio = BRANCH_RATIO_THRESHOLD; 178 oob_enable = malloc(ci->core_count * sizeof(uint16_t)); 179 if (oob_enable == NULL) { 180 printf("Error - Unable to allocate memory\n"); 181 return -1; 182 } 183 cnt = parse_set(optarg, oob_enable, ci->core_count); 184 if (cnt < 0) { 185 printf("Invalid core-list section in " 186 "core-branch-ratio matrix - [%s]\n", 187 optarg); 188 free(oob_enable); 189 break; 190 } 191 cnt = parse_branch_ratio(optarg, &branch_ratio); 192 if (cnt < 0) { 193 printf("Invalid branch-ratio section in " 194 "core-branch-ratio matrix - [%s]\n", 195 optarg); 196 free(oob_enable); 197 break; 198 } 199 if (branch_ratio <= 0.0 || branch_ratio > 100.0) { 200 printf("invalid branch ratio specified\n"); 201 free(oob_enable); 202 return -1; 203 } 204 for (i = 0; i < ci->core_count; i++) { 205 if (oob_enable[i]) { 206 printf("***Using core %d " 207 "with branch ratio %f\n", 208 i, branch_ratio); 209 ci->cd[i].oob_enabled = 1; 210 ci->cd[i].global_enabled_cpus = 1; 211 ci->cd[i].branch_ratio_threshold = 212 branch_ratio; 213 } 214 } 215 free(oob_enable); 216 break; 217 /* long options */ 218 case 0: 219 break; 220 221 default: 222 return -1; 223 } 224 } 225 226 if (optind >= 0) 227 argv[optind-1] = prgname; 228 229 ret = optind-1; 230 optind = 0; /* reset getopt lib */ 231 return ret; 232 } 233 234 static void 235 check_all_ports_link_status(uint32_t port_mask) 236 { 237 #define CHECK_INTERVAL 100 /* 100ms */ 238 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 239 uint16_t portid, count, all_ports_up, print_flag = 0; 240 struct rte_eth_link link; 241 int ret; 242 char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; 243 244 printf("\nChecking link status"); 245 fflush(stdout); 246 for (count = 0; count <= MAX_CHECK_TIME; count++) { 247 if (force_quit) 248 return; 249 all_ports_up = 1; 250 RTE_ETH_FOREACH_DEV(portid) { 251 if (force_quit) 252 return; 253 if ((port_mask & (1 << portid)) == 0) 254 continue; 255 memset(&link, 0, sizeof(link)); 256 ret = rte_eth_link_get_nowait(portid, &link); 257 if (ret < 0) { 258 all_ports_up = 0; 259 if (print_flag == 1) 260 printf("Port %u link get failed: %s\n", 261 portid, rte_strerror(-ret)); 262 continue; 263 } 264 /* print link status if flag set */ 265 if (print_flag == 1) { 266 rte_eth_link_to_str(link_status_text, 267 sizeof(link_status_text), &link); 268 printf("Port %d %s\n", portid, 269 link_status_text); 270 continue; 271 } 272 /* clear all_ports_up flag if any link down */ 273 if (link.link_status == RTE_ETH_LINK_DOWN) { 274 all_ports_up = 0; 275 break; 276 } 277 } 278 /* after finally printing all link status, get out */ 279 if (print_flag == 1) 280 break; 281 282 if (all_ports_up == 0) { 283 printf("."); 284 fflush(stdout); 285 rte_delay_ms(CHECK_INTERVAL); 286 } 287 288 /* set the print_flag if all ports up or timeout */ 289 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 290 print_flag = 1; 291 printf("done\n"); 292 } 293 } 294 } 295 static int 296 run_monitor(__rte_unused void *arg) 297 { 298 if (channel_monitor_init() < 0) { 299 printf("Unable to initialize channel monitor\n"); 300 return -1; 301 } 302 run_channel_monitor(); 303 return 0; 304 } 305 306 static int 307 run_core_monitor(__rte_unused void *arg) 308 { 309 if (branch_monitor_init() < 0) { 310 printf("Unable to initialize core monitor\n"); 311 return -1; 312 } 313 run_branch_monitor(); 314 return 0; 315 } 316 317 static void 318 sig_handler(int signo) 319 { 320 printf("Received signal %d, exiting...\n", signo); 321 channel_monitor_exit(); 322 channel_manager_exit(); 323 power_manager_exit(); 324 325 } 326 327 int 328 main(int argc, char **argv) 329 { 330 int ret; 331 unsigned lcore_id; 332 unsigned int nb_ports; 333 struct rte_mempool *mbuf_pool; 334 uint16_t portid; 335 struct core_info *ci; 336 337 338 ret = core_info_init(); 339 if (ret < 0) 340 rte_panic("Cannot allocate core info\n"); 341 342 ci = get_core_info(); 343 344 ret = rte_eal_init(argc, argv); 345 if (ret < 0) 346 rte_panic("Cannot init EAL\n"); 347 348 signal(SIGINT, sig_handler); 349 signal(SIGTERM, sig_handler); 350 351 argc -= ret; 352 argv += ret; 353 354 /* parse application arguments (after the EAL ones) */ 355 ret = parse_args(argc, argv); 356 if (ret < 0) 357 rte_exit(EXIT_FAILURE, "Invalid arguments\n"); 358 359 nb_ports = rte_eth_dev_count_avail(); 360 361 if (nb_ports > 0) { 362 mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 363 NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0, 364 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 365 366 if (mbuf_pool == NULL) 367 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 368 369 /* Initialize ports. */ 370 RTE_ETH_FOREACH_DEV(portid) { 371 struct rte_ether_addr eth; 372 int w, j; 373 int ret; 374 375 if ((enabled_port_mask & (1 << portid)) == 0) 376 continue; 377 378 eth.addr_bytes[0] = 0xe0; 379 eth.addr_bytes[1] = 0xe0; 380 eth.addr_bytes[2] = 0xe0; 381 eth.addr_bytes[3] = 0xe0; 382 eth.addr_bytes[4] = portid + 0xf0; 383 384 if (port_init(portid, mbuf_pool) != 0) 385 rte_exit(EXIT_FAILURE, 386 "Cannot init port %"PRIu8 "\n", 387 portid); 388 389 for (w = 0; w < RTE_POWER_MAX_VFS; w++) { 390 eth.addr_bytes[5] = w + 0xf0; 391 392 ret = -ENOTSUP; 393 #ifdef RTE_NET_IXGBE 394 ret = rte_pmd_ixgbe_set_vf_mac_addr(portid, 395 w, ð); 396 #endif 397 #ifdef RTE_NET_I40E 398 if (ret == -ENOTSUP) 399 ret = rte_pmd_i40e_set_vf_mac_addr( 400 portid, w, ð); 401 #endif 402 #ifdef RTE_NET_BNXT 403 if (ret == -ENOTSUP) 404 ret = rte_pmd_bnxt_set_vf_mac_addr( 405 portid, w, ð); 406 #endif 407 408 switch (ret) { 409 case 0: 410 printf("Port %d VF %d MAC: ", 411 portid, w); 412 for (j = 0; j < 5; j++) { 413 printf("%02x:", 414 eth.addr_bytes[j]); 415 } 416 printf("%02x\n", eth.addr_bytes[5]); 417 break; 418 } 419 printf("\n"); 420 } 421 } 422 } 423 424 check_all_ports_link_status(enabled_port_mask); 425 426 lcore_id = rte_get_next_lcore(-1, 1, 0); 427 if (lcore_id == RTE_MAX_LCORE) { 428 RTE_LOG(ERR, EAL, "A minimum of three cores are required to run " 429 "application\n"); 430 return 0; 431 } 432 printf("Running channel monitor on lcore id %d\n", lcore_id); 433 rte_eal_remote_launch(run_monitor, NULL, lcore_id); 434 435 lcore_id = rte_get_next_lcore(lcore_id, 1, 0); 436 if (lcore_id == RTE_MAX_LCORE) { 437 RTE_LOG(ERR, EAL, "A minimum of three cores are required to run " 438 "application\n"); 439 return 0; 440 } 441 if (power_manager_init() < 0) { 442 printf("Unable to initialize power manager\n"); 443 return -1; 444 } 445 if (channel_manager_init(CHANNEL_MGR_DEFAULT_HV_PATH) < 0) { 446 printf("Unable to initialize channel manager\n"); 447 return -1; 448 } 449 450 add_host_channels(); 451 452 printf("Running core monitor on lcore id %d\n", lcore_id); 453 rte_eal_remote_launch(run_core_monitor, NULL, lcore_id); 454 455 run_cli(NULL); 456 457 branch_monitor_exit(); 458 459 rte_eal_mp_wait_lcore(); 460 461 free(ci->cd); 462 463 /* clean up the EAL */ 464 rte_eal_cleanup(); 465 466 return 0; 467 } 468