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