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 #include <rte_pmd_ixgbe.h> 35 #include <rte_pmd_i40e.h> 36 #include <rte_pmd_bnxt.h> 37 38 #define RX_RING_SIZE 1024 39 #define TX_RING_SIZE 1024 40 41 #define NUM_MBUFS 8191 42 #define MBUF_CACHE_SIZE 250 43 #define BURST_SIZE 32 44 45 static uint32_t enabled_port_mask; 46 static volatile bool force_quit; 47 48 /****************/ 49 static const struct rte_eth_conf port_conf_default = { 50 .rxmode = { 51 .max_rx_pkt_len = ETHER_MAX_LEN, 52 }, 53 }; 54 55 static inline int 56 port_init(uint16_t port, struct rte_mempool *mbuf_pool) 57 { 58 struct rte_eth_conf port_conf = port_conf_default; 59 const uint16_t rx_rings = 1, tx_rings = 1; 60 int retval; 61 uint16_t q; 62 struct rte_eth_dev_info dev_info; 63 struct rte_eth_txconf txq_conf; 64 65 if (!rte_eth_dev_is_valid_port(port)) 66 return -1; 67 68 rte_eth_dev_info_get(port, &dev_info); 69 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 70 port_conf.txmode.offloads |= 71 DEV_TX_OFFLOAD_MBUF_FAST_FREE; 72 73 /* Configure the Ethernet device. */ 74 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 75 if (retval != 0) 76 return retval; 77 78 /* Allocate and set up 1 RX queue per Ethernet port. */ 79 for (q = 0; q < rx_rings; q++) { 80 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, 81 rte_eth_dev_socket_id(port), NULL, mbuf_pool); 82 if (retval < 0) 83 return retval; 84 } 85 86 txq_conf = dev_info.default_txconf; 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, cnt, i; 139 char **argvopt; 140 uint16_t *oob_enable; 141 int option_index; 142 char *prgname = argv[0]; 143 struct core_info *ci; 144 float branch_ratio; 145 static struct option lgopts[] = { 146 { "mac-updating", no_argument, 0, 1}, 147 { "no-mac-updating", no_argument, 0, 0}, 148 { "core-list", optional_argument, 0, 'l'}, 149 { "port-list", optional_argument, 0, 'p'}, 150 { "branch-ratio", optional_argument, 0, 'b'}, 151 {NULL, 0, 0, 0} 152 }; 153 argvopt = argv; 154 ci = get_core_info(); 155 156 while ((opt = getopt_long(argc, argvopt, "l:p:q:T:b:", 157 lgopts, &option_index)) != EOF) { 158 159 switch (opt) { 160 /* portmask */ 161 case 'p': 162 enabled_port_mask = parse_portmask(optarg); 163 if (enabled_port_mask == 0) { 164 printf("invalid portmask\n"); 165 return -1; 166 } 167 break; 168 case 'l': 169 oob_enable = malloc(ci->core_count * sizeof(uint16_t)); 170 if (oob_enable == NULL) { 171 printf("Error - Unable to allocate memory\n"); 172 return -1; 173 } 174 cnt = parse_set(optarg, oob_enable, ci->core_count); 175 if (cnt < 0) { 176 printf("Invalid core-list - [%s]\n", 177 optarg); 178 free(oob_enable); 179 break; 180 } 181 for (i = 0; i < ci->core_count; i++) { 182 if (oob_enable[i]) { 183 printf("***Using core %d\n", i); 184 ci->cd[i].oob_enabled = 1; 185 ci->cd[i].global_enabled_cpus = 1; 186 } 187 } 188 free(oob_enable); 189 break; 190 case 'b': 191 branch_ratio = 0.0; 192 if (strlen(optarg)) 193 branch_ratio = atof(optarg); 194 if (branch_ratio <= 0.0) { 195 printf("invalid branch ratio specified\n"); 196 return -1; 197 } 198 ci->branch_ratio_threshold = branch_ratio; 199 printf("***Setting branch ratio to %f\n", 200 branch_ratio); 201 break; 202 /* long options */ 203 case 0: 204 break; 205 206 default: 207 return -1; 208 } 209 } 210 211 if (optind >= 0) 212 argv[optind-1] = prgname; 213 214 ret = optind-1; 215 optind = 0; /* reset getopt lib */ 216 return ret; 217 } 218 219 static void 220 check_all_ports_link_status(uint32_t port_mask) 221 { 222 #define CHECK_INTERVAL 100 /* 100ms */ 223 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 224 uint16_t portid, count, all_ports_up, print_flag = 0; 225 struct rte_eth_link link; 226 227 printf("\nChecking link status"); 228 fflush(stdout); 229 for (count = 0; count <= MAX_CHECK_TIME; count++) { 230 if (force_quit) 231 return; 232 all_ports_up = 1; 233 RTE_ETH_FOREACH_DEV(portid) { 234 if (force_quit) 235 return; 236 if ((port_mask & (1 << portid)) == 0) 237 continue; 238 memset(&link, 0, sizeof(link)); 239 rte_eth_link_get_nowait(portid, &link); 240 /* print link status if flag set */ 241 if (print_flag == 1) { 242 if (link.link_status) 243 printf("Port %d Link Up - speed %u " 244 "Mbps - %s\n", (uint16_t)portid, 245 (unsigned int)link.link_speed, 246 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 247 ("full-duplex") : ("half-duplex\n")); 248 else 249 printf("Port %d Link Down\n", 250 (uint16_t)portid); 251 continue; 252 } 253 /* clear all_ports_up flag if any link down */ 254 if (link.link_status == ETH_LINK_DOWN) { 255 all_ports_up = 0; 256 break; 257 } 258 } 259 /* after finally printing all link status, get out */ 260 if (print_flag == 1) 261 break; 262 263 if (all_ports_up == 0) { 264 printf("."); 265 fflush(stdout); 266 rte_delay_ms(CHECK_INTERVAL); 267 } 268 269 /* set the print_flag if all ports up or timeout */ 270 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 271 print_flag = 1; 272 printf("done\n"); 273 } 274 } 275 } 276 static int 277 run_monitor(__attribute__((unused)) void *arg) 278 { 279 if (channel_monitor_init() < 0) { 280 printf("Unable to initialize channel monitor\n"); 281 return -1; 282 } 283 run_channel_monitor(); 284 return 0; 285 } 286 287 static int 288 run_core_monitor(__attribute__((unused)) void *arg) 289 { 290 if (branch_monitor_init() < 0) { 291 printf("Unable to initialize core monitor\n"); 292 return -1; 293 } 294 run_branch_monitor(); 295 return 0; 296 } 297 298 static void 299 sig_handler(int signo) 300 { 301 printf("Received signal %d, exiting...\n", signo); 302 channel_monitor_exit(); 303 channel_manager_exit(); 304 power_manager_exit(); 305 306 } 307 308 int 309 main(int argc, char **argv) 310 { 311 int ret; 312 unsigned lcore_id; 313 unsigned int nb_ports; 314 struct rte_mempool *mbuf_pool; 315 uint16_t portid; 316 struct core_info *ci; 317 318 319 ret = core_info_init(); 320 if (ret < 0) 321 rte_panic("Cannot allocate core info\n"); 322 323 ci = get_core_info(); 324 325 ret = rte_eal_init(argc, argv); 326 if (ret < 0) 327 rte_panic("Cannot init EAL\n"); 328 329 signal(SIGINT, sig_handler); 330 signal(SIGTERM, sig_handler); 331 332 argc -= ret; 333 argv += ret; 334 335 /* parse application arguments (after the EAL ones) */ 336 ret = parse_args(argc, argv); 337 if (ret < 0) 338 rte_exit(EXIT_FAILURE, "Invalid arguments\n"); 339 340 nb_ports = rte_eth_dev_count_avail(); 341 342 if (nb_ports > 0) { 343 mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 344 NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0, 345 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 346 347 if (mbuf_pool == NULL) 348 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 349 350 /* Initialize ports. */ 351 RTE_ETH_FOREACH_DEV(portid) { 352 struct ether_addr eth; 353 int w, j; 354 int ret; 355 356 if ((enabled_port_mask & (1 << portid)) == 0) 357 continue; 358 359 eth.addr_bytes[0] = 0xe0; 360 eth.addr_bytes[1] = 0xe0; 361 eth.addr_bytes[2] = 0xe0; 362 eth.addr_bytes[3] = 0xe0; 363 eth.addr_bytes[4] = portid + 0xf0; 364 365 if (port_init(portid, mbuf_pool) != 0) 366 rte_exit(EXIT_FAILURE, 367 "Cannot init port %"PRIu8 "\n", 368 portid); 369 370 for (w = 0; w < MAX_VFS; w++) { 371 eth.addr_bytes[5] = w + 0xf0; 372 373 ret = rte_pmd_ixgbe_set_vf_mac_addr(portid, 374 w, ð); 375 if (ret == -ENOTSUP) 376 ret = rte_pmd_i40e_set_vf_mac_addr( 377 portid, w, ð); 378 if (ret == -ENOTSUP) 379 ret = rte_pmd_bnxt_set_vf_mac_addr( 380 portid, w, ð); 381 382 switch (ret) { 383 case 0: 384 printf("Port %d VF %d MAC: ", 385 portid, w); 386 for (j = 0; j < 5; j++) { 387 printf("%02x:", 388 eth.addr_bytes[j]); 389 } 390 printf("%02x\n", eth.addr_bytes[5]); 391 break; 392 } 393 printf("\n"); 394 break; 395 } 396 } 397 } 398 399 check_all_ports_link_status(enabled_port_mask); 400 401 lcore_id = rte_get_next_lcore(-1, 1, 0); 402 if (lcore_id == RTE_MAX_LCORE) { 403 RTE_LOG(ERR, EAL, "A minimum of three cores are required to run " 404 "application\n"); 405 return 0; 406 } 407 printf("Running channel monitor on lcore id %d\n", lcore_id); 408 rte_eal_remote_launch(run_monitor, NULL, lcore_id); 409 410 lcore_id = rte_get_next_lcore(lcore_id, 1, 0); 411 if (lcore_id == RTE_MAX_LCORE) { 412 RTE_LOG(ERR, EAL, "A minimum of three cores are required to run " 413 "application\n"); 414 return 0; 415 } 416 if (power_manager_init() < 0) { 417 printf("Unable to initialize power manager\n"); 418 return -1; 419 } 420 if (channel_manager_init(CHANNEL_MGR_DEFAULT_HV_PATH) < 0) { 421 printf("Unable to initialize channel manager\n"); 422 return -1; 423 } 424 425 add_host_channel(); 426 427 printf("Running core monitor on lcore id %d\n", lcore_id); 428 rte_eal_remote_launch(run_core_monitor, NULL, lcore_id); 429 430 run_cli(NULL); 431 432 branch_monitor_exit(); 433 434 rte_eal_mp_wait_lcore(); 435 436 free(ci->cd); 437 438 return 0; 439 } 440