1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#if HAVE_CONFIG_H 35219820Sjeff# include <config.h> 36219820Sjeff#endif /* HAVE_CONFIG_H */ 37219820Sjeff 38219820Sjeff#define _GNU_SOURCE /* for getline */ 39219820Sjeff#include <stdio.h> 40219820Sjeff#include <stdlib.h> 41219820Sjeff#include <sys/poll.h> 42219820Sjeff#include <sys/types.h> 43219820Sjeff#include <sys/socket.h> 44219820Sjeff#include <netdb.h> 45219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 46219820Sjeff#include <arpa/inet.h> 47219820Sjeff#endif 48219820Sjeff#include <unistd.h> 49219820Sjeff#include <errno.h> 50219820Sjeff#include <ctype.h> 51219820Sjeff#include <sys/time.h> 52219820Sjeff#include <opensm/osm_console.h> 53219820Sjeff#include <complib/cl_passivelock.h> 54219820Sjeff#include <opensm/osm_perfmgr.h> 55219820Sjeff#include <opensm/osm_subnet.h> 56219820Sjeff 57219820Sjeffstruct command { 58219820Sjeff char *name; 59219820Sjeff void (*help_function) (FILE * out, int detail); 60219820Sjeff void (*parse_function) (char **p_last, osm_opensm_t * p_osm, 61219820Sjeff FILE * out); 62219820Sjeff}; 63219820Sjeff 64219820Sjeffstatic struct { 65219820Sjeff int on; 66219820Sjeff int delay_s; 67219820Sjeff time_t previous; 68219820Sjeff void (*loop_function) (osm_opensm_t * p_osm, FILE * out); 69219820Sjeff} loop_command = { 70254123Sjeff .on = 0, 71254123Sjeff .delay_s = 2, 72254123Sjeff .loop_function = NULL, 73254123Sjeff}; 74219820Sjeff 75219820Sjeffstatic const struct command console_cmds[]; 76219820Sjeff 77219820Sjeffstatic inline char *next_token(char **p_last) 78219820Sjeff{ 79219820Sjeff return strtok_r(NULL, " \t\n\r", p_last); 80219820Sjeff} 81219820Sjeff 82219820Sjeffstatic void help_command(FILE * out, int detail) 83219820Sjeff{ 84219820Sjeff int i; 85219820Sjeff 86219820Sjeff fprintf(out, "Supported commands and syntax:\n"); 87219820Sjeff fprintf(out, "help [<command>]\n"); 88219820Sjeff /* skip help command */ 89219820Sjeff for (i = 1; console_cmds[i].name; i++) 90219820Sjeff console_cmds[i].help_function(out, 0); 91219820Sjeff} 92219820Sjeff 93219820Sjeffstatic void help_quit(FILE * out, int detail) 94219820Sjeff{ 95219820Sjeff fprintf(out, "quit (not valid in local mode; use ctl-c)\n"); 96219820Sjeff} 97219820Sjeff 98219820Sjeffstatic void help_loglevel(FILE * out, int detail) 99219820Sjeff{ 100219820Sjeff fprintf(out, "loglevel [<log-level>]\n"); 101219820Sjeff if (detail) { 102219820Sjeff fprintf(out, " log-level is OR'ed from the following\n"); 103219820Sjeff fprintf(out, " OSM_LOG_NONE 0x%02X\n", 104219820Sjeff OSM_LOG_NONE); 105219820Sjeff fprintf(out, " OSM_LOG_ERROR 0x%02X\n", 106219820Sjeff OSM_LOG_ERROR); 107219820Sjeff fprintf(out, " OSM_LOG_INFO 0x%02X\n", 108219820Sjeff OSM_LOG_INFO); 109219820Sjeff fprintf(out, " OSM_LOG_VERBOSE 0x%02X\n", 110219820Sjeff OSM_LOG_VERBOSE); 111219820Sjeff fprintf(out, " OSM_LOG_DEBUG 0x%02X\n", 112219820Sjeff OSM_LOG_DEBUG); 113219820Sjeff fprintf(out, " OSM_LOG_FUNCS 0x%02X\n", 114219820Sjeff OSM_LOG_FUNCS); 115219820Sjeff fprintf(out, " OSM_LOG_FRAMES 0x%02X\n", 116219820Sjeff OSM_LOG_FRAMES); 117219820Sjeff fprintf(out, " OSM_LOG_ROUTING 0x%02X\n", 118219820Sjeff OSM_LOG_ROUTING); 119219820Sjeff fprintf(out, " OSM_LOG_SYS 0x%02X\n", 120219820Sjeff OSM_LOG_SYS); 121219820Sjeff fprintf(out, "\n"); 122219820Sjeff fprintf(out, " OSM_LOG_DEFAULT_LEVEL 0x%02X\n", 123219820Sjeff OSM_LOG_DEFAULT_LEVEL); 124219820Sjeff } 125219820Sjeff} 126219820Sjeff 127219820Sjeffstatic void help_priority(FILE * out, int detail) 128219820Sjeff{ 129219820Sjeff fprintf(out, "priority [<sm-priority>]\n"); 130219820Sjeff} 131219820Sjeff 132219820Sjeffstatic void help_resweep(FILE * out, int detail) 133219820Sjeff{ 134219820Sjeff fprintf(out, "resweep [heavy|light]\n"); 135219820Sjeff} 136219820Sjeff 137219820Sjeffstatic void help_reroute(FILE * out, int detail) 138219820Sjeff{ 139219820Sjeff fprintf(out, "reroute\n"); 140219820Sjeff if (detail) { 141219820Sjeff fprintf(out, "reroute the fabric\n"); 142219820Sjeff } 143219820Sjeff} 144219820Sjeff 145219820Sjeffstatic void help_status(FILE * out, int detail) 146219820Sjeff{ 147219820Sjeff fprintf(out, "status [loop]\n"); 148219820Sjeff if (detail) { 149219820Sjeff fprintf(out, " loop -- type \"q<ret>\" to quit\n"); 150219820Sjeff } 151219820Sjeff} 152219820Sjeff 153219820Sjeffstatic void help_logflush(FILE * out, int detail) 154219820Sjeff{ 155219820Sjeff fprintf(out, "logflush -- flush the opensm.log file\n"); 156219820Sjeff} 157219820Sjeff 158219820Sjeffstatic void help_querylid(FILE * out, int detail) 159219820Sjeff{ 160219820Sjeff fprintf(out, 161219820Sjeff "querylid lid -- print internal information about the lid specified\n"); 162219820Sjeff} 163219820Sjeff 164219820Sjeffstatic void help_portstatus(FILE * out, int detail) 165219820Sjeff{ 166219820Sjeff fprintf(out, "portstatus [ca|switch|router]\n"); 167219820Sjeff if (detail) { 168219820Sjeff fprintf(out, "summarize port status\n"); 169219820Sjeff fprintf(out, 170219820Sjeff " [ca|switch|router] -- limit the results to the node type specified\n"); 171219820Sjeff } 172219820Sjeff 173219820Sjeff} 174219820Sjeff 175219820Sjeffstatic void help_switchbalance(FILE * out, int detail) 176219820Sjeff{ 177219820Sjeff fprintf(out, "switchbalance [verbose] [guid]\n"); 178219820Sjeff if (detail) { 179219820Sjeff fprintf(out, "output switch balancing information\n"); 180219820Sjeff fprintf(out, 181219820Sjeff " [verbose] -- verbose output\n" 182219820Sjeff " [guid] -- limit results to specified guid\n"); 183219820Sjeff } 184219820Sjeff} 185219820Sjeff 186219820Sjeffstatic void help_lidbalance(FILE * out, int detail) 187219820Sjeff{ 188219820Sjeff fprintf(out, "lidbalance [switchguid]\n"); 189219820Sjeff if (detail) { 190219820Sjeff fprintf(out, "output lid balanced forwarding information\n"); 191219820Sjeff fprintf(out, 192219820Sjeff " [switchguid] -- limit results to specified switch guid\n"); 193219820Sjeff } 194219820Sjeff} 195219820Sjeff 196219820Sjeffstatic void help_dump_conf(FILE *out, int detail) 197219820Sjeff{ 198219820Sjeff fprintf(out, "dump_conf\n"); 199219820Sjeff if (detail) { 200219820Sjeff fprintf(out, "dump current opensm configuration\n"); 201219820Sjeff } 202219820Sjeff} 203219820Sjeff 204219820Sjeff#ifdef ENABLE_OSM_PERF_MGR 205219820Sjeffstatic void help_perfmgr(FILE * out, int detail) 206219820Sjeff{ 207219820Sjeff fprintf(out, 208219820Sjeff "perfmgr [enable|disable|clear_counters|dump_counters|sweep_time[seconds]]\n"); 209219820Sjeff if (detail) { 210219820Sjeff fprintf(out, 211219820Sjeff "perfmgr -- print the performance manager state\n"); 212219820Sjeff fprintf(out, 213219820Sjeff " [enable|disable] -- change the perfmgr state\n"); 214219820Sjeff fprintf(out, 215219820Sjeff " [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n"); 216219820Sjeff fprintf(out, 217219820Sjeff " [clear_counters] -- clear the counters stored\n"); 218219820Sjeff fprintf(out, 219219820Sjeff " [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n"); 220219820Sjeff fprintf(out, 221219820Sjeff " [print_counters <nodename|nodeguid>] -- print the counters for the specified node\n"); 222219820Sjeff } 223219820Sjeff} 224219820Sjeff#endif /* ENABLE_OSM_PERF_MGR */ 225219820Sjeff 226219820Sjeff/* more help routines go here */ 227219820Sjeff 228219820Sjeffstatic void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 229219820Sjeff{ 230219820Sjeff char *p_cmd; 231219820Sjeff int i, found = 0; 232219820Sjeff 233219820Sjeff p_cmd = next_token(p_last); 234219820Sjeff if (!p_cmd) 235219820Sjeff help_command(out, 0); 236219820Sjeff else { 237219820Sjeff for (i = 1; console_cmds[i].name; i++) { 238219820Sjeff if (!strcmp(p_cmd, console_cmds[i].name)) { 239219820Sjeff found = 1; 240219820Sjeff console_cmds[i].help_function(out, 1); 241219820Sjeff break; 242219820Sjeff } 243219820Sjeff } 244219820Sjeff if (!found) { 245219820Sjeff fprintf(out, "%s : Command not found\n\n", p_cmd); 246219820Sjeff help_command(out, 0); 247219820Sjeff } 248219820Sjeff } 249219820Sjeff} 250219820Sjeff 251219820Sjeffstatic void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 252219820Sjeff{ 253219820Sjeff char *p_cmd; 254219820Sjeff int level; 255219820Sjeff 256219820Sjeff p_cmd = next_token(p_last); 257219820Sjeff if (!p_cmd) 258219820Sjeff fprintf(out, "Current log level is 0x%x\n", 259219820Sjeff osm_log_get_level(&p_osm->log)); 260219820Sjeff else { 261219820Sjeff /* Handle x, 0x, and decimal specification of log level */ 262219820Sjeff if (!strncmp(p_cmd, "x", 1)) { 263219820Sjeff p_cmd++; 264219820Sjeff level = strtoul(p_cmd, NULL, 16); 265219820Sjeff } else { 266219820Sjeff if (!strncmp(p_cmd, "0x", 2)) { 267219820Sjeff p_cmd += 2; 268219820Sjeff level = strtoul(p_cmd, NULL, 16); 269219820Sjeff } else 270219820Sjeff level = strtol(p_cmd, NULL, 10); 271219820Sjeff } 272219820Sjeff if ((level >= 0) && (level < 256)) { 273219820Sjeff fprintf(out, "Setting log level to 0x%x\n", level); 274219820Sjeff osm_log_set_level(&p_osm->log, level); 275219820Sjeff } else 276219820Sjeff fprintf(out, "Invalid log level 0x%x\n", level); 277219820Sjeff } 278219820Sjeff} 279219820Sjeff 280219820Sjeffstatic void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 281219820Sjeff{ 282219820Sjeff char *p_cmd; 283219820Sjeff int priority; 284219820Sjeff 285219820Sjeff p_cmd = next_token(p_last); 286219820Sjeff if (!p_cmd) 287219820Sjeff fprintf(out, "Current sm-priority is %d\n", 288219820Sjeff p_osm->subn.opt.sm_priority); 289219820Sjeff else { 290219820Sjeff priority = strtol(p_cmd, NULL, 0); 291219820Sjeff if (0 > priority || 15 < priority) 292219820Sjeff fprintf(out, 293219820Sjeff "Invalid sm-priority %d; must be between 0 and 15\n", 294219820Sjeff priority); 295219820Sjeff else { 296219820Sjeff fprintf(out, "Setting sm-priority to %d\n", priority); 297219820Sjeff osm_set_sm_priority(&p_osm->sm, (uint8_t)priority); 298219820Sjeff } 299219820Sjeff } 300219820Sjeff} 301219820Sjeff 302219820Sjeffstatic char *sm_state_str(int state) 303219820Sjeff{ 304219820Sjeff switch (state) { 305219820Sjeff case IB_SMINFO_STATE_DISCOVERING: 306219820Sjeff return ("Discovering"); 307219820Sjeff case IB_SMINFO_STATE_STANDBY: 308219820Sjeff return ("Standby"); 309219820Sjeff case IB_SMINFO_STATE_NOTACTIVE: 310219820Sjeff return ("Not Active"); 311219820Sjeff case IB_SMINFO_STATE_MASTER: 312219820Sjeff return ("Master"); 313219820Sjeff } 314219820Sjeff return ("UNKNOWN"); 315219820Sjeff} 316219820Sjeff 317219820Sjeffstatic char *sa_state_str(osm_sa_state_t state) 318219820Sjeff{ 319219820Sjeff switch (state) { 320219820Sjeff case OSM_SA_STATE_INIT: 321219820Sjeff return ("Init"); 322219820Sjeff case OSM_SA_STATE_READY: 323219820Sjeff return ("Ready"); 324219820Sjeff } 325219820Sjeff return ("UNKNOWN"); 326219820Sjeff} 327219820Sjeff 328219820Sjeffstatic void print_status(osm_opensm_t * p_osm, FILE * out) 329219820Sjeff{ 330219820Sjeff cl_list_item_t *item; 331219820Sjeff 332219820Sjeff if (out) { 333219820Sjeff cl_plock_acquire(&p_osm->lock); 334219820Sjeff fprintf(out, " OpenSM Version : %s\n", p_osm->osm_version); 335219820Sjeff fprintf(out, " SM State : %s\n", 336219820Sjeff sm_state_str(p_osm->subn.sm_state)); 337219820Sjeff fprintf(out, " SA State : %s\n", 338219820Sjeff sa_state_str(p_osm->sa.state)); 339219820Sjeff fprintf(out, " Routing Engine : %s\n", 340219820Sjeff osm_routing_engine_type_str(p_osm-> 341219820Sjeff routing_engine_used)); 342219820Sjeff 343219820Sjeff fprintf(out, " Loaded event plugins :"); 344219820Sjeff if (cl_qlist_head(&p_osm->plugin_list) == 345219820Sjeff cl_qlist_end(&p_osm->plugin_list)) { 346219820Sjeff fprintf(out, " <none>"); 347219820Sjeff } 348219820Sjeff for (item = cl_qlist_head(&p_osm->plugin_list); 349219820Sjeff item != cl_qlist_end(&p_osm->plugin_list); 350219820Sjeff item = cl_qlist_next(item)) 351219820Sjeff fprintf(out, " %s", 352219820Sjeff ((osm_epi_plugin_t *)item)->plugin_name); 353219820Sjeff fprintf(out, "\n"); 354219820Sjeff 355219820Sjeff#ifdef ENABLE_OSM_PERF_MGR 356219820Sjeff fprintf(out, "\n PerfMgr state/sweep state : %s/%s\n", 357219820Sjeff osm_perfmgr_get_state_str(&(p_osm->perfmgr)), 358219820Sjeff osm_perfmgr_get_sweep_state_str(&(p_osm->perfmgr))); 359219820Sjeff#endif 360219820Sjeff fprintf(out, "\n MAD stats\n" 361219820Sjeff " ---------\n" 362219820Sjeff " QP0 MADs outstanding : %d\n" 363219820Sjeff " QP0 MADs outstanding (on wire) : %d\n" 364219820Sjeff " QP0 MADs rcvd : %d\n" 365219820Sjeff " QP0 MADs sent : %d\n" 366219820Sjeff " QP0 unicasts sent : %d\n" 367219820Sjeff " QP0 unknown MADs rcvd : %d\n" 368219820Sjeff " SA MADs outstanding : %d\n" 369219820Sjeff " SA MADs rcvd : %d\n" 370219820Sjeff " SA MADs sent : %d\n" 371219820Sjeff " SA unknown MADs rcvd : %d\n" 372219820Sjeff " SA MADs ignored : %d\n", 373219820Sjeff p_osm->stats.qp0_mads_outstanding, 374219820Sjeff p_osm->stats.qp0_mads_outstanding_on_wire, 375219820Sjeff p_osm->stats.qp0_mads_rcvd, 376219820Sjeff p_osm->stats.qp0_mads_sent, 377219820Sjeff p_osm->stats.qp0_unicasts_sent, 378219820Sjeff p_osm->stats.qp0_mads_rcvd_unknown, 379219820Sjeff p_osm->stats.sa_mads_outstanding, 380219820Sjeff p_osm->stats.sa_mads_rcvd, 381219820Sjeff p_osm->stats.sa_mads_sent, 382219820Sjeff p_osm->stats.sa_mads_rcvd_unknown, 383219820Sjeff p_osm->stats.sa_mads_ignored); 384219820Sjeff fprintf(out, "\n Subnet flags\n" 385219820Sjeff " ------------\n" 386219820Sjeff " Ignore existing lfts : %d\n" 387219820Sjeff " Subnet Init errors : %d\n" 388219820Sjeff " In sweep hop 0 : %d\n" 389219820Sjeff " First time master sweep : %d\n" 390219820Sjeff " Coming out of standby : %d\n", 391219820Sjeff p_osm->subn.ignore_existing_lfts, 392219820Sjeff p_osm->subn.subnet_initialization_error, 393219820Sjeff p_osm->subn.in_sweep_hop_0, 394219820Sjeff p_osm->subn.first_time_master_sweep, 395219820Sjeff p_osm->subn.coming_out_of_standby); 396219820Sjeff fprintf(out, "\n"); 397219820Sjeff cl_plock_release(&p_osm->lock); 398219820Sjeff } 399219820Sjeff} 400219820Sjeff 401219820Sjeffstatic int loop_command_check_time(void) 402219820Sjeff{ 403219820Sjeff time_t cur = time(NULL); 404219820Sjeff if ((loop_command.previous + loop_command.delay_s) < cur) { 405219820Sjeff loop_command.previous = cur; 406219820Sjeff return (1); 407219820Sjeff } 408219820Sjeff return (0); 409219820Sjeff} 410219820Sjeff 411219820Sjeffstatic void status_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 412219820Sjeff{ 413219820Sjeff char *p_cmd; 414219820Sjeff 415219820Sjeff p_cmd = next_token(p_last); 416219820Sjeff if (p_cmd) { 417219820Sjeff if (strcmp(p_cmd, "loop") == 0) { 418219820Sjeff fprintf(out, "Looping on status command...\n"); 419219820Sjeff fflush(out); 420219820Sjeff loop_command.on = 1; 421219820Sjeff loop_command.previous = time(NULL); 422219820Sjeff loop_command.loop_function = print_status; 423219820Sjeff } else { 424219820Sjeff help_status(out, 1); 425219820Sjeff return; 426219820Sjeff } 427219820Sjeff } 428219820Sjeff print_status(p_osm, out); 429219820Sjeff} 430219820Sjeff 431219820Sjeffstatic void resweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 432219820Sjeff{ 433219820Sjeff char *p_cmd; 434219820Sjeff 435219820Sjeff p_cmd = next_token(p_last); 436219820Sjeff if (!p_cmd || 437219820Sjeff (strcmp(p_cmd, "heavy") != 0 && strcmp(p_cmd, "light") != 0)) { 438219820Sjeff fprintf(out, "Invalid resweep command\n"); 439219820Sjeff help_resweep(out, 1); 440219820Sjeff } else { 441219820Sjeff if (strcmp(p_cmd, "heavy") == 0) 442219820Sjeff p_osm->subn.force_heavy_sweep = TRUE; 443219820Sjeff osm_opensm_sweep(p_osm); 444219820Sjeff } 445219820Sjeff} 446219820Sjeff 447219820Sjeffstatic void reroute_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 448219820Sjeff{ 449219820Sjeff p_osm->subn.force_reroute = TRUE; 450219820Sjeff osm_opensm_sweep(p_osm); 451219820Sjeff} 452219820Sjeff 453219820Sjeffstatic void logflush_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 454219820Sjeff{ 455219820Sjeff fflush(p_osm->log.out_port); 456219820Sjeff} 457219820Sjeff 458219820Sjeffstatic void querylid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 459219820Sjeff{ 460219820Sjeff int p = 0; 461219820Sjeff uint16_t lid = 0; 462219820Sjeff osm_port_t *p_port = NULL; 463219820Sjeff char *p_cmd = next_token(p_last); 464219820Sjeff 465219820Sjeff if (!p_cmd) { 466219820Sjeff fprintf(out, "no LID specified\n"); 467219820Sjeff help_querylid(out, 1); 468219820Sjeff return; 469219820Sjeff } 470219820Sjeff 471219820Sjeff lid = (uint16_t) strtoul(p_cmd, NULL, 0); 472219820Sjeff cl_plock_acquire(&p_osm->lock); 473219820Sjeff if (lid > cl_ptr_vector_get_capacity(&(p_osm->subn.port_lid_tbl))) 474219820Sjeff goto invalid_lid; 475219820Sjeff p_port = cl_ptr_vector_get(&(p_osm->subn.port_lid_tbl), lid); 476219820Sjeff if (!p_port) 477219820Sjeff goto invalid_lid; 478219820Sjeff 479219820Sjeff fprintf(out, "Query results for LID %u\n", lid); 480219820Sjeff fprintf(out, 481219820Sjeff " GUID : 0x%016" PRIx64 "\n" 482219820Sjeff " Node Desc : %s\n" 483219820Sjeff " Node Type : %s\n" 484219820Sjeff " Num Ports : %d\n", 485219820Sjeff cl_ntoh64(p_port->guid), 486219820Sjeff p_port->p_node->print_desc, 487219820Sjeff ib_get_node_type_str(osm_node_get_type(p_port->p_node)), 488219820Sjeff p_port->p_node->node_info.num_ports); 489219820Sjeff 490219820Sjeff if (p_port->p_node->sw) 491219820Sjeff p = 0; 492219820Sjeff else 493219820Sjeff p = 1; 494219820Sjeff for ( /* see above */ ; p < p_port->p_node->physp_tbl_size; p++) { 495219820Sjeff fprintf(out, 496219820Sjeff " Port %d health : %s\n", 497219820Sjeff p, 498219820Sjeff p_port->p_node->physp_table[p]. 499219820Sjeff healthy ? "OK" : "ERROR"); 500219820Sjeff } 501219820Sjeff 502219820Sjeff cl_plock_release(&p_osm->lock); 503219820Sjeff return; 504219820Sjeff 505219820Sjeffinvalid_lid: 506219820Sjeff cl_plock_release(&p_osm->lock); 507219820Sjeff fprintf(out, "Invalid lid %d\n", lid); 508219820Sjeff return; 509219820Sjeff} 510219820Sjeff 511219820Sjeff/** 512219820Sjeff * Data structures for the portstatus command 513219820Sjeff */ 514219820Sjefftypedef struct _port_report { 515219820Sjeff struct _port_report *next; 516219820Sjeff uint64_t node_guid; 517219820Sjeff uint8_t port_num; 518219820Sjeff char print_desc[IB_NODE_DESCRIPTION_SIZE + 1]; 519219820Sjeff} port_report_t; 520219820Sjeff 521219820Sjeffstatic void 522219820Sjeff__tag_port_report(port_report_t ** head, uint64_t node_guid, 523219820Sjeff uint8_t port_num, char *print_desc) 524219820Sjeff{ 525219820Sjeff port_report_t *rep = malloc(sizeof(*rep)); 526219820Sjeff if (!rep) 527219820Sjeff return; 528219820Sjeff 529219820Sjeff rep->node_guid = node_guid; 530219820Sjeff rep->port_num = port_num; 531219820Sjeff memcpy(rep->print_desc, print_desc, IB_NODE_DESCRIPTION_SIZE + 1); 532219820Sjeff rep->next = NULL; 533219820Sjeff if (*head) { 534219820Sjeff rep->next = *head; 535219820Sjeff *head = rep; 536219820Sjeff } else 537219820Sjeff *head = rep; 538219820Sjeff} 539219820Sjeff 540219820Sjeffstatic void __print_port_report(FILE * out, port_report_t * head) 541219820Sjeff{ 542219820Sjeff port_report_t *item = head; 543219820Sjeff while (item != NULL) { 544219820Sjeff fprintf(out, " 0x%016" PRIx64 " %d (%s)\n", 545219820Sjeff item->node_guid, item->port_num, item->print_desc); 546219820Sjeff port_report_t *next = item->next; 547219820Sjeff free(item); 548219820Sjeff item = next; 549219820Sjeff } 550219820Sjeff} 551219820Sjeff 552219820Sjefftypedef struct { 553219820Sjeff uint8_t node_type_lim; /* limit the results; 0 == ALL */ 554219820Sjeff uint64_t total_nodes; 555219820Sjeff uint64_t total_ports; 556219820Sjeff uint64_t ports_down; 557219820Sjeff uint64_t ports_active; 558219820Sjeff uint64_t ports_disabled; 559219820Sjeff port_report_t *disabled_ports; 560219820Sjeff uint64_t ports_1X; 561219820Sjeff uint64_t ports_4X; 562219820Sjeff uint64_t ports_8X; 563219820Sjeff uint64_t ports_12X; 564219820Sjeff uint64_t ports_unknown_width; 565219820Sjeff uint64_t ports_reduced_width; 566219820Sjeff port_report_t *reduced_width_ports; 567219820Sjeff uint64_t ports_sdr; 568219820Sjeff uint64_t ports_ddr; 569219820Sjeff uint64_t ports_qdr; 570219820Sjeff uint64_t ports_unknown_speed; 571219820Sjeff uint64_t ports_reduced_speed; 572219820Sjeff port_report_t *reduced_speed_ports; 573219820Sjeff} fabric_stats_t; 574219820Sjeff 575219820Sjeff/** 576219820Sjeff * iterator function to get portstatus on each node 577219820Sjeff */ 578219820Sjeffstatic void __get_stats(cl_map_item_t * const p_map_item, void *context) 579219820Sjeff{ 580219820Sjeff fabric_stats_t *fs = (fabric_stats_t *) context; 581219820Sjeff osm_node_t *node = (osm_node_t *) p_map_item; 582219820Sjeff uint8_t num_ports = osm_node_get_num_physp(node); 583219820Sjeff uint8_t port = 0; 584219820Sjeff 585219820Sjeff /* Skip nodes we are not interested in */ 586219820Sjeff if (fs->node_type_lim != 0 587219820Sjeff && fs->node_type_lim != node->node_info.node_type) 588219820Sjeff return; 589219820Sjeff 590219820Sjeff fs->total_nodes++; 591219820Sjeff 592219820Sjeff for (port = 1; port < num_ports; port++) { 593219820Sjeff osm_physp_t *phys = osm_node_get_physp_ptr(node, port); 594219820Sjeff ib_port_info_t *pi = NULL; 595219820Sjeff uint8_t active_speed = 0; 596219820Sjeff uint8_t enabled_speed = 0; 597219820Sjeff uint8_t active_width = 0; 598219820Sjeff uint8_t enabled_width = 0; 599219820Sjeff uint8_t port_state = 0; 600219820Sjeff uint8_t port_phys_state = 0; 601219820Sjeff 602219820Sjeff if (!phys) 603219820Sjeff continue; 604219820Sjeff 605219820Sjeff pi = &(phys->port_info); 606219820Sjeff active_speed = ib_port_info_get_link_speed_active(pi); 607219820Sjeff enabled_speed = ib_port_info_get_link_speed_enabled(pi); 608219820Sjeff active_width = pi->link_width_active; 609219820Sjeff enabled_width = pi->link_width_enabled; 610219820Sjeff port_state = ib_port_info_get_port_state(pi); 611219820Sjeff port_phys_state = ib_port_info_get_port_phys_state(pi); 612219820Sjeff 613219820Sjeff if ((enabled_width ^ active_width) > active_width) { 614219820Sjeff __tag_port_report(&(fs->reduced_width_ports), 615219820Sjeff cl_ntoh64(node->node_info.node_guid), 616219820Sjeff port, node->print_desc); 617219820Sjeff fs->ports_reduced_width++; 618219820Sjeff } 619219820Sjeff 620219820Sjeff if ((enabled_speed ^ active_speed) > active_speed) { 621219820Sjeff __tag_port_report(&(fs->reduced_speed_ports), 622219820Sjeff cl_ntoh64(node->node_info.node_guid), 623219820Sjeff port, node->print_desc); 624219820Sjeff fs->ports_reduced_speed++; 625219820Sjeff } 626219820Sjeff 627219820Sjeff switch (active_speed) { 628219820Sjeff case IB_LINK_SPEED_ACTIVE_2_5: 629219820Sjeff fs->ports_sdr++; 630219820Sjeff break; 631219820Sjeff case IB_LINK_SPEED_ACTIVE_5: 632219820Sjeff fs->ports_ddr++; 633219820Sjeff break; 634219820Sjeff case IB_LINK_SPEED_ACTIVE_10: 635219820Sjeff fs->ports_qdr++; 636219820Sjeff break; 637219820Sjeff default: 638219820Sjeff fs->ports_unknown_speed++; 639219820Sjeff break; 640219820Sjeff } 641219820Sjeff switch (active_width) { 642219820Sjeff case IB_LINK_WIDTH_ACTIVE_1X: 643219820Sjeff fs->ports_1X++; 644219820Sjeff break; 645219820Sjeff case IB_LINK_WIDTH_ACTIVE_4X: 646219820Sjeff fs->ports_4X++; 647219820Sjeff break; 648219820Sjeff case IB_LINK_WIDTH_ACTIVE_8X: 649219820Sjeff fs->ports_8X++; 650219820Sjeff break; 651219820Sjeff case IB_LINK_WIDTH_ACTIVE_12X: 652219820Sjeff fs->ports_12X++; 653219820Sjeff break; 654219820Sjeff default: 655219820Sjeff fs->ports_unknown_width++; 656219820Sjeff break; 657219820Sjeff } 658219820Sjeff if (port_state == IB_LINK_DOWN) 659219820Sjeff fs->ports_down++; 660219820Sjeff else if (port_state == IB_LINK_ACTIVE) 661219820Sjeff fs->ports_active++; 662219820Sjeff if (port_phys_state == IB_PORT_PHYS_STATE_DISABLED) { 663219820Sjeff __tag_port_report(&(fs->disabled_ports), 664219820Sjeff cl_ntoh64(node->node_info.node_guid), 665219820Sjeff port, node->print_desc); 666219820Sjeff fs->ports_disabled++; 667219820Sjeff } 668219820Sjeff 669219820Sjeff fs->total_ports++; 670219820Sjeff } 671219820Sjeff} 672219820Sjeff 673219820Sjeffstatic void portstatus_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 674219820Sjeff{ 675219820Sjeff fabric_stats_t fs; 676219820Sjeff struct timeval before, after; 677219820Sjeff char *p_cmd; 678219820Sjeff 679219820Sjeff memset(&fs, 0, sizeof(fs)); 680219820Sjeff 681219820Sjeff p_cmd = next_token(p_last); 682219820Sjeff if (p_cmd) { 683219820Sjeff if (strcmp(p_cmd, "ca") == 0) { 684219820Sjeff fs.node_type_lim = IB_NODE_TYPE_CA; 685219820Sjeff } else if (strcmp(p_cmd, "switch") == 0) { 686219820Sjeff fs.node_type_lim = IB_NODE_TYPE_SWITCH; 687219820Sjeff } else if (strcmp(p_cmd, "router") == 0) { 688219820Sjeff fs.node_type_lim = IB_NODE_TYPE_ROUTER; 689219820Sjeff } else { 690219820Sjeff fprintf(out, "Node type not understood\n"); 691219820Sjeff help_portstatus(out, 1); 692219820Sjeff return; 693219820Sjeff } 694219820Sjeff } 695219820Sjeff 696219820Sjeff gettimeofday(&before, NULL); 697219820Sjeff 698219820Sjeff /* for each node in the system gather the stats */ 699219820Sjeff cl_plock_acquire(&p_osm->lock); 700219820Sjeff cl_qmap_apply_func(&(p_osm->subn.node_guid_tbl), __get_stats, 701219820Sjeff (void *)&fs); 702219820Sjeff cl_plock_release(&p_osm->lock); 703219820Sjeff 704219820Sjeff gettimeofday(&after, NULL); 705219820Sjeff 706219820Sjeff /* report the stats */ 707219820Sjeff fprintf(out, "\"%s\" port status:\n", 708219820Sjeff fs.node_type_lim ? ib_get_node_type_str(fs. 709219820Sjeff node_type_lim) : "ALL"); 710219820Sjeff fprintf(out, 711219820Sjeff " %" PRIu64 " port(s) scanned on %" PRIu64 712219820Sjeff " nodes in %lu us\n", fs.total_ports, fs.total_nodes, 713219820Sjeff after.tv_usec - before.tv_usec); 714219820Sjeff 715219820Sjeff if (fs.ports_down) 716219820Sjeff fprintf(out, " %" PRIu64 " down\n", fs.ports_down); 717219820Sjeff if (fs.ports_active) 718219820Sjeff fprintf(out, " %" PRIu64 " active\n", fs.ports_active); 719219820Sjeff if (fs.ports_1X) 720219820Sjeff fprintf(out, " %" PRIu64 " at 1X\n", fs.ports_1X); 721219820Sjeff if (fs.ports_4X) 722219820Sjeff fprintf(out, " %" PRIu64 " at 4X\n", fs.ports_4X); 723219820Sjeff if (fs.ports_8X) 724219820Sjeff fprintf(out, " %" PRIu64 " at 8X\n", fs.ports_8X); 725219820Sjeff if (fs.ports_12X) 726219820Sjeff fprintf(out, " %" PRIu64 " at 12X\n", fs.ports_12X); 727219820Sjeff 728219820Sjeff if (fs.ports_sdr) 729219820Sjeff fprintf(out, " %" PRIu64 " at 2.5 Gbps\n", fs.ports_sdr); 730219820Sjeff if (fs.ports_ddr) 731219820Sjeff fprintf(out, " %" PRIu64 " at 5.0 Gbps\n", fs.ports_ddr); 732219820Sjeff if (fs.ports_qdr) 733219820Sjeff fprintf(out, " %" PRIu64 " at 10.0 Gbps\n", fs.ports_qdr); 734219820Sjeff 735219820Sjeff if (fs.ports_disabled + fs.ports_reduced_speed + fs.ports_reduced_width 736219820Sjeff > 0) { 737219820Sjeff fprintf(out, "\nPossible issues:\n"); 738219820Sjeff } 739219820Sjeff if (fs.ports_disabled) { 740219820Sjeff fprintf(out, " %" PRIu64 " disabled\n", fs.ports_disabled); 741219820Sjeff __print_port_report(out, fs.disabled_ports); 742219820Sjeff } 743219820Sjeff if (fs.ports_reduced_speed) { 744219820Sjeff fprintf(out, " %" PRIu64 " with reduced speed\n", 745219820Sjeff fs.ports_reduced_speed); 746219820Sjeff __print_port_report(out, fs.reduced_speed_ports); 747219820Sjeff } 748219820Sjeff if (fs.ports_reduced_width) { 749219820Sjeff fprintf(out, " %" PRIu64 " with reduced width\n", 750219820Sjeff fs.ports_reduced_width); 751219820Sjeff __print_port_report(out, fs.reduced_width_ports); 752219820Sjeff } 753219820Sjeff fprintf(out, "\n"); 754219820Sjeff} 755219820Sjeff 756219820Sjeffstatic void switchbalance_check(osm_opensm_t * p_osm, 757219820Sjeff osm_switch_t * p_sw, FILE * out, int verbose) 758219820Sjeff{ 759219820Sjeff uint8_t port_num; 760219820Sjeff uint8_t num_ports; 761219820Sjeff const cl_qmap_t *p_port_tbl; 762219820Sjeff osm_port_t *p_port; 763219820Sjeff osm_physp_t *p_physp; 764219820Sjeff osm_physp_t *p_rem_physp; 765219820Sjeff osm_node_t *p_rem_node; 766219820Sjeff uint32_t count[255]; /* max ports is a uint8_t */ 767219820Sjeff uint8_t output_ports[255]; 768219820Sjeff uint8_t output_ports_count = 0; 769219820Sjeff uint32_t min_count = 0xFFFFFFFF; 770219820Sjeff uint32_t max_count = 0; 771219820Sjeff unsigned int i; 772219820Sjeff 773219820Sjeff memset(count, '\0', sizeof(uint32_t) * 255); 774219820Sjeff 775219820Sjeff /* Count port usage */ 776219820Sjeff p_port_tbl = &p_osm->subn.port_guid_tbl; 777219820Sjeff for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); 778219820Sjeff p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); 779219820Sjeff p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { 780219820Sjeff uint16_t min_lid_ho; 781219820Sjeff uint16_t max_lid_ho; 782219820Sjeff uint16_t lid_ho; 783219820Sjeff 784219820Sjeff /* Don't count switches in port usage */ 785219820Sjeff if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) 786219820Sjeff continue; 787219820Sjeff 788219820Sjeff osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 789219820Sjeff 790219820Sjeff if (min_lid_ho == 0 || max_lid_ho == 0) 791219820Sjeff continue; 792219820Sjeff 793219820Sjeff for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { 794219820Sjeff port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); 795219820Sjeff if (port_num == OSM_NO_PATH) 796219820Sjeff continue; 797219820Sjeff 798219820Sjeff count[port_num]++; 799219820Sjeff } 800219820Sjeff } 801219820Sjeff 802219820Sjeff num_ports = p_sw->num_ports; 803219820Sjeff for (port_num = 1; port_num < num_ports; port_num++) { 804219820Sjeff p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); 805219820Sjeff 806219820Sjeff /* if port is down/unhealthy, don't consider it in 807219820Sjeff * min/max calculations 808219820Sjeff */ 809219820Sjeff if (!p_physp || !osm_physp_is_healthy(p_physp) 810219820Sjeff || !osm_physp_get_remote(p_physp)) 811219820Sjeff continue; 812219820Sjeff 813219820Sjeff p_rem_physp = osm_physp_get_remote(p_physp); 814219820Sjeff p_rem_node = osm_physp_get_node_ptr(p_rem_physp); 815219820Sjeff 816219820Sjeff /* If we are directly connected to a CA/router, its not really 817219820Sjeff * up for balancing consideration. 818219820Sjeff */ 819219820Sjeff if (osm_node_get_type(p_rem_node) != IB_NODE_TYPE_SWITCH) 820219820Sjeff continue; 821219820Sjeff 822219820Sjeff output_ports[output_ports_count] = port_num; 823219820Sjeff output_ports_count++; 824219820Sjeff 825219820Sjeff if (count[port_num] < min_count) 826219820Sjeff min_count = count[port_num]; 827219820Sjeff if (count[port_num] > max_count) 828219820Sjeff max_count = count[port_num]; 829219820Sjeff } 830219820Sjeff 831219820Sjeff if (verbose || ((max_count - min_count) > 1)) { 832219820Sjeff if ((max_count - min_count) > 1) 833219820Sjeff fprintf(out, 834219820Sjeff "Unbalanced Switch: 0x%016" PRIx64 " (%s)\n", 835219820Sjeff cl_ntoh64(p_sw->p_node->node_info.node_guid), 836219820Sjeff p_sw->p_node->print_desc); 837219820Sjeff else 838219820Sjeff fprintf(out, 839219820Sjeff "Switch: 0x%016" PRIx64 " (%s)\n", 840219820Sjeff cl_ntoh64(p_sw->p_node->node_info.node_guid), 841219820Sjeff p_sw->p_node->print_desc); 842219820Sjeff 843219820Sjeff for (i = 0; i < output_ports_count; i++) { 844219820Sjeff fprintf(out, 845219820Sjeff "Port %d: %d\n", 846219820Sjeff output_ports[i], count[output_ports[i]]); 847219820Sjeff } 848219820Sjeff } 849219820Sjeff} 850219820Sjeff 851219820Sjeffstatic void switchbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 852219820Sjeff{ 853219820Sjeff char *p_cmd; 854219820Sjeff uint64_t guid = 0; 855219820Sjeff osm_switch_t *p_sw; 856219820Sjeff int verbose = 0; 857219820Sjeff 858219820Sjeff p_cmd = next_token(p_last); 859219820Sjeff if (p_cmd) { 860219820Sjeff char *p_end; 861219820Sjeff 862219820Sjeff if (strcmp(p_cmd, "verbose") == 0) { 863219820Sjeff verbose++; 864219820Sjeff p_cmd = next_token(p_last); 865219820Sjeff } 866219820Sjeff 867219820Sjeff if (p_cmd) { 868219820Sjeff guid = strtoull(p_cmd, &p_end, 0); 869219820Sjeff if (!guid || *p_end != '\0') { 870219820Sjeff fprintf(out, "Invalid guid specified\n"); 871219820Sjeff help_switchbalance(out, 1); 872219820Sjeff return; 873219820Sjeff } 874219820Sjeff } 875219820Sjeff } 876219820Sjeff 877219820Sjeff cl_plock_acquire(&p_osm->lock); 878219820Sjeff if (guid) { 879219820Sjeff p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); 880219820Sjeff if (!p_sw) { 881219820Sjeff fprintf(out, "guid not found\n"); 882219820Sjeff goto lock_exit; 883219820Sjeff } 884219820Sjeff 885219820Sjeff switchbalance_check(p_osm, p_sw, out, verbose); 886219820Sjeff } else { 887219820Sjeff cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; 888219820Sjeff for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); 889219820Sjeff p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); 890219820Sjeff p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) 891219820Sjeff switchbalance_check(p_osm, p_sw, out, verbose); 892219820Sjeff } 893219820Sjefflock_exit: 894219820Sjeff cl_plock_release(&p_osm->lock); 895219820Sjeff return; 896219820Sjeff} 897219820Sjeff 898219820Sjeffstatic void lidbalance_check(osm_opensm_t * p_osm, 899219820Sjeff osm_switch_t * p_sw, FILE * out) 900219820Sjeff{ 901219820Sjeff uint8_t port_num; 902219820Sjeff const cl_qmap_t *p_port_tbl; 903219820Sjeff osm_port_t *p_port; 904219820Sjeff 905219820Sjeff p_port_tbl = &p_osm->subn.port_guid_tbl; 906219820Sjeff for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); 907219820Sjeff p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); 908219820Sjeff p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { 909219820Sjeff uint32_t port_count[255]; /* max ports is a uint8_t */ 910219820Sjeff osm_node_t *rem_node[255]; 911219820Sjeff uint32_t rem_node_count; 912219820Sjeff uint32_t rem_count[255]; 913219820Sjeff osm_physp_t *p_physp; 914219820Sjeff osm_physp_t *p_rem_physp; 915219820Sjeff osm_node_t *p_rem_node; 916219820Sjeff uint32_t port_min_count = 0xFFFFFFFF; 917219820Sjeff uint32_t port_max_count = 0; 918219820Sjeff uint32_t rem_min_count = 0xFFFFFFFF; 919219820Sjeff uint32_t rem_max_count = 0; 920219820Sjeff uint16_t min_lid_ho; 921219820Sjeff uint16_t max_lid_ho; 922219820Sjeff uint16_t lid_ho; 923219820Sjeff uint8_t num_ports; 924219820Sjeff unsigned int i; 925219820Sjeff 926219820Sjeff /* we only care about non-switches */ 927219820Sjeff if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) 928219820Sjeff continue; 929219820Sjeff 930219820Sjeff osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 931219820Sjeff 932219820Sjeff if (min_lid_ho == 0 || max_lid_ho == 0) 933219820Sjeff continue; 934219820Sjeff 935219820Sjeff memset(port_count, '\0', sizeof(uint32_t) * 255); 936219820Sjeff memset(rem_node, '\0', sizeof(osm_node_t *) * 255); 937219820Sjeff rem_node_count = 0; 938219820Sjeff memset(rem_count, '\0', sizeof(uint32_t) * 255); 939219820Sjeff 940219820Sjeff for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { 941219820Sjeff boolean_t rem_node_found = FALSE; 942219820Sjeff unsigned int indx = 0; 943219820Sjeff 944219820Sjeff port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); 945219820Sjeff if (port_num == OSM_NO_PATH) 946219820Sjeff continue; 947219820Sjeff 948219820Sjeff p_physp = 949219820Sjeff osm_node_get_physp_ptr(p_sw->p_node, port_num); 950219820Sjeff 951219820Sjeff /* if port is down/unhealthy, can't calculate */ 952219820Sjeff if (!p_physp || !osm_physp_is_healthy(p_physp) 953219820Sjeff || !osm_physp_get_remote(p_physp)) 954219820Sjeff continue; 955219820Sjeff 956219820Sjeff p_rem_physp = osm_physp_get_remote(p_physp); 957219820Sjeff p_rem_node = osm_physp_get_node_ptr(p_rem_physp); 958219820Sjeff 959219820Sjeff /* determine if we've seen this remote node before. 960219820Sjeff * If not, store it. If yes, update the counter 961219820Sjeff */ 962219820Sjeff for (i = 0; i < rem_node_count; i++) { 963219820Sjeff if (rem_node[i] == p_rem_node) { 964219820Sjeff rem_node_found = TRUE; 965219820Sjeff indx = i; 966219820Sjeff break; 967219820Sjeff } 968219820Sjeff } 969219820Sjeff 970219820Sjeff if (!rem_node_found) { 971219820Sjeff rem_node[rem_node_count] = p_rem_node; 972219820Sjeff rem_count[rem_node_count]++; 973219820Sjeff indx = rem_node_count; 974219820Sjeff rem_node_count++; 975219820Sjeff } else 976219820Sjeff rem_count[indx]++; 977219820Sjeff 978219820Sjeff port_count[port_num]++; 979219820Sjeff } 980219820Sjeff 981219820Sjeff if (!rem_node_count) 982219820Sjeff continue; 983219820Sjeff 984219820Sjeff for (i = 0; i < rem_node_count; i++) { 985219820Sjeff if (rem_count[i] < rem_min_count) 986219820Sjeff rem_min_count = rem_count[i]; 987219820Sjeff if (rem_count[i] > rem_max_count) 988219820Sjeff rem_max_count = rem_count[i]; 989219820Sjeff } 990219820Sjeff 991219820Sjeff num_ports = p_sw->num_ports; 992219820Sjeff for (i = 0; i < num_ports; i++) { 993219820Sjeff if (!port_count[i]) 994219820Sjeff continue; 995219820Sjeff if (port_count[i] < port_min_count) 996219820Sjeff port_min_count = port_count[i]; 997219820Sjeff if (port_count[i] > port_max_count) 998219820Sjeff port_max_count = port_count[i]; 999219820Sjeff } 1000219820Sjeff 1001219820Sjeff /* Output if this CA/router is being forwarded an unbalanced number of 1002219820Sjeff * times to a destination. 1003219820Sjeff */ 1004219820Sjeff if ((rem_max_count - rem_min_count) > 1) { 1005219820Sjeff fprintf(out, 1006219820Sjeff "Unbalanced Remote Forwarding: Switch 0x%016" 1007219820Sjeff PRIx64 " (%s): ", 1008219820Sjeff cl_ntoh64(p_sw->p_node->node_info.node_guid), 1009219820Sjeff p_sw->p_node->print_desc); 1010219820Sjeff if (osm_node_get_type(p_port->p_node) == 1011219820Sjeff IB_NODE_TYPE_CA) 1012219820Sjeff fprintf(out, "CA"); 1013219820Sjeff else if (osm_node_get_type(p_port->p_node) == 1014219820Sjeff IB_NODE_TYPE_ROUTER) 1015219820Sjeff fprintf(out, "Router"); 1016219820Sjeff fprintf(out, " 0x%016" PRIx64 " (%s): ", 1017219820Sjeff cl_ntoh64(p_port->p_node->node_info.node_guid), 1018219820Sjeff p_port->p_node->print_desc); 1019219820Sjeff for (i = 0; i < rem_node_count; i++) { 1020219820Sjeff fprintf(out, 1021219820Sjeff "Dest 0x%016" PRIx64 "(%s) - %u ", 1022219820Sjeff cl_ntoh64(rem_node[i]->node_info. 1023219820Sjeff node_guid), 1024219820Sjeff rem_node[i]->print_desc, rem_count[i]); 1025219820Sjeff } 1026219820Sjeff fprintf(out, "\n"); 1027219820Sjeff } 1028219820Sjeff 1029219820Sjeff /* Output if this CA/router is being forwarded through a port 1030219820Sjeff * an unbalanced number of times. 1031219820Sjeff */ 1032219820Sjeff if ((port_max_count - port_min_count) > 1) { 1033219820Sjeff fprintf(out, 1034219820Sjeff "Unbalanced Port Forwarding: Switch 0x%016" 1035219820Sjeff PRIx64 " (%s): ", 1036219820Sjeff cl_ntoh64(p_sw->p_node->node_info.node_guid), 1037219820Sjeff p_sw->p_node->print_desc); 1038219820Sjeff if (osm_node_get_type(p_port->p_node) == 1039219820Sjeff IB_NODE_TYPE_CA) 1040219820Sjeff fprintf(out, "CA"); 1041219820Sjeff else if (osm_node_get_type(p_port->p_node) == 1042219820Sjeff IB_NODE_TYPE_ROUTER) 1043219820Sjeff fprintf(out, "Router"); 1044219820Sjeff fprintf(out, " 0x%016" PRIx64 " (%s): ", 1045219820Sjeff cl_ntoh64(p_port->p_node->node_info.node_guid), 1046219820Sjeff p_port->p_node->print_desc); 1047219820Sjeff for (i = 0; i < num_ports; i++) { 1048219820Sjeff if (!port_count[i]) 1049219820Sjeff continue; 1050219820Sjeff fprintf(out, "Port %u - %u: ", i, 1051219820Sjeff port_count[i]); 1052219820Sjeff } 1053219820Sjeff fprintf(out, "\n"); 1054219820Sjeff } 1055219820Sjeff } 1056219820Sjeff} 1057219820Sjeff 1058219820Sjeffstatic void lidbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1059219820Sjeff{ 1060219820Sjeff char *p_cmd; 1061219820Sjeff uint64_t guid = 0; 1062219820Sjeff osm_switch_t *p_sw; 1063219820Sjeff 1064219820Sjeff p_cmd = next_token(p_last); 1065219820Sjeff if (p_cmd) { 1066219820Sjeff char *p_end; 1067219820Sjeff 1068219820Sjeff guid = strtoull(p_cmd, &p_end, 0); 1069219820Sjeff if (!guid || *p_end != '\0') { 1070219820Sjeff fprintf(out, "Invalid switchguid specified\n"); 1071219820Sjeff help_lidbalance(out, 1); 1072219820Sjeff return; 1073219820Sjeff } 1074219820Sjeff } 1075219820Sjeff 1076219820Sjeff cl_plock_acquire(&p_osm->lock); 1077219820Sjeff if (guid) { 1078219820Sjeff p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); 1079219820Sjeff if (!p_sw) { 1080219820Sjeff fprintf(out, "switchguid not found\n"); 1081219820Sjeff goto lock_exit; 1082219820Sjeff } 1083219820Sjeff lidbalance_check(p_osm, p_sw, out); 1084219820Sjeff } else { 1085219820Sjeff cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; 1086219820Sjeff for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); 1087219820Sjeff p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); 1088219820Sjeff p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) 1089219820Sjeff lidbalance_check(p_osm, p_sw, out); 1090219820Sjeff } 1091219820Sjeff 1092219820Sjefflock_exit: 1093219820Sjeff cl_plock_release(&p_osm->lock); 1094219820Sjeff return; 1095219820Sjeff} 1096219820Sjeff 1097219820Sjeffstatic void dump_conf_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1098219820Sjeff{ 1099219820Sjeff osm_subn_output_conf(out, &p_osm->subn.opt); 1100219820Sjeff} 1101219820Sjeff 1102219820Sjeff#ifdef ENABLE_OSM_PERF_MGR 1103219820Sjeffstatic void perfmgr_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1104219820Sjeff{ 1105219820Sjeff char *p_cmd; 1106219820Sjeff 1107219820Sjeff p_cmd = next_token(p_last); 1108219820Sjeff if (p_cmd) { 1109219820Sjeff if (strcmp(p_cmd, "enable") == 0) { 1110219820Sjeff osm_perfmgr_set_state(&(p_osm->perfmgr), 1111219820Sjeff PERFMGR_STATE_ENABLED); 1112219820Sjeff } else if (strcmp(p_cmd, "disable") == 0) { 1113219820Sjeff osm_perfmgr_set_state(&(p_osm->perfmgr), 1114219820Sjeff PERFMGR_STATE_DISABLE); 1115219820Sjeff } else if (strcmp(p_cmd, "clear_counters") == 0) { 1116219820Sjeff osm_perfmgr_clear_counters(&(p_osm->perfmgr)); 1117219820Sjeff } else if (strcmp(p_cmd, "dump_counters") == 0) { 1118219820Sjeff p_cmd = next_token(p_last); 1119219820Sjeff if (p_cmd && (strcmp(p_cmd, "mach") == 0)) { 1120219820Sjeff osm_perfmgr_dump_counters(&(p_osm->perfmgr), 1121219820Sjeff PERFMGR_EVENT_DB_DUMP_MR); 1122219820Sjeff } else { 1123219820Sjeff osm_perfmgr_dump_counters(&(p_osm->perfmgr), 1124219820Sjeff PERFMGR_EVENT_DB_DUMP_HR); 1125219820Sjeff } 1126219820Sjeff } else if (strcmp(p_cmd, "print_counters") == 0) { 1127219820Sjeff p_cmd = next_token(p_last); 1128219820Sjeff if (p_cmd) { 1129219820Sjeff osm_perfmgr_print_counters(&(p_osm->perfmgr), 1130219820Sjeff p_cmd, out); 1131219820Sjeff } else { 1132219820Sjeff fprintf(out, 1133219820Sjeff "print_counters requires a node name to be specified\n"); 1134219820Sjeff } 1135219820Sjeff } else if (strcmp(p_cmd, "sweep_time") == 0) { 1136219820Sjeff p_cmd = next_token(p_last); 1137219820Sjeff if (p_cmd) { 1138219820Sjeff uint16_t time_s = atoi(p_cmd); 1139219820Sjeff osm_perfmgr_set_sweep_time_s(&(p_osm->perfmgr), 1140219820Sjeff time_s); 1141219820Sjeff } else { 1142219820Sjeff fprintf(out, 1143219820Sjeff "sweep_time requires a time period (in seconds) to be specified\n"); 1144219820Sjeff } 1145219820Sjeff } else { 1146219820Sjeff fprintf(out, "\"%s\" option not found\n", p_cmd); 1147219820Sjeff } 1148219820Sjeff } else { 1149219820Sjeff fprintf(out, "Performance Manager status:\n" 1150219820Sjeff "state : %s\n" 1151219820Sjeff "sweep state : %s\n" 1152219820Sjeff "sweep time : %us\n" 1153219820Sjeff "outstanding queries/max : %d/%u\n", 1154219820Sjeff osm_perfmgr_get_state_str(&(p_osm->perfmgr)), 1155219820Sjeff osm_perfmgr_get_sweep_state_str(&(p_osm->perfmgr)), 1156219820Sjeff osm_perfmgr_get_sweep_time_s(&(p_osm->perfmgr)), 1157219820Sjeff p_osm->perfmgr.outstanding_queries, 1158219820Sjeff p_osm->perfmgr.max_outstanding_queries); 1159219820Sjeff } 1160219820Sjeff} 1161219820Sjeff#endif /* ENABLE_OSM_PERF_MGR */ 1162219820Sjeff 1163219820Sjeffstatic void quit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1164219820Sjeff{ 1165219820Sjeff osm_console_exit(&p_osm->console, &p_osm->log); 1166219820Sjeff} 1167219820Sjeff 1168219820Sjeffstatic void help_version(FILE * out, int detail) 1169219820Sjeff{ 1170219820Sjeff fprintf(out, "version -- print the OSM version\n"); 1171219820Sjeff} 1172219820Sjeff 1173219820Sjeffstatic void version_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1174219820Sjeff{ 1175219820Sjeff fprintf(out, "%s build %s %s\n", p_osm->osm_version, __DATE__, __TIME__); 1176219820Sjeff} 1177219820Sjeff 1178219820Sjeff/* more parse routines go here */ 1179219820Sjeff 1180219820Sjeffstatic const struct command console_cmds[] = { 1181219820Sjeff {"help", &help_command, &help_parse}, 1182219820Sjeff {"quit", &help_quit, &quit_parse}, 1183219820Sjeff {"loglevel", &help_loglevel, &loglevel_parse}, 1184219820Sjeff {"priority", &help_priority, &priority_parse}, 1185219820Sjeff {"resweep", &help_resweep, &resweep_parse}, 1186219820Sjeff {"reroute", &help_reroute, &reroute_parse}, 1187219820Sjeff {"status", &help_status, &status_parse}, 1188219820Sjeff {"logflush", &help_logflush, &logflush_parse}, 1189219820Sjeff {"querylid", &help_querylid, &querylid_parse}, 1190219820Sjeff {"portstatus", &help_portstatus, &portstatus_parse}, 1191219820Sjeff {"switchbalance", &help_switchbalance, &switchbalance_parse}, 1192219820Sjeff {"lidbalance", &help_lidbalance, &lidbalance_parse}, 1193219820Sjeff {"dump_conf", &help_dump_conf, &dump_conf_parse}, 1194219820Sjeff {"version", &help_version, &version_parse}, 1195219820Sjeff#ifdef ENABLE_OSM_PERF_MGR 1196219820Sjeff {"perfmgr", &help_perfmgr, &perfmgr_parse}, 1197219820Sjeff#endif /* ENABLE_OSM_PERF_MGR */ 1198219820Sjeff {NULL, NULL, NULL} /* end of array */ 1199219820Sjeff}; 1200219820Sjeff 1201219820Sjeffstatic void parse_cmd_line(char *line, osm_opensm_t * p_osm) 1202219820Sjeff{ 1203219820Sjeff char *p_cmd, *p_last; 1204219820Sjeff int i, found = 0; 1205219820Sjeff FILE *out = p_osm->console.out; 1206219820Sjeff 1207219820Sjeff while (isspace(*line)) 1208219820Sjeff line++; 1209219820Sjeff if (!*line) 1210219820Sjeff return; 1211219820Sjeff 1212219820Sjeff /* find first token which is the command */ 1213219820Sjeff p_cmd = strtok_r(line, " \t\n\r", &p_last); 1214219820Sjeff if (p_cmd) { 1215219820Sjeff for (i = 0; console_cmds[i].name; i++) { 1216219820Sjeff if (loop_command.on) { 1217219820Sjeff if (!strcmp(p_cmd, "q")) { 1218219820Sjeff loop_command.on = 0; 1219219820Sjeff } 1220219820Sjeff found = 1; 1221219820Sjeff break; 1222219820Sjeff } 1223219820Sjeff if (!strcmp(p_cmd, console_cmds[i].name)) { 1224219820Sjeff found = 1; 1225219820Sjeff console_cmds[i].parse_function(&p_last, p_osm, 1226219820Sjeff out); 1227219820Sjeff break; 1228219820Sjeff } 1229219820Sjeff } 1230219820Sjeff if (!found) { 1231219820Sjeff fprintf(out, "%s : Command not found\n\n", p_cmd); 1232219820Sjeff help_command(out, 0); 1233219820Sjeff } 1234219820Sjeff } else { 1235219820Sjeff fprintf(out, "Error parsing command line: `%s'\n", line); 1236219820Sjeff } 1237219820Sjeff if (loop_command.on) { 1238219820Sjeff fprintf(out, "use \"q<ret>\" to quit loop\n"); 1239219820Sjeff fflush(out); 1240219820Sjeff } 1241219820Sjeff} 1242219820Sjeff 1243219820Sjeffvoid osm_console(osm_opensm_t * p_osm) 1244219820Sjeff{ 1245219820Sjeff struct pollfd pollfd[2]; 1246219820Sjeff char *p_line; 1247219820Sjeff size_t len; 1248219820Sjeff ssize_t n; 1249219820Sjeff struct pollfd *fds; 1250219820Sjeff nfds_t nfds; 1251219820Sjeff osm_console_t *p_oct = &p_osm->console; 1252219820Sjeff osm_log_t *p_log = &p_osm->log; 1253219820Sjeff 1254219820Sjeff pollfd[0].fd = p_oct->socket; 1255219820Sjeff pollfd[0].events = POLLIN; 1256219820Sjeff pollfd[0].revents = 0; 1257219820Sjeff 1258219820Sjeff pollfd[1].fd = p_oct->in_fd; 1259219820Sjeff pollfd[1].events = POLLIN; 1260219820Sjeff pollfd[1].revents = 0; 1261219820Sjeff 1262219820Sjeff fds = p_oct->socket < 0 ? &pollfd[1] : pollfd; 1263219820Sjeff nfds = p_oct->socket < 0 || pollfd[1].fd < 0 ? 1 : 2; 1264219820Sjeff 1265219820Sjeff if (loop_command.on && loop_command_check_time() && 1266219820Sjeff loop_command.loop_function) { 1267219820Sjeff if (p_oct->out) { 1268219820Sjeff loop_command.loop_function(p_osm, p_oct->out); 1269219820Sjeff fflush(p_oct->out); 1270219820Sjeff } else { 1271219820Sjeff loop_command.on = 0; 1272219820Sjeff } 1273219820Sjeff } 1274219820Sjeff 1275219820Sjeff if (poll(fds, nfds, 1000) <= 0) 1276219820Sjeff return; 1277219820Sjeff 1278219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 1279219820Sjeff if (pollfd[0].revents & POLLIN) { 1280219820Sjeff int new_fd = 0; 1281219820Sjeff struct sockaddr_in sin; 1282219820Sjeff socklen_t len = sizeof(sin); 1283219820Sjeff struct hostent *hent; 1284219820Sjeff if ((new_fd = accept(p_oct->socket, &sin, &len)) < 0) { 1285219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, 1286219820Sjeff "ERR 4B04: Failed to accept console socket: %s\n", 1287219820Sjeff strerror(errno)); 1288219820Sjeff p_oct->in_fd = -1; 1289219820Sjeff return; 1290219820Sjeff } 1291219820Sjeff if (inet_ntop 1292219820Sjeff (AF_INET, &sin.sin_addr, p_oct->client_ip, 1293219820Sjeff sizeof(p_oct->client_ip)) == NULL) { 1294219820Sjeff snprintf(p_oct->client_ip, 64, "STRING_UNKNOWN"); 1295219820Sjeff } 1296219820Sjeff if ((hent = gethostbyaddr((const char *)&sin.sin_addr, 1297219820Sjeff sizeof(struct in_addr), 1298219820Sjeff AF_INET)) == NULL) { 1299219820Sjeff snprintf(p_oct->client_hn, 128, "STRING_UNKNOWN"); 1300219820Sjeff } else { 1301219820Sjeff snprintf(p_oct->client_hn, 128, "%s", hent->h_name); 1302219820Sjeff } 1303219820Sjeff if (is_authorized(p_oct)) { 1304219820Sjeff cio_open(p_oct, new_fd, p_log); 1305219820Sjeff } else { 1306219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, 1307219820Sjeff "ERR 4B05: Console connection denied: %s (%s)\n", 1308219820Sjeff p_oct->client_hn, p_oct->client_ip); 1309219820Sjeff close(new_fd); 1310219820Sjeff } 1311219820Sjeff return; 1312219820Sjeff } 1313219820Sjeff#endif 1314219820Sjeff 1315219820Sjeff if (pollfd[1].revents & POLLIN) { 1316219820Sjeff p_line = NULL; 1317219820Sjeff /* Get input line */ 1318219820Sjeff n = getline(&p_line, &len, p_oct->in); 1319219820Sjeff if (n > 0) { 1320219820Sjeff /* Parse and act on input */ 1321219820Sjeff parse_cmd_line(p_line, p_osm); 1322219820Sjeff if (!loop_command.on) { 1323219820Sjeff osm_console_prompt(p_oct->out); 1324219820Sjeff } 1325219820Sjeff } else 1326219820Sjeff osm_console_exit(p_oct, p_log); 1327219820Sjeff if (p_line) 1328219820Sjeff free(p_line); 1329219820Sjeff } 1330219820Sjeff} 1331