1 /* 2 * Copyright (c) 2005-2009 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2009,2010 HNR Consulting. All rights reserved. 4 * Copyright (c) 2010,2011 Mellanox Technologies LTD. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 * 34 */ 35 36 #if HAVE_CONFIG_H 37 # include <config.h> 38 #endif /* HAVE_CONFIG_H */ 39 40 #define _WITH_GETLINE /* for getline */ 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <sys/poll.h> 44 #include <sys/types.h> 45 #include <sys/socket.h> 46 #include <netdb.h> 47 #include <regex.h> 48 #ifdef ENABLE_OSM_CONSOLE_LOOPBACK 49 #include <arpa/inet.h> 50 #include <netinet/in.h> 51 #include <sys/socket.h> 52 #endif 53 #include <unistd.h> 54 #include <errno.h> 55 #include <ctype.h> 56 #include <sys/time.h> 57 #include <opensm/osm_file_ids.h> 58 #define FILE_ID OSM_FILE_CONSOLE_C 59 #include <opensm/osm_console.h> 60 #include <complib/cl_passivelock.h> 61 #include <opensm/osm_perfmgr.h> 62 #include <opensm/osm_subnet.h> 63 64 extern void osm_update_node_desc(IN osm_opensm_t *osm); 65 66 struct command { 67 const char *name; 68 void (*help_function) (FILE * out, int detail); 69 void (*parse_function) (char **p_last, osm_opensm_t * p_osm, 70 FILE * out); 71 }; 72 73 static struct { 74 int on; 75 int delay_s; 76 time_t previous; 77 void (*loop_function) (osm_opensm_t * p_osm, FILE * out); 78 } loop_command = { 79 .on = 0, .delay_s = 2, .loop_function = NULL}; 80 81 static const struct command console_cmds[]; 82 83 static char *next_token(char **p_last) 84 { 85 return strtok_r(NULL, " \t\n\r", p_last); 86 } 87 88 #ifdef ENABLE_OSM_PERF_MGR 89 static char *name_token(char **p_last) 90 { 91 return strtok_r(NULL, "\t\n\r", p_last); 92 } 93 #endif 94 95 static void help_command(FILE * out, int detail) 96 { 97 int i; 98 99 fprintf(out, "Supported commands and syntax:\n"); 100 fprintf(out, "help [<command>]\n"); 101 /* skip help command */ 102 for (i = 1; console_cmds[i].name; i++) 103 console_cmds[i].help_function(out, 0); 104 } 105 106 static void help_quit(FILE * out, int detail) 107 { 108 fprintf(out, "quit (not valid in local mode; use ctl-c)\n"); 109 } 110 111 static void help_loglevel(FILE * out, int detail) 112 { 113 fprintf(out, "loglevel [<log-level>]\n"); 114 if (detail) { 115 fprintf(out, " log-level is OR'ed from the following\n"); 116 fprintf(out, " OSM_LOG_NONE 0x%02X\n", 117 OSM_LOG_NONE); 118 fprintf(out, " OSM_LOG_ERROR 0x%02X\n", 119 OSM_LOG_ERROR); 120 fprintf(out, " OSM_LOG_INFO 0x%02X\n", 121 OSM_LOG_INFO); 122 fprintf(out, " OSM_LOG_VERBOSE 0x%02X\n", 123 OSM_LOG_VERBOSE); 124 fprintf(out, " OSM_LOG_DEBUG 0x%02X\n", 125 OSM_LOG_DEBUG); 126 fprintf(out, " OSM_LOG_FUNCS 0x%02X\n", 127 OSM_LOG_FUNCS); 128 fprintf(out, " OSM_LOG_FRAMES 0x%02X\n", 129 OSM_LOG_FRAMES); 130 fprintf(out, " OSM_LOG_ROUTING 0x%02X\n", 131 OSM_LOG_ROUTING); 132 fprintf(out, " OSM_LOG_SYS 0x%02X\n", 133 OSM_LOG_SYS); 134 fprintf(out, "\n"); 135 fprintf(out, " OSM_LOG_DEFAULT_LEVEL 0x%02X\n", 136 OSM_LOG_DEFAULT_LEVEL); 137 } 138 } 139 140 static void help_permodlog(FILE * out, int detail) 141 { 142 fprintf(out, "permodlog\n"); 143 } 144 145 static void help_priority(FILE * out, int detail) 146 { 147 fprintf(out, "priority [<sm-priority>]\n"); 148 } 149 150 static void help_resweep(FILE * out, int detail) 151 { 152 fprintf(out, "resweep [heavy|light]\n"); 153 } 154 155 static void help_reroute(FILE * out, int detail) 156 { 157 fprintf(out, "reroute\n"); 158 if (detail) { 159 fprintf(out, "reroute the fabric\n"); 160 } 161 } 162 163 static void help_sweep(FILE * out, int detail) 164 { 165 fprintf(out, "sweep [on|off]\n"); 166 if (detail) { 167 fprintf(out, "enable or disable sweeping\n"); 168 fprintf(out, " [on] sweep normally\n"); 169 fprintf(out, " [off] inhibit all sweeping\n"); 170 } 171 } 172 173 static void help_status(FILE * out, int detail) 174 { 175 fprintf(out, "status [loop]\n"); 176 if (detail) { 177 fprintf(out, " loop -- type \"q<ret>\" to quit\n"); 178 } 179 } 180 181 static void help_logflush(FILE * out, int detail) 182 { 183 fprintf(out, "logflush [on|off] -- toggle opensm.log file flushing\n"); 184 } 185 186 static void help_querylid(FILE * out, int detail) 187 { 188 fprintf(out, 189 "querylid lid -- print internal information about the lid specified\n"); 190 } 191 192 static void help_portstatus(FILE * out, int detail) 193 { 194 fprintf(out, "portstatus [ca|switch|router]\n"); 195 if (detail) { 196 fprintf(out, "summarize port status\n"); 197 fprintf(out, 198 " [ca|switch|router] -- limit the results to the node type specified\n"); 199 } 200 201 } 202 203 static void help_switchbalance(FILE * out, int detail) 204 { 205 fprintf(out, "switchbalance [verbose] [guid]\n"); 206 if (detail) { 207 fprintf(out, "output switch balancing information\n"); 208 fprintf(out, 209 " [verbose] -- verbose output\n" 210 " [guid] -- limit results to specified guid\n"); 211 } 212 } 213 214 static void help_lidbalance(FILE * out, int detail) 215 { 216 fprintf(out, "lidbalance [switchguid]\n"); 217 if (detail) { 218 fprintf(out, "output lid balanced forwarding information\n"); 219 fprintf(out, 220 " [switchguid] -- limit results to specified switch guid\n"); 221 } 222 } 223 224 static void help_dump_conf(FILE *out, int detail) 225 { 226 fprintf(out, "dump_conf\n"); 227 if (detail) { 228 fprintf(out, "dump current opensm configuration\n"); 229 } 230 } 231 232 static void help_update_desc(FILE *out, int detail) 233 { 234 fprintf(out, "update_desc\n"); 235 if (detail) { 236 fprintf(out, "update node description for all nodes\n"); 237 } 238 } 239 240 #ifdef ENABLE_OSM_PERF_MGR 241 static void help_perfmgr(FILE * out, int detail) 242 { 243 fprintf(out, 244 "perfmgr(pm) [enable|disable\n" 245 " |clear_counters|dump_counters|print_counters(pc)|print_errors(pe)\n" 246 " |set_rm_nodes|clear_rm_nodes|clear_inactive\n" 247 " |set_query_cpi|clear_query_cpi\n" 248 " |dump_redir|clear_redir\n" 249 " |sweep|sweep_time[seconds]]\n"); 250 if (detail) { 251 fprintf(out, 252 "perfmgr -- print the performance manager state\n"); 253 fprintf(out, 254 " [enable|disable] -- change the perfmgr state\n"); 255 fprintf(out, 256 " [sweep] -- Initiate a sweep of the fabric\n"); 257 fprintf(out, 258 " [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n"); 259 fprintf(out, 260 " [clear_counters] -- clear the counters stored\n"); 261 fprintf(out, 262 " [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n"); 263 fprintf(out, 264 " [print_counters [<nodename|nodeguid>][:<port>]] -- print the internal counters\n" 265 " Optionally limit output by name, guid, or port\n"); 266 fprintf(out, 267 " [pc [<nodename|nodeguid>][:<port>]] -- same as print_counters\n"); 268 fprintf(out, 269 " [print_errors [<nodename|nodeguid>]] -- print only ports with errors\n" 270 " Optionally limit output by name or guid\n"); 271 fprintf(out, 272 " [pe [<nodename|nodeguid>]] -- same as print_errors\n"); 273 fprintf(out, 274 " [dump_redir [<nodename|nodeguid>]] -- dump the redirection table\n"); 275 fprintf(out, 276 " [clear_redir [<nodename|nodeguid>]] -- clear the redirection table\n"); 277 fprintf(out, 278 " [[set|clear]_rm_nodes] -- enable/disable the removal of \"inactive\" nodes from the DB\n" 279 " Inactive nodes are those which no longer appear on the fabric\n"); 280 fprintf(out, 281 " [[set|clear]_query_cpi] -- enable/disable PerfMgrGet(ClassPortInfo)\n" 282 " ClassPortInfo indicates hardware support for extended attributes such as PortCountersExtended\n"); 283 fprintf(out, 284 " [clear_inactive] -- Delete inactive nodes from the DB\n"); 285 } 286 } 287 static void help_pm(FILE *out, int detail) 288 { 289 if (detail) 290 help_perfmgr(out, detail); 291 } 292 #endif /* ENABLE_OSM_PERF_MGR */ 293 294 /* more help routines go here */ 295 296 static void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 297 { 298 char *p_cmd; 299 int i, found = 0; 300 301 p_cmd = next_token(p_last); 302 if (!p_cmd) 303 help_command(out, 0); 304 else { 305 for (i = 1; console_cmds[i].name; i++) { 306 if (!strcmp(p_cmd, console_cmds[i].name)) { 307 found = 1; 308 console_cmds[i].help_function(out, 1); 309 break; 310 } 311 } 312 if (!found) { 313 fprintf(out, "%s : Command not found\n\n", p_cmd); 314 help_command(out, 0); 315 } 316 } 317 } 318 319 static void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 320 { 321 char *p_cmd; 322 int level; 323 324 p_cmd = next_token(p_last); 325 if (!p_cmd) 326 fprintf(out, "Current log level is 0x%x\n", 327 osm_log_get_level(&p_osm->log)); 328 else { 329 /* Handle x, 0x, and decimal specification of log level */ 330 if (!strncmp(p_cmd, "x", 1)) { 331 p_cmd++; 332 level = strtoul(p_cmd, NULL, 16); 333 } else { 334 if (!strncmp(p_cmd, "0x", 2)) { 335 p_cmd += 2; 336 level = strtoul(p_cmd, NULL, 16); 337 } else 338 level = strtol(p_cmd, NULL, 10); 339 } 340 if ((level >= 0) && (level < 256)) { 341 fprintf(out, "Setting log level to 0x%x\n", level); 342 osm_log_set_level(&p_osm->log, level); 343 } else 344 fprintf(out, "Invalid log level 0x%x\n", level); 345 } 346 } 347 348 static void permodlog_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 349 { 350 FILE *fp; 351 char buf[1024]; 352 353 if (p_osm->subn.opt.per_module_logging_file != NULL) { 354 fp = fopen(p_osm->subn.opt.per_module_logging_file, "r"); 355 if (!fp) { 356 if (errno == ENOENT) 357 return; 358 fprintf(out, "fopen(%s) failed: %s\n", 359 p_osm->subn.opt.per_module_logging_file, 360 strerror(errno)); 361 return; 362 } 363 364 fprintf(out, "Per module logging file: %s\n", 365 p_osm->subn.opt.per_module_logging_file); 366 while (fgets(buf, sizeof buf, fp) != NULL) 367 fprintf(out, "%s", buf); 368 fclose(fp); 369 fprintf(out, "\n"); 370 } 371 } 372 373 static void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 374 { 375 char *p_cmd; 376 int priority; 377 378 p_cmd = next_token(p_last); 379 if (!p_cmd) 380 fprintf(out, "Current sm-priority is %d\n", 381 p_osm->subn.opt.sm_priority); 382 else { 383 priority = strtol(p_cmd, NULL, 0); 384 if (0 > priority || 15 < priority) 385 fprintf(out, 386 "Invalid sm-priority %d; must be between 0 and 15\n", 387 priority); 388 else { 389 fprintf(out, "Setting sm-priority to %d\n", priority); 390 osm_set_sm_priority(&p_osm->sm, (uint8_t)priority); 391 } 392 } 393 } 394 395 static const char *sm_state_str(int state) 396 { 397 switch (state) { 398 case IB_SMINFO_STATE_DISCOVERING: 399 return "Discovering"; 400 case IB_SMINFO_STATE_STANDBY: 401 return "Standby "; 402 case IB_SMINFO_STATE_NOTACTIVE: 403 return "Not Active "; 404 case IB_SMINFO_STATE_MASTER: 405 return "Master "; 406 } 407 return "UNKNOWN "; 408 } 409 410 static const char *sa_state_str(osm_sa_state_t state) 411 { 412 switch (state) { 413 case OSM_SA_STATE_INIT: 414 return "Init"; 415 case OSM_SA_STATE_READY: 416 return "Ready"; 417 } 418 return "UNKNOWN"; 419 } 420 421 static void dump_sms(osm_opensm_t * p_osm, FILE * out) 422 { 423 osm_subn_t *p_subn = &p_osm->subn; 424 osm_remote_sm_t *p_rsm; 425 426 fprintf(out, "\n Known SMs\n" 427 " ---------\n"); 428 fprintf(out, " Port GUID SM State Priority\n"); 429 fprintf(out, " --------- -------- --------\n"); 430 fprintf(out, " 0x%" PRIx64 " %s %d SELF\n", 431 cl_ntoh64(p_subn->sm_port_guid), 432 sm_state_str(p_subn->sm_state), 433 p_subn->opt.sm_priority); 434 435 CL_PLOCK_ACQUIRE(p_osm->sm.p_lock); 436 p_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl); 437 while (p_rsm != (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) { 438 fprintf(out, " 0x%" PRIx64 " %s %d\n", 439 cl_ntoh64(p_rsm->smi.guid), 440 sm_state_str(ib_sminfo_get_state(&p_rsm->smi)), 441 ib_sminfo_get_priority(&p_rsm->smi)); 442 p_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item); 443 } 444 CL_PLOCK_RELEASE(p_osm->sm.p_lock); 445 } 446 447 static void print_status(osm_opensm_t * p_osm, FILE * out) 448 { 449 cl_list_item_t *item; 450 451 if (out) { 452 const char *re_str; 453 454 cl_plock_acquire(&p_osm->lock); 455 fprintf(out, " OpenSM Version : %s\n", p_osm->osm_version); 456 fprintf(out, " SM State : %s\n", 457 sm_state_str(p_osm->subn.sm_state)); 458 fprintf(out, " SM Priority : %d\n", 459 p_osm->subn.opt.sm_priority); 460 fprintf(out, " SA State : %s\n", 461 sa_state_str(p_osm->sa.state)); 462 463 re_str = p_osm->routing_engine_used ? 464 osm_routing_engine_type_str(p_osm->routing_engine_used->type) : 465 osm_routing_engine_type_str(OSM_ROUTING_ENGINE_TYPE_NONE); 466 fprintf(out, " Routing Engine : %s\n", re_str); 467 468 fprintf(out, " Loaded event plugins :"); 469 if (cl_qlist_head(&p_osm->plugin_list) == 470 cl_qlist_end(&p_osm->plugin_list)) { 471 fprintf(out, " <none>"); 472 } 473 for (item = cl_qlist_head(&p_osm->plugin_list); 474 item != cl_qlist_end(&p_osm->plugin_list); 475 item = cl_qlist_next(item)) 476 fprintf(out, " %s", 477 ((osm_epi_plugin_t *)item)->plugin_name); 478 fprintf(out, "\n"); 479 480 #ifdef ENABLE_OSM_PERF_MGR 481 fprintf(out, "\n PerfMgr state/sweep state : %s/%s\n", 482 osm_perfmgr_get_state_str(&p_osm->perfmgr), 483 osm_perfmgr_get_sweep_state_str(&p_osm->perfmgr)); 484 #endif 485 fprintf(out, "\n MAD stats\n" 486 " ---------\n" 487 " QP0 MADs outstanding : %u\n" 488 " QP0 MADs outstanding (on wire) : %u\n" 489 " QP0 MADs rcvd : %u\n" 490 " QP0 MADs sent : %u\n" 491 " QP0 unicasts sent : %u\n" 492 " QP0 unknown MADs rcvd : %u\n" 493 " SA MADs outstanding : %u\n" 494 " SA MADs rcvd : %u\n" 495 " SA MADs sent : %u\n" 496 " SA unknown MADs rcvd : %u\n" 497 " SA MADs ignored : %u\n", 498 (uint32_t)p_osm->stats.qp0_mads_outstanding, 499 (uint32_t)p_osm->stats.qp0_mads_outstanding_on_wire, 500 (uint32_t)p_osm->stats.qp0_mads_rcvd, 501 (uint32_t)p_osm->stats.qp0_mads_sent, 502 (uint32_t)p_osm->stats.qp0_unicasts_sent, 503 (uint32_t)p_osm->stats.qp0_mads_rcvd_unknown, 504 (uint32_t)p_osm->stats.sa_mads_outstanding, 505 (uint32_t)p_osm->stats.sa_mads_rcvd, 506 (uint32_t)p_osm->stats.sa_mads_sent, 507 (uint32_t)p_osm->stats.sa_mads_rcvd_unknown, 508 (uint32_t)p_osm->stats.sa_mads_ignored); 509 fprintf(out, "\n Subnet flags\n" 510 " ------------\n" 511 " Sweeping enabled : %d\n" 512 " Sweep interval (seconds) : %u\n" 513 " Ignore existing lfts : %d\n" 514 " Subnet Init errors : %d\n" 515 " In sweep hop 0 : %d\n" 516 " First time master sweep : %d\n" 517 " Coming out of standby : %d\n", 518 p_osm->subn.sweeping_enabled, 519 p_osm->subn.opt.sweep_interval, 520 p_osm->subn.ignore_existing_lfts, 521 p_osm->subn.subnet_initialization_error, 522 p_osm->subn.in_sweep_hop_0, 523 p_osm->subn.first_time_master_sweep, 524 p_osm->subn.coming_out_of_standby); 525 dump_sms(p_osm, out); 526 fprintf(out, "\n"); 527 cl_plock_release(&p_osm->lock); 528 } 529 } 530 531 static int loop_command_check_time(void) 532 { 533 time_t cur = time(NULL); 534 if ((loop_command.previous + loop_command.delay_s) < cur) { 535 loop_command.previous = cur; 536 return 1; 537 } 538 return 0; 539 } 540 541 static void status_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 542 { 543 char *p_cmd; 544 545 p_cmd = next_token(p_last); 546 if (p_cmd) { 547 if (strcmp(p_cmd, "loop") == 0) { 548 fprintf(out, "Looping on status command...\n"); 549 fflush(out); 550 loop_command.on = 1; 551 loop_command.previous = time(NULL); 552 loop_command.loop_function = print_status; 553 } else { 554 help_status(out, 1); 555 return; 556 } 557 } 558 print_status(p_osm, out); 559 } 560 561 static void resweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 562 { 563 char *p_cmd; 564 565 p_cmd = next_token(p_last); 566 if (!p_cmd || 567 (strcmp(p_cmd, "heavy") != 0 && strcmp(p_cmd, "light") != 0)) { 568 fprintf(out, "Invalid resweep command\n"); 569 help_resweep(out, 1); 570 } else { 571 if (strcmp(p_cmd, "heavy") == 0) 572 p_osm->subn.force_heavy_sweep = TRUE; 573 osm_opensm_sweep(p_osm); 574 } 575 } 576 577 static void reroute_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 578 { 579 p_osm->subn.force_reroute = TRUE; 580 osm_opensm_sweep(p_osm); 581 } 582 583 static void sweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 584 { 585 char *p_cmd; 586 587 p_cmd = next_token(p_last); 588 if (!p_cmd || 589 (strcmp(p_cmd, "on") != 0 && strcmp(p_cmd, "off") != 0)) { 590 fprintf(out, "Invalid sweep command\n"); 591 help_sweep(out, 1); 592 } else { 593 if (strcmp(p_cmd, "on") == 0) 594 p_osm->subn.sweeping_enabled = TRUE; 595 else 596 p_osm->subn.sweeping_enabled = FALSE; 597 } 598 } 599 600 static void logflush_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 601 { 602 char *p_cmd; 603 604 p_cmd = next_token(p_last); 605 if (!p_cmd || 606 (strcmp(p_cmd, "on") != 0 && strcmp(p_cmd, "off") != 0)) { 607 fprintf(out, "Invalid logflush command\n"); 608 help_sweep(out, 1); 609 } else { 610 if (strcmp(p_cmd, "on") == 0) { 611 p_osm->log.flush = TRUE; 612 fflush(p_osm->log.out_port); 613 } else 614 p_osm->log.flush = FALSE; 615 } 616 } 617 618 static void querylid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 619 { 620 unsigned int p = 0; 621 uint16_t lid = 0; 622 osm_port_t *p_port = NULL; 623 char *p_cmd = next_token(p_last); 624 625 if (!p_cmd) { 626 fprintf(out, "no LID specified\n"); 627 help_querylid(out, 1); 628 return; 629 } 630 631 lid = (uint16_t) strtoul(p_cmd, NULL, 0); 632 cl_plock_acquire(&p_osm->lock); 633 p_port = osm_get_port_by_lid_ho(&p_osm->subn, lid); 634 if (!p_port) 635 goto invalid_lid; 636 637 fprintf(out, "Query results for LID %u\n", lid); 638 fprintf(out, 639 " GUID : 0x%016" PRIx64 "\n" 640 " Node Desc : %s\n" 641 " Node Type : %s\n" 642 " Num Ports : %d\n", 643 cl_ntoh64(p_port->guid), 644 p_port->p_node->print_desc, 645 ib_get_node_type_str(osm_node_get_type(p_port->p_node)), 646 p_port->p_node->node_info.num_ports); 647 648 if (p_port->p_node->sw) 649 p = 0; 650 else 651 p = 1; 652 for ( /* see above */ ; p < p_port->p_node->physp_tbl_size; p++) { 653 fprintf(out, 654 " Port %u health : %s\n", 655 p, 656 p_port->p_node->physp_table[p]. 657 healthy ? "OK" : "ERROR"); 658 } 659 660 cl_plock_release(&p_osm->lock); 661 return; 662 663 invalid_lid: 664 cl_plock_release(&p_osm->lock); 665 fprintf(out, "Invalid lid %d\n", lid); 666 return; 667 } 668 669 /** 670 * Data structures for the portstatus command 671 */ 672 typedef struct _port_report { 673 struct _port_report *next; 674 uint64_t node_guid; 675 uint8_t port_num; 676 char print_desc[IB_NODE_DESCRIPTION_SIZE + 1]; 677 } port_report_t; 678 679 static void 680 __tag_port_report(port_report_t ** head, uint64_t node_guid, 681 uint8_t port_num, char *print_desc) 682 { 683 port_report_t *rep = malloc(sizeof(*rep)); 684 if (!rep) 685 return; 686 687 rep->node_guid = node_guid; 688 rep->port_num = port_num; 689 memcpy(rep->print_desc, print_desc, IB_NODE_DESCRIPTION_SIZE + 1); 690 rep->next = NULL; 691 if (*head) { 692 rep->next = *head; 693 *head = rep; 694 } else 695 *head = rep; 696 } 697 698 static void __print_port_report(FILE * out, port_report_t * head) 699 { 700 port_report_t *item = head; 701 while (item != NULL) { 702 fprintf(out, " 0x%016" PRIx64 " %d (%s)\n", 703 item->node_guid, item->port_num, item->print_desc); 704 port_report_t *next = item->next; 705 free(item); 706 item = next; 707 } 708 } 709 710 typedef struct { 711 uint8_t node_type_lim; /* limit the results; 0 == ALL */ 712 uint64_t total_nodes; 713 uint64_t total_ports; 714 uint64_t ports_down; 715 uint64_t ports_active; 716 uint64_t ports_disabled; 717 port_report_t *disabled_ports; 718 uint64_t ports_1X; 719 uint64_t ports_4X; 720 uint64_t ports_8X; 721 uint64_t ports_12X; 722 uint64_t ports_2X; 723 uint64_t ports_unknown_width; 724 port_report_t *unknown_width_ports; 725 uint64_t ports_unenabled_width; 726 port_report_t *unenabled_width_ports; 727 uint64_t ports_reduced_width; 728 port_report_t *reduced_width_ports; 729 uint64_t ports_sdr; 730 uint64_t ports_ddr; 731 uint64_t ports_qdr; 732 uint64_t ports_fdr10; 733 uint64_t ports_fdr; 734 uint64_t ports_edr; 735 uint64_t ports_unknown_speed; 736 port_report_t *unknown_speed_ports; 737 uint64_t ports_unenabled_speed; 738 port_report_t *unenabled_speed_ports; 739 uint64_t ports_reduced_speed; 740 port_report_t *reduced_speed_ports; 741 } fabric_stats_t; 742 743 /** 744 * iterator function to get portstatus on each node 745 */ 746 static void __get_stats(cl_map_item_t * const p_map_item, void *context) 747 { 748 fabric_stats_t *fs = (fabric_stats_t *) context; 749 osm_node_t *node = (osm_node_t *) p_map_item; 750 osm_physp_t *physp0; 751 ib_port_info_t *pi0; 752 uint8_t num_ports = osm_node_get_num_physp(node); 753 uint8_t port = 0; 754 755 /* Skip nodes we are not interested in */ 756 if (fs->node_type_lim != 0 757 && fs->node_type_lim != node->node_info.node_type) 758 return; 759 760 fs->total_nodes++; 761 762 if (osm_node_get_type(node) == IB_NODE_TYPE_SWITCH) { 763 physp0 = osm_node_get_physp_ptr(node, 0); 764 pi0 = &physp0->port_info; 765 } else 766 pi0 = NULL; 767 768 for (port = 1; port < num_ports; port++) { 769 osm_physp_t *phys = osm_node_get_physp_ptr(node, port); 770 ib_port_info_t *pi = NULL; 771 ib_mlnx_ext_port_info_t *epi = NULL; 772 uint8_t active_speed = 0; 773 uint8_t enabled_speed = 0; 774 uint8_t active_width = 0; 775 uint8_t enabled_width = 0; 776 uint8_t port_state = 0; 777 uint8_t port_phys_state = 0; 778 779 if (!phys) 780 continue; 781 782 pi = &phys->port_info; 783 epi = &phys->ext_port_info; 784 if (!pi0) 785 pi0 = pi; 786 active_speed = ib_port_info_get_link_speed_active(pi); 787 enabled_speed = ib_port_info_get_link_speed_enabled(pi); 788 active_width = pi->link_width_active; 789 enabled_width = pi->link_width_enabled; 790 port_state = ib_port_info_get_port_state(pi); 791 port_phys_state = ib_port_info_get_port_phys_state(pi); 792 793 if (port_state == IB_LINK_DOWN) 794 fs->ports_down++; 795 else if (port_state == IB_LINK_ACTIVE) 796 fs->ports_active++; 797 if (port_phys_state == IB_PORT_PHYS_STATE_DISABLED) { 798 __tag_port_report(&(fs->disabled_ports), 799 cl_ntoh64(node->node_info.node_guid), 800 port, node->print_desc); 801 fs->ports_disabled++; 802 } 803 804 fs->total_ports++; 805 806 if (port_state == IB_LINK_DOWN) 807 continue; 808 809 if (!(active_width & enabled_width)) { 810 __tag_port_report(&(fs->unenabled_width_ports), 811 cl_ntoh64(node->node_info.node_guid), 812 port, node->print_desc); 813 fs->ports_unenabled_width++; 814 } 815 else if ((enabled_width ^ active_width) > active_width) { 816 __tag_port_report(&(fs->reduced_width_ports), 817 cl_ntoh64(node->node_info.node_guid), 818 port, node->print_desc); 819 fs->ports_reduced_width++; 820 } 821 822 /* unenabled speed usually due to problems with force_link_speed */ 823 if (!(active_speed & enabled_speed)) { 824 __tag_port_report(&(fs->unenabled_speed_ports), 825 cl_ntoh64(node->node_info.node_guid), 826 port, node->print_desc); 827 fs->ports_unenabled_speed++; 828 } 829 else if ((enabled_speed ^ active_speed) > active_speed) { 830 __tag_port_report(&(fs->reduced_speed_ports), 831 cl_ntoh64(node->node_info.node_guid), 832 port, node->print_desc); 833 fs->ports_reduced_speed++; 834 } 835 836 switch (active_speed) { 837 case IB_LINK_SPEED_ACTIVE_2_5: 838 fs->ports_sdr++; 839 break; 840 case IB_LINK_SPEED_ACTIVE_5: 841 fs->ports_ddr++; 842 break; 843 case IB_LINK_SPEED_ACTIVE_10: 844 if (!(pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) || 845 !ib_port_info_get_link_speed_ext_active(pi)) { 846 if (epi->link_speed_active & FDR10) 847 fs->ports_fdr10++; 848 else { 849 fs->ports_qdr++; 850 /* check for speed reduced from FDR10 */ 851 if (epi->link_speed_enabled & FDR10) { 852 __tag_port_report(&(fs->reduced_speed_ports), 853 cl_ntoh64(node->node_info.node_guid), 854 port, node->print_desc); 855 fs->ports_reduced_speed++; 856 } 857 } 858 } 859 break; 860 case IB_LINK_SPEED_ACTIVE_EXTENDED: 861 break; 862 default: 863 __tag_port_report(&(fs->unknown_speed_ports), 864 cl_ntoh64(node->node_info.node_guid), 865 port, node->print_desc); 866 fs->ports_unknown_speed++; 867 break; 868 } 869 if (pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS && 870 ib_port_info_get_link_speed_ext_sup(pi) && 871 (enabled_speed = ib_port_info_get_link_speed_ext_enabled(pi)) != IB_LINK_SPEED_EXT_DISABLE && 872 active_speed == IB_LINK_SPEED_ACTIVE_10) { 873 active_speed = ib_port_info_get_link_speed_ext_active(pi); 874 if (!(active_speed & enabled_speed)) { 875 __tag_port_report(&(fs->unenabled_speed_ports), 876 cl_ntoh64(node->node_info.node_guid), 877 port, node->print_desc); 878 fs->ports_unenabled_speed++; 879 } 880 else if ((enabled_speed ^ active_speed) > active_speed) { 881 __tag_port_report(&(fs->reduced_speed_ports), 882 cl_ntoh64(node->node_info.node_guid), 883 port, node->print_desc); 884 fs->ports_reduced_speed++; 885 } 886 switch (active_speed) { 887 case IB_LINK_SPEED_EXT_ACTIVE_14: 888 fs->ports_fdr++; 889 break; 890 case IB_LINK_SPEED_EXT_ACTIVE_25: 891 fs->ports_edr++; 892 break; 893 case IB_LINK_SPEED_EXT_ACTIVE_NONE: 894 break; 895 default: 896 __tag_port_report(&(fs->unknown_speed_ports), 897 cl_ntoh64(node->node_info.node_guid), 898 port, node->print_desc); 899 fs->ports_unknown_speed++; 900 break; 901 } 902 } 903 switch (active_width) { 904 case IB_LINK_WIDTH_ACTIVE_1X: 905 fs->ports_1X++; 906 break; 907 case IB_LINK_WIDTH_ACTIVE_4X: 908 fs->ports_4X++; 909 break; 910 case IB_LINK_WIDTH_ACTIVE_8X: 911 fs->ports_8X++; 912 break; 913 case IB_LINK_WIDTH_ACTIVE_12X: 914 fs->ports_12X++; 915 break; 916 case IB_LINK_WIDTH_ACTIVE_2X: 917 fs->ports_2X++; 918 break; 919 default: 920 __tag_port_report(&(fs->unknown_width_ports), 921 cl_ntoh64(node->node_info.node_guid), 922 port, node->print_desc); 923 fs->ports_unknown_width++; 924 break; 925 } 926 } 927 } 928 929 static void portstatus_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 930 { 931 fabric_stats_t fs; 932 struct timeval before, after; 933 char *p_cmd; 934 935 memset(&fs, 0, sizeof(fs)); 936 937 p_cmd = next_token(p_last); 938 if (p_cmd) { 939 if (strcmp(p_cmd, "ca") == 0) { 940 fs.node_type_lim = IB_NODE_TYPE_CA; 941 } else if (strcmp(p_cmd, "switch") == 0) { 942 fs.node_type_lim = IB_NODE_TYPE_SWITCH; 943 } else if (strcmp(p_cmd, "router") == 0) { 944 fs.node_type_lim = IB_NODE_TYPE_ROUTER; 945 } else { 946 fprintf(out, "Node type not understood\n"); 947 help_portstatus(out, 1); 948 return; 949 } 950 } 951 952 gettimeofday(&before, NULL); 953 954 /* for each node in the system gather the stats */ 955 cl_plock_acquire(&p_osm->lock); 956 cl_qmap_apply_func(&(p_osm->subn.node_guid_tbl), __get_stats, 957 (void *)&fs); 958 cl_plock_release(&p_osm->lock); 959 960 gettimeofday(&after, NULL); 961 962 /* report the stats */ 963 fprintf(out, "\"%s\" port status:\n", 964 fs.node_type_lim ? ib_get_node_type_str(fs. 965 node_type_lim) : "ALL"); 966 fprintf(out, 967 " %" PRIu64 " port(s) scanned on %" PRIu64 968 " nodes in %lu us\n", fs.total_ports, fs.total_nodes, 969 after.tv_usec - before.tv_usec); 970 971 if (fs.ports_down) 972 fprintf(out, " %" PRIu64 " down\n", fs.ports_down); 973 if (fs.ports_active) 974 fprintf(out, " %" PRIu64 " active\n", fs.ports_active); 975 if (fs.ports_1X) 976 fprintf(out, " %" PRIu64 " at 1X\n", fs.ports_1X); 977 if (fs.ports_4X) 978 fprintf(out, " %" PRIu64 " at 4X\n", fs.ports_4X); 979 if (fs.ports_8X) 980 fprintf(out, " %" PRIu64 " at 8X\n", fs.ports_8X); 981 if (fs.ports_12X) 982 fprintf(out, " %" PRIu64 " at 12X\n", fs.ports_12X); 983 984 if (fs.ports_sdr) 985 fprintf(out, " %" PRIu64 " at 2.5 Gbps\n", fs.ports_sdr); 986 if (fs.ports_ddr) 987 fprintf(out, " %" PRIu64 " at 5.0 Gbps\n", fs.ports_ddr); 988 if (fs.ports_qdr) 989 fprintf(out, " %" PRIu64 " at 10.0 Gbps\n", fs.ports_qdr); 990 if (fs.ports_fdr10) 991 fprintf(out, " %" PRIu64 " at 10.0 Gbps (FDR10)\n", fs.ports_fdr10); 992 if (fs.ports_fdr) 993 fprintf(out, " %" PRIu64 " at 14.0625 Gbps\n", fs.ports_fdr); 994 if (fs.ports_edr) 995 fprintf(out, " %" PRIu64 " at 25.78125 Gbps\n", fs.ports_edr); 996 997 if (fs.ports_disabled + fs.ports_reduced_speed + fs.ports_reduced_width 998 + fs.ports_unenabled_width + fs.ports_unenabled_speed 999 + fs.ports_unknown_width + fs.ports_unknown_speed > 0) { 1000 fprintf(out, "\nPossible issues:\n"); 1001 } 1002 if (fs.ports_disabled) { 1003 fprintf(out, " %" PRIu64 " disabled\n", fs.ports_disabled); 1004 __print_port_report(out, fs.disabled_ports); 1005 } 1006 if (fs.ports_unenabled_speed) { 1007 fprintf(out, " %" PRIu64 " with unenabled speed\n", 1008 fs.ports_unenabled_speed); 1009 __print_port_report(out, fs.unenabled_speed_ports); 1010 } 1011 if (fs.ports_reduced_speed) { 1012 fprintf(out, " %" PRIu64 " with reduced speed\n", 1013 fs.ports_reduced_speed); 1014 __print_port_report(out, fs.reduced_speed_ports); 1015 } 1016 if (fs.ports_unknown_speed) { 1017 fprintf(out, " %" PRIu64 " with unknown speed\n", 1018 fs.ports_unknown_speed); 1019 __print_port_report(out, fs.unknown_speed_ports); 1020 } 1021 if (fs.ports_unenabled_width) { 1022 fprintf(out, " %" PRIu64 " with unenabled width\n", 1023 fs.ports_unenabled_width); 1024 __print_port_report(out, fs.unenabled_width_ports); 1025 } 1026 if (fs.ports_reduced_width) { 1027 fprintf(out, " %" PRIu64 " with reduced width\n", 1028 fs.ports_reduced_width); 1029 __print_port_report(out, fs.reduced_width_ports); 1030 } 1031 if (fs.ports_unknown_width) { 1032 fprintf(out, " %" PRIu64 " with unknown width\n", 1033 fs.ports_unknown_width); 1034 __print_port_report(out, fs.unknown_width_ports); 1035 } 1036 fprintf(out, "\n"); 1037 } 1038 1039 static void switchbalance_check(osm_opensm_t * p_osm, 1040 osm_switch_t * p_sw, FILE * out, int verbose) 1041 { 1042 uint8_t port_num; 1043 uint8_t num_ports; 1044 const cl_qmap_t *p_port_tbl; 1045 osm_port_t *p_port; 1046 osm_physp_t *p_physp; 1047 osm_physp_t *p_rem_physp; 1048 osm_node_t *p_rem_node; 1049 uint32_t count[255]; /* max ports is a uint8_t */ 1050 uint8_t output_ports[255]; 1051 uint8_t output_ports_count = 0; 1052 uint32_t min_count = 0xFFFFFFFF; 1053 uint32_t max_count = 0; 1054 unsigned int i; 1055 1056 memset(count, '\0', sizeof(uint32_t) * 255); 1057 1058 /* Count port usage */ 1059 p_port_tbl = &p_osm->subn.port_guid_tbl; 1060 for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); 1061 p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); 1062 p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { 1063 uint16_t min_lid_ho; 1064 uint16_t max_lid_ho; 1065 uint16_t lid_ho; 1066 1067 /* Don't count switches in port usage */ 1068 if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) 1069 continue; 1070 1071 osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 1072 1073 if (min_lid_ho == 0 || max_lid_ho == 0) 1074 continue; 1075 1076 for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { 1077 port_num = osm_switch_get_port_by_lid(p_sw, lid_ho, 1078 OSM_NEW_LFT); 1079 if (port_num == OSM_NO_PATH) 1080 continue; 1081 1082 count[port_num]++; 1083 } 1084 } 1085 1086 num_ports = p_sw->num_ports; 1087 for (port_num = 1; port_num < num_ports; port_num++) { 1088 p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); 1089 1090 /* if port is down/unhealthy, don't consider it in 1091 * min/max calculations 1092 */ 1093 if (!p_physp || !osm_physp_is_healthy(p_physp) 1094 || !osm_physp_get_remote(p_physp)) 1095 continue; 1096 1097 p_rem_physp = osm_physp_get_remote(p_physp); 1098 p_rem_node = osm_physp_get_node_ptr(p_rem_physp); 1099 1100 /* If we are directly connected to a CA/router, its not really 1101 * up for balancing consideration. 1102 */ 1103 if (osm_node_get_type(p_rem_node) != IB_NODE_TYPE_SWITCH) 1104 continue; 1105 1106 output_ports[output_ports_count] = port_num; 1107 output_ports_count++; 1108 1109 if (count[port_num] < min_count) 1110 min_count = count[port_num]; 1111 if (count[port_num] > max_count) 1112 max_count = count[port_num]; 1113 } 1114 1115 if (verbose || ((max_count - min_count) > 1)) { 1116 if ((max_count - min_count) > 1) 1117 fprintf(out, 1118 "Unbalanced Switch: 0x%016" PRIx64 " (%s)\n", 1119 cl_ntoh64(p_sw->p_node->node_info.node_guid), 1120 p_sw->p_node->print_desc); 1121 else 1122 fprintf(out, 1123 "Switch: 0x%016" PRIx64 " (%s)\n", 1124 cl_ntoh64(p_sw->p_node->node_info.node_guid), 1125 p_sw->p_node->print_desc); 1126 1127 for (i = 0; i < output_ports_count; i++) { 1128 fprintf(out, 1129 "Port %d: %d\n", 1130 output_ports[i], count[output_ports[i]]); 1131 } 1132 } 1133 } 1134 1135 static void switchbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1136 { 1137 char *p_cmd; 1138 uint64_t guid = 0; 1139 osm_switch_t *p_sw; 1140 int verbose = 0; 1141 1142 p_cmd = next_token(p_last); 1143 if (p_cmd) { 1144 char *p_end; 1145 1146 if (strcmp(p_cmd, "verbose") == 0) { 1147 verbose++; 1148 p_cmd = next_token(p_last); 1149 } 1150 1151 if (p_cmd) { 1152 guid = strtoull(p_cmd, &p_end, 0); 1153 if (!guid || *p_end != '\0') { 1154 fprintf(out, "Invalid guid specified\n"); 1155 help_switchbalance(out, 1); 1156 return; 1157 } 1158 } 1159 } 1160 1161 cl_plock_acquire(&p_osm->lock); 1162 if (guid) { 1163 p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); 1164 if (!p_sw) { 1165 fprintf(out, "guid not found\n"); 1166 goto lock_exit; 1167 } 1168 1169 switchbalance_check(p_osm, p_sw, out, verbose); 1170 } else { 1171 cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; 1172 for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); 1173 p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); 1174 p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) 1175 switchbalance_check(p_osm, p_sw, out, verbose); 1176 } 1177 lock_exit: 1178 cl_plock_release(&p_osm->lock); 1179 return; 1180 } 1181 1182 static void lidbalance_check(osm_opensm_t * p_osm, 1183 osm_switch_t * p_sw, FILE * out) 1184 { 1185 uint8_t port_num; 1186 const cl_qmap_t *p_port_tbl; 1187 osm_port_t *p_port; 1188 1189 p_port_tbl = &p_osm->subn.port_guid_tbl; 1190 for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); 1191 p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); 1192 p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { 1193 uint32_t port_count[255]; /* max ports is a uint8_t */ 1194 osm_node_t *rem_node[255]; 1195 uint32_t rem_node_count; 1196 uint32_t rem_count[255]; 1197 osm_physp_t *p_physp; 1198 osm_physp_t *p_rem_physp; 1199 osm_node_t *p_rem_node; 1200 uint32_t port_min_count = 0xFFFFFFFF; 1201 uint32_t port_max_count = 0; 1202 uint32_t rem_min_count = 0xFFFFFFFF; 1203 uint32_t rem_max_count = 0; 1204 uint16_t min_lid_ho; 1205 uint16_t max_lid_ho; 1206 uint16_t lid_ho; 1207 uint8_t num_ports; 1208 unsigned int i; 1209 1210 /* we only care about non-switches */ 1211 if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) 1212 continue; 1213 1214 osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 1215 1216 if (min_lid_ho == 0 || max_lid_ho == 0) 1217 continue; 1218 1219 memset(port_count, '\0', sizeof(uint32_t) * 255); 1220 memset(rem_node, '\0', sizeof(osm_node_t *) * 255); 1221 rem_node_count = 0; 1222 memset(rem_count, '\0', sizeof(uint32_t) * 255); 1223 1224 for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { 1225 boolean_t rem_node_found = FALSE; 1226 unsigned int indx = 0; 1227 1228 port_num = osm_switch_get_port_by_lid(p_sw, lid_ho, 1229 OSM_NEW_LFT); 1230 if (port_num == OSM_NO_PATH) 1231 continue; 1232 1233 p_physp = 1234 osm_node_get_physp_ptr(p_sw->p_node, port_num); 1235 1236 /* if port is down/unhealthy, can't calculate */ 1237 if (!p_physp || !osm_physp_is_healthy(p_physp) 1238 || !osm_physp_get_remote(p_physp)) 1239 continue; 1240 1241 p_rem_physp = osm_physp_get_remote(p_physp); 1242 p_rem_node = osm_physp_get_node_ptr(p_rem_physp); 1243 1244 /* determine if we've seen this remote node before. 1245 * If not, store it. If yes, update the counter 1246 */ 1247 for (i = 0; i < rem_node_count; i++) { 1248 if (rem_node[i] == p_rem_node) { 1249 rem_node_found = TRUE; 1250 indx = i; 1251 break; 1252 } 1253 } 1254 1255 if (!rem_node_found) { 1256 rem_node[rem_node_count] = p_rem_node; 1257 rem_count[rem_node_count]++; 1258 indx = rem_node_count; 1259 rem_node_count++; 1260 } else 1261 rem_count[indx]++; 1262 1263 port_count[port_num]++; 1264 } 1265 1266 if (!rem_node_count) 1267 continue; 1268 1269 for (i = 0; i < rem_node_count; i++) { 1270 if (rem_count[i] < rem_min_count) 1271 rem_min_count = rem_count[i]; 1272 if (rem_count[i] > rem_max_count) 1273 rem_max_count = rem_count[i]; 1274 } 1275 1276 num_ports = p_sw->num_ports; 1277 for (i = 0; i < num_ports; i++) { 1278 if (!port_count[i]) 1279 continue; 1280 if (port_count[i] < port_min_count) 1281 port_min_count = port_count[i]; 1282 if (port_count[i] > port_max_count) 1283 port_max_count = port_count[i]; 1284 } 1285 1286 /* Output if this CA/router is being forwarded an unbalanced number of 1287 * times to a destination. 1288 */ 1289 if ((rem_max_count - rem_min_count) > 1) { 1290 fprintf(out, 1291 "Unbalanced Remote Forwarding: Switch 0x%016" 1292 PRIx64 " (%s): ", 1293 cl_ntoh64(p_sw->p_node->node_info.node_guid), 1294 p_sw->p_node->print_desc); 1295 if (osm_node_get_type(p_port->p_node) == 1296 IB_NODE_TYPE_CA) 1297 fprintf(out, "CA"); 1298 else if (osm_node_get_type(p_port->p_node) == 1299 IB_NODE_TYPE_ROUTER) 1300 fprintf(out, "Router"); 1301 fprintf(out, " 0x%016" PRIx64 " (%s): ", 1302 cl_ntoh64(p_port->p_node->node_info.node_guid), 1303 p_port->p_node->print_desc); 1304 for (i = 0; i < rem_node_count; i++) { 1305 fprintf(out, 1306 "Dest 0x%016" PRIx64 "(%s) - %u ", 1307 cl_ntoh64(rem_node[i]->node_info. 1308 node_guid), 1309 rem_node[i]->print_desc, rem_count[i]); 1310 } 1311 fprintf(out, "\n"); 1312 } 1313 1314 /* Output if this CA/router is being forwarded through a port 1315 * an unbalanced number of times. 1316 */ 1317 if ((port_max_count - port_min_count) > 1) { 1318 fprintf(out, 1319 "Unbalanced Port Forwarding: Switch 0x%016" 1320 PRIx64 " (%s): ", 1321 cl_ntoh64(p_sw->p_node->node_info.node_guid), 1322 p_sw->p_node->print_desc); 1323 if (osm_node_get_type(p_port->p_node) == 1324 IB_NODE_TYPE_CA) 1325 fprintf(out, "CA"); 1326 else if (osm_node_get_type(p_port->p_node) == 1327 IB_NODE_TYPE_ROUTER) 1328 fprintf(out, "Router"); 1329 fprintf(out, " 0x%016" PRIx64 " (%s): ", 1330 cl_ntoh64(p_port->p_node->node_info.node_guid), 1331 p_port->p_node->print_desc); 1332 for (i = 0; i < num_ports; i++) { 1333 if (!port_count[i]) 1334 continue; 1335 fprintf(out, "Port %u - %u: ", i, 1336 port_count[i]); 1337 } 1338 fprintf(out, "\n"); 1339 } 1340 } 1341 } 1342 1343 static void lidbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1344 { 1345 char *p_cmd; 1346 uint64_t guid = 0; 1347 osm_switch_t *p_sw; 1348 1349 p_cmd = next_token(p_last); 1350 if (p_cmd) { 1351 char *p_end; 1352 1353 guid = strtoull(p_cmd, &p_end, 0); 1354 if (!guid || *p_end != '\0') { 1355 fprintf(out, "Invalid switchguid specified\n"); 1356 help_lidbalance(out, 1); 1357 return; 1358 } 1359 } 1360 1361 cl_plock_acquire(&p_osm->lock); 1362 if (guid) { 1363 p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); 1364 if (!p_sw) { 1365 fprintf(out, "switchguid not found\n"); 1366 goto lock_exit; 1367 } 1368 lidbalance_check(p_osm, p_sw, out); 1369 } else { 1370 cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; 1371 for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); 1372 p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); 1373 p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) 1374 lidbalance_check(p_osm, p_sw, out); 1375 } 1376 1377 lock_exit: 1378 cl_plock_release(&p_osm->lock); 1379 return; 1380 } 1381 1382 static void dump_conf_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1383 { 1384 osm_subn_output_conf(out, &p_osm->subn.opt); 1385 } 1386 1387 static void update_desc_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1388 { 1389 osm_update_node_desc(p_osm); 1390 } 1391 1392 #ifdef ENABLE_OSM_PERF_MGR 1393 static monitored_node_t *find_node_by_name(osm_opensm_t * p_osm, 1394 char *nodename) 1395 { 1396 cl_map_item_t *item; 1397 monitored_node_t *node; 1398 1399 item = cl_qmap_head(&p_osm->perfmgr.monitored_map); 1400 while (item != cl_qmap_end(&p_osm->perfmgr.monitored_map)) { 1401 node = (monitored_node_t *)item; 1402 if (strcmp(node->name, nodename) == 0) 1403 return node; 1404 item = cl_qmap_next(item); 1405 } 1406 1407 return NULL; 1408 } 1409 1410 static monitored_node_t *find_node_by_guid(osm_opensm_t * p_osm, 1411 uint64_t guid) 1412 { 1413 cl_map_item_t *node; 1414 1415 node = cl_qmap_get(&p_osm->perfmgr.monitored_map, guid); 1416 if (node != cl_qmap_end(&p_osm->perfmgr.monitored_map)) 1417 return (monitored_node_t *)node; 1418 1419 return NULL; 1420 } 1421 1422 static void dump_redir_entry(monitored_node_t *p_mon_node, FILE * out) 1423 { 1424 int port, redir; 1425 1426 /* only display monitored nodes with redirection info */ 1427 redir = 0; 1428 for (port = (p_mon_node->esp0) ? 0 : 1; 1429 port < p_mon_node->num_ports; port++) { 1430 if (p_mon_node->port[port].redirection) { 1431 if (!redir) { 1432 fprintf(out, " Node GUID ESP0 Name\n"); 1433 fprintf(out, " --------- ---- ----\n"); 1434 fprintf(out, " 0x%" PRIx64 " %d %s\n", 1435 p_mon_node->guid, p_mon_node->esp0, 1436 p_mon_node->name); 1437 fprintf(out, "\n Port Valid LIDs PKey QP PKey Index\n"); 1438 fprintf(out, " ---- ----- ---- ---- -- ----------\n"); 1439 redir = 1; 1440 } 1441 fprintf(out, " %d %d %u->%u 0x%x 0x%x %d\n", 1442 port, p_mon_node->port[port].valid, 1443 cl_ntoh16(p_mon_node->port[port].orig_lid), 1444 cl_ntoh16(p_mon_node->port[port].lid), 1445 cl_ntoh16(p_mon_node->port[port].pkey), 1446 cl_ntoh32(p_mon_node->port[port].qp), 1447 p_mon_node->port[port].pkey_ix); 1448 } 1449 } 1450 if (redir) 1451 fprintf(out, "\n"); 1452 } 1453 1454 static void dump_redir(osm_opensm_t * p_osm, char *nodename, FILE * out) 1455 { 1456 monitored_node_t *p_mon_node; 1457 uint64_t guid; 1458 1459 if (!p_osm->subn.opt.perfmgr_redir) 1460 fprintf(out, "Perfmgr redirection not enabled\n"); 1461 1462 fprintf(out, "\nRedirection Table\n"); 1463 fprintf(out, "-----------------\n"); 1464 cl_plock_acquire(&p_osm->lock); 1465 if (nodename) { 1466 guid = strtoull(nodename, NULL, 0); 1467 if (guid == 0 && errno) 1468 p_mon_node = find_node_by_name(p_osm, nodename); 1469 else 1470 p_mon_node = find_node_by_guid(p_osm, guid); 1471 if (p_mon_node) 1472 dump_redir_entry(p_mon_node, out); 1473 else { 1474 if (guid == 0 && errno) 1475 fprintf(out, "Node %s not found...\n", nodename); 1476 else 1477 fprintf(out, "Node 0x%" PRIx64 " not found...\n", guid); 1478 } 1479 } else { 1480 p_mon_node = (monitored_node_t *) cl_qmap_head(&p_osm->perfmgr.monitored_map); 1481 while (p_mon_node != (monitored_node_t *) cl_qmap_end(&p_osm->perfmgr.monitored_map)) { 1482 dump_redir_entry(p_mon_node, out); 1483 p_mon_node = (monitored_node_t *) cl_qmap_next((const cl_map_item_t *)p_mon_node); 1484 } 1485 } 1486 cl_plock_release(&p_osm->lock); 1487 } 1488 1489 static void clear_redir_entry(monitored_node_t *p_mon_node) 1490 { 1491 int port; 1492 ib_net16_t orig_lid; 1493 1494 for (port = (p_mon_node->esp0) ? 0 : 1; 1495 port < p_mon_node->num_ports; port++) { 1496 if (p_mon_node->port[port].redirection) { 1497 orig_lid = p_mon_node->port[port].orig_lid; 1498 memset(&p_mon_node->port[port], 0, 1499 sizeof(monitored_port_t)); 1500 p_mon_node->port[port].valid = TRUE; 1501 p_mon_node->port[port].orig_lid = orig_lid; 1502 } 1503 } 1504 } 1505 1506 static void clear_redir(osm_opensm_t * p_osm, char *nodename, FILE * out) 1507 { 1508 monitored_node_t *p_mon_node; 1509 uint64_t guid; 1510 1511 if (!p_osm->subn.opt.perfmgr_redir) 1512 fprintf(out, "Perfmgr redirection not enabled\n"); 1513 1514 cl_plock_acquire(&p_osm->lock); 1515 if (nodename) { 1516 guid = strtoull(nodename, NULL, 0); 1517 if (guid == 0 && errno) 1518 p_mon_node = find_node_by_name(p_osm, nodename); 1519 else 1520 p_mon_node = find_node_by_guid(p_osm, guid); 1521 if (p_mon_node) 1522 clear_redir_entry(p_mon_node); 1523 else { 1524 if (guid == 0 && errno) 1525 fprintf(out, "Node %s not found...\n", nodename); 1526 else 1527 fprintf(out, "Node 0x%" PRIx64 " not found...\n", guid); 1528 } 1529 } else { 1530 p_mon_node = (monitored_node_t *) cl_qmap_head(&p_osm->perfmgr.monitored_map); 1531 while (p_mon_node != (monitored_node_t *) cl_qmap_end(&p_osm->perfmgr.monitored_map)) { 1532 clear_redir_entry(p_mon_node); 1533 p_mon_node = (monitored_node_t *) cl_qmap_next((const cl_map_item_t *)p_mon_node); 1534 } 1535 } 1536 cl_plock_release(&p_osm->lock); 1537 } 1538 1539 static void perfmgr_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1540 { 1541 char *p_cmd; 1542 1543 p_cmd = next_token(p_last); 1544 if (p_cmd) { 1545 if (strcmp(p_cmd, "enable") == 0) { 1546 osm_perfmgr_set_state(&p_osm->perfmgr, 1547 PERFMGR_STATE_ENABLED); 1548 } else if (strcmp(p_cmd, "disable") == 0) { 1549 osm_perfmgr_set_state(&p_osm->perfmgr, 1550 PERFMGR_STATE_DISABLE); 1551 } else if (strcmp(p_cmd, "clear_counters") == 0) { 1552 osm_perfmgr_clear_counters(&p_osm->perfmgr); 1553 } else if (strcmp(p_cmd, "set_rm_nodes") == 0) { 1554 osm_perfmgr_set_rm_nodes(&p_osm->perfmgr, 1); 1555 } else if (strcmp(p_cmd, "clear_rm_nodes") == 0) { 1556 osm_perfmgr_set_rm_nodes(&p_osm->perfmgr, 0); 1557 } else if (strcmp(p_cmd, "set_query_cpi") == 0) { 1558 osm_perfmgr_set_query_cpi(&p_osm->perfmgr, 1); 1559 } else if (strcmp(p_cmd, "clear_query_cpi") == 0) { 1560 osm_perfmgr_set_query_cpi(&p_osm->perfmgr, 0); 1561 } else if (strcmp(p_cmd, "dump_counters") == 0) { 1562 p_cmd = next_token(p_last); 1563 if (p_cmd && (strcmp(p_cmd, "mach") == 0)) { 1564 osm_perfmgr_dump_counters(&p_osm->perfmgr, 1565 PERFMGR_EVENT_DB_DUMP_MR); 1566 } else { 1567 osm_perfmgr_dump_counters(&p_osm->perfmgr, 1568 PERFMGR_EVENT_DB_DUMP_HR); 1569 } 1570 } else if (strcmp(p_cmd, "clear_inactive") == 0) { 1571 unsigned cnt = osm_perfmgr_delete_inactive(&p_osm->perfmgr); 1572 fprintf(out, "Removed %u nodes from Database\n", cnt); 1573 } else if (strcmp(p_cmd, "print_counters") == 0 || 1574 strcmp(p_cmd, "pc") == 0) { 1575 char *port = NULL; 1576 p_cmd = name_token(p_last); 1577 if (p_cmd) { 1578 port = strchr(p_cmd, ':'); 1579 if (port) { 1580 *port = '\0'; 1581 port++; 1582 } 1583 } 1584 osm_perfmgr_print_counters(&p_osm->perfmgr, p_cmd, 1585 out, port, 0); 1586 } else if (strcmp(p_cmd, "print_errors") == 0 || 1587 strcmp(p_cmd, "pe") == 0) { 1588 p_cmd = name_token(p_last); 1589 osm_perfmgr_print_counters(&p_osm->perfmgr, p_cmd, 1590 out, NULL, 1); 1591 } else if (strcmp(p_cmd, "dump_redir") == 0) { 1592 p_cmd = name_token(p_last); 1593 dump_redir(p_osm, p_cmd, out); 1594 } else if (strcmp(p_cmd, "clear_redir") == 0) { 1595 p_cmd = name_token(p_last); 1596 clear_redir(p_osm, p_cmd, out); 1597 } else if (strcmp(p_cmd, "sweep_time") == 0) { 1598 p_cmd = next_token(p_last); 1599 if (p_cmd) { 1600 uint16_t time_s = atoi(p_cmd); 1601 if (time_s < 1) 1602 fprintf(out, 1603 "sweep_time requires a " 1604 "positive time period " 1605 "(in seconds) to be " 1606 "specified\n"); 1607 else 1608 osm_perfmgr_set_sweep_time_s( 1609 &p_osm->perfmgr, 1610 time_s); 1611 } else { 1612 fprintf(out, 1613 "sweep_time requires a time period " 1614 "(in seconds) to be specified\n"); 1615 } 1616 } else if (strcmp(p_cmd, "sweep") == 0) { 1617 osm_sm_signal(&p_osm->sm, OSM_SIGNAL_PERFMGR_SWEEP); 1618 fprintf(out, "sweep initiated...\n"); 1619 } else { 1620 fprintf(out, "\"%s\" option not found\n", p_cmd); 1621 } 1622 } else { 1623 fprintf(out, "Performance Manager status:\n" 1624 "state : %s\n" 1625 "sweep state : %s\n" 1626 "sweep time : %us\n" 1627 "outstanding queries/max : %d/%u\n" 1628 "remove missing nodes from DB : %s\n" 1629 "query ClassPortInfo : %s\n", 1630 osm_perfmgr_get_state_str(&p_osm->perfmgr), 1631 osm_perfmgr_get_sweep_state_str(&p_osm->perfmgr), 1632 osm_perfmgr_get_sweep_time_s(&p_osm->perfmgr), 1633 p_osm->perfmgr.outstanding_queries, 1634 p_osm->perfmgr.max_outstanding_queries, 1635 osm_perfmgr_get_rm_nodes(&p_osm->perfmgr) 1636 ? "TRUE" : "FALSE", 1637 osm_perfmgr_get_query_cpi(&p_osm->perfmgr) 1638 ? "TRUE" : "FALSE"); 1639 } 1640 } 1641 #endif /* ENABLE_OSM_PERF_MGR */ 1642 1643 static void quit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1644 { 1645 cio_close(&p_osm->console, &p_osm->log); 1646 } 1647 1648 static void help_version(FILE * out, int detail) 1649 { 1650 fprintf(out, "version -- print the OSM version\n"); 1651 } 1652 1653 static void version_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1654 { 1655 fprintf(out, "%s build %s %s\n", p_osm->osm_version, __DATE__, __TIME__); 1656 } 1657 1658 /* more parse routines go here */ 1659 typedef struct _regexp_list { 1660 regex_t exp; 1661 struct _regexp_list *next; 1662 } regexp_list_t; 1663 1664 static void dump_portguid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1665 { 1666 cl_qmap_t *p_alias_port_guid_tbl; 1667 osm_alias_guid_t *p_alias_guid, *p_next_alias_guid; 1668 regexp_list_t *p_regexp, *p_head_regexp = NULL; 1669 FILE *output = out; 1670 1671 while (1) { 1672 char *p_cmd = next_token(p_last); 1673 if (!p_cmd) 1674 break; 1675 1676 if (strcmp(p_cmd, "file") == 0) { 1677 p_cmd = next_token(p_last); 1678 if (p_cmd) { 1679 output = fopen(p_cmd, "w+"); 1680 if (output == NULL) { 1681 fprintf(out, 1682 "Could not open file %s: %s\n", 1683 p_cmd, strerror(errno)); 1684 output = out; 1685 } 1686 } else 1687 fprintf(out, "No file name passed\n"); 1688 } else if (!(p_regexp = malloc(sizeof(*p_regexp)))) { 1689 fprintf(out, "No memory\n"); 1690 break; 1691 } else if (regcomp(&p_regexp->exp, p_cmd, 1692 REG_NOSUB | REG_EXTENDED) != 0) { 1693 fprintf(out, "Cannot parse regular expression \'%s\'." 1694 " Skipping\n", p_cmd); 1695 free(p_regexp); 1696 continue; 1697 } else { 1698 p_regexp->next = p_head_regexp; 1699 p_head_regexp = p_regexp; 1700 } 1701 } 1702 1703 /* Check we have at least one expression to match */ 1704 if (p_head_regexp == NULL) { 1705 fprintf(out, "No valid expression provided. Aborting\n"); 1706 goto Exit; 1707 } 1708 1709 if (p_osm->sm.p_subn->need_update != 0) { 1710 fprintf(out, "Subnet is not ready yet. Try again later\n"); 1711 goto Free_and_exit; 1712 } 1713 1714 /* Subnet doesn't need to be updated so we can carry on */ 1715 1716 p_alias_port_guid_tbl = &(p_osm->sm.p_subn->alias_port_guid_tbl); 1717 CL_PLOCK_ACQUIRE(p_osm->sm.p_lock); 1718 1719 p_next_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_alias_port_guid_tbl); 1720 while (p_next_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_alias_port_guid_tbl)) { 1721 1722 p_alias_guid = p_next_alias_guid; 1723 p_next_alias_guid = 1724 (osm_alias_guid_t *) cl_qmap_next(&p_next_alias_guid->map_item); 1725 1726 for (p_regexp = p_head_regexp; p_regexp != NULL; 1727 p_regexp = p_regexp->next) 1728 if (regexec(&p_regexp->exp, 1729 p_alias_guid->p_base_port->p_node->print_desc, 1730 0, NULL, 0) == 0) { 1731 fprintf(output, "0x%" PRIxLEAST64 "\n", 1732 cl_ntoh64(p_alias_guid->alias_guid)); 1733 break; 1734 } 1735 } 1736 1737 CL_PLOCK_RELEASE(p_osm->sm.p_lock); 1738 1739 Free_and_exit: 1740 for (; p_head_regexp; p_head_regexp = p_regexp) { 1741 p_regexp = p_head_regexp->next; 1742 regfree(&p_head_regexp->exp); 1743 free(p_head_regexp); 1744 } 1745 Exit: 1746 if (output != out) 1747 fclose(output); 1748 } 1749 1750 static void help_dump_portguid(FILE * out, int detail) 1751 { 1752 fprintf(out, 1753 "dump_portguid [file filename] regexp1 [regexp2 [regexp3 ...]] -- Dump port GUID matching a regexp \n"); 1754 if (detail) { 1755 fprintf(out, 1756 "getguidgetguid -- Dump all the port GUID whom node_desc matches one of the provided regexp\n"); 1757 fprintf(out, 1758 " [file filename] -- Send the port GUID list to the specified file instead of regular output\n"); 1759 } 1760 1761 } 1762 1763 static const struct command console_cmds[] = { 1764 {"help", &help_command, &help_parse}, 1765 {"quit", &help_quit, &quit_parse}, 1766 {"loglevel", &help_loglevel, &loglevel_parse}, 1767 {"permodlog", &help_permodlog, &permodlog_parse}, 1768 {"priority", &help_priority, &priority_parse}, 1769 {"resweep", &help_resweep, &resweep_parse}, 1770 {"reroute", &help_reroute, &reroute_parse}, 1771 {"sweep", &help_sweep, &sweep_parse}, 1772 {"status", &help_status, &status_parse}, 1773 {"logflush", &help_logflush, &logflush_parse}, 1774 {"querylid", &help_querylid, &querylid_parse}, 1775 {"portstatus", &help_portstatus, &portstatus_parse}, 1776 {"switchbalance", &help_switchbalance, &switchbalance_parse}, 1777 {"lidbalance", &help_lidbalance, &lidbalance_parse}, 1778 {"dump_conf", &help_dump_conf, &dump_conf_parse}, 1779 {"update_desc", &help_update_desc, &update_desc_parse}, 1780 {"version", &help_version, &version_parse}, 1781 #ifdef ENABLE_OSM_PERF_MGR 1782 {"perfmgr", &help_perfmgr, &perfmgr_parse}, 1783 {"pm", &help_pm, &perfmgr_parse}, 1784 #endif /* ENABLE_OSM_PERF_MGR */ 1785 {"dump_portguid", &help_dump_portguid, &dump_portguid_parse}, 1786 {NULL, NULL, NULL} /* end of array */ 1787 }; 1788 1789 static void parse_cmd_line(char *line, osm_opensm_t * p_osm) 1790 { 1791 char *p_cmd, *p_last; 1792 int i, found = 0; 1793 FILE *out = p_osm->console.out; 1794 1795 while (isspace(*line)) 1796 line++; 1797 if (!*line) 1798 return; 1799 1800 /* find first token which is the command */ 1801 p_cmd = strtok_r(line, " \t\n\r", &p_last); 1802 if (p_cmd) { 1803 for (i = 0; console_cmds[i].name; i++) { 1804 if (loop_command.on) { 1805 if (!strcmp(p_cmd, "q")) { 1806 loop_command.on = 0; 1807 } 1808 found = 1; 1809 break; 1810 } 1811 if (!strcmp(p_cmd, console_cmds[i].name)) { 1812 found = 1; 1813 console_cmds[i].parse_function(&p_last, p_osm, 1814 out); 1815 break; 1816 } 1817 } 1818 if (!found) { 1819 fprintf(out, "%s : Command not found\n\n", p_cmd); 1820 help_command(out, 0); 1821 } 1822 } else { 1823 fprintf(out, "Error parsing command line: `%s'\n", line); 1824 } 1825 if (loop_command.on) { 1826 fprintf(out, "use \"q<ret>\" to quit loop\n"); 1827 fflush(out); 1828 } 1829 } 1830 1831 int osm_console(osm_opensm_t * p_osm) 1832 { 1833 struct pollfd pollfd[2]; 1834 char *p_line; 1835 size_t len; 1836 ssize_t n; 1837 struct pollfd *fds; 1838 nfds_t nfds; 1839 osm_console_t *p_oct = &p_osm->console; 1840 1841 pollfd[0].fd = p_oct->socket; 1842 pollfd[0].events = POLLIN; 1843 pollfd[0].revents = 0; 1844 1845 pollfd[1].fd = p_oct->in_fd; 1846 pollfd[1].events = POLLIN; 1847 pollfd[1].revents = 0; 1848 1849 fds = p_oct->socket < 0 ? &pollfd[1] : pollfd; 1850 nfds = p_oct->socket < 0 || pollfd[1].fd < 0 ? 1 : 2; 1851 1852 if (loop_command.on && loop_command_check_time() && 1853 loop_command.loop_function) { 1854 if (p_oct->out) { 1855 loop_command.loop_function(p_osm, p_oct->out); 1856 fflush(p_oct->out); 1857 } else { 1858 loop_command.on = 0; 1859 } 1860 } 1861 1862 if (poll(fds, nfds, 1000) <= 0) 1863 return 0; 1864 1865 #ifdef ENABLE_OSM_CONSOLE_LOOPBACK 1866 if (pollfd[0].revents & POLLIN) { 1867 int new_fd = 0; 1868 struct sockaddr_in sin; 1869 socklen_t len = sizeof(sin); 1870 struct hostent *hent; 1871 if ((new_fd = accept(p_oct->socket, (struct sockaddr *)&sin, &len)) < 0) { 1872 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 1873 "ERR 4B04: Failed to accept console socket: %s\n", 1874 strerror(errno)); 1875 p_oct->in_fd = -1; 1876 return 0; 1877 } 1878 if (inet_ntop 1879 (AF_INET, &sin.sin_addr, p_oct->client_ip, 1880 sizeof(p_oct->client_ip)) == NULL) { 1881 snprintf(p_oct->client_ip, sizeof(p_oct->client_ip), 1882 "STRING_UNKNOWN"); 1883 } 1884 if ((hent = gethostbyaddr((const char *)&sin.sin_addr, 1885 sizeof(struct in_addr), 1886 AF_INET)) == NULL) { 1887 snprintf(p_oct->client_hn, sizeof(p_oct->client_hn), 1888 "STRING_UNKNOWN"); 1889 } else { 1890 snprintf(p_oct->client_hn, sizeof(p_oct->client_hn), 1891 "%s", hent->h_name); 1892 } 1893 if (is_authorized(p_oct)) { 1894 cio_open(p_oct, new_fd, &p_osm->log); 1895 } else { 1896 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 1897 "ERR 4B05: Console connection denied: %s (%s)\n", 1898 p_oct->client_hn, p_oct->client_ip); 1899 close(new_fd); 1900 } 1901 return 0; 1902 } 1903 #endif 1904 1905 if (pollfd[1].revents & POLLIN) { 1906 p_line = NULL; 1907 /* Get input line */ 1908 n = getline(&p_line, &len, p_oct->in); 1909 if (n > 0) { 1910 /* Parse and act on input */ 1911 parse_cmd_line(p_line, p_osm); 1912 if (!loop_command.on) { 1913 osm_console_prompt(p_oct->out); 1914 } 1915 } else 1916 cio_close(p_oct, &p_osm->log); 1917 if (p_line) 1918 free(p_line); 1919 return 0; 1920 } 1921 /* input fd is closed (hanged up) */ 1922 if (pollfd[1].revents & POLLHUP) { 1923 #ifdef ENABLE_OSM_CONSOLE_LOOPBACK 1924 /* If we are using a socket, we close the current connection */ 1925 if (p_oct->socket >= 0) { 1926 cio_close(p_oct, &p_osm->log); 1927 return 0; 1928 } 1929 #endif 1930 /* If we use a local console, stdin is closed (most probable is pipe ended) 1931 * so we close the local console */ 1932 return -1; 1933 } 1934 1935 return 0; 1936 } 1937