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, ð); 314 if (ret == -ENOTSUP) 315 ret = rte_pmd_i40e_set_vf_mac_addr(portid, 316 w, ð); 317 if (ret == -ENOTSUP) 318 ret = rte_pmd_bnxt_set_vf_mac_addr(portid, 319 w, ð); 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