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