1/* 2 * Copyright (c) 2005-2008 Voltaire, Inc. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 */ 33 34#if HAVE_CONFIG_H 35# include <config.h> 36#endif /* HAVE_CONFIG_H */ 37 38#define _GNU_SOURCE /* for getline */ 39#include <stdio.h> 40#include <stdlib.h> 41#include <sys/poll.h> 42#include <sys/types.h> 43#include <sys/socket.h> 44#include <netdb.h> 45#ifdef ENABLE_OSM_CONSOLE_SOCKET 46#include <arpa/inet.h> 47#endif 48#include <unistd.h> 49#include <errno.h> 50#include <ctype.h> 51#include <sys/time.h> 52#include <opensm/osm_console.h> 53#include <complib/cl_passivelock.h> 54#include <opensm/osm_perfmgr.h> 55#include <opensm/osm_subnet.h> 56 57struct command { 58 char *name; 59 void (*help_function) (FILE * out, int detail); 60 void (*parse_function) (char **p_last, osm_opensm_t * p_osm, 61 FILE * out); 62}; 63 64static struct { 65 int on; 66 int delay_s; 67 time_t previous; 68 void (*loop_function) (osm_opensm_t * p_osm, FILE * out); 69} loop_command = { 70 .on = 0, 71 .delay_s = 2, 72 .loop_function = NULL, 73}; 74 75static const struct command console_cmds[]; 76 77static inline char *next_token(char **p_last) 78{ 79 return strtok_r(NULL, " \t\n\r", p_last); 80} 81 82static void help_command(FILE * out, int detail) 83{ 84 int i; 85 86 fprintf(out, "Supported commands and syntax:\n"); 87 fprintf(out, "help [<command>]\n"); 88 /* skip help command */ 89 for (i = 1; console_cmds[i].name; i++) 90 console_cmds[i].help_function(out, 0); 91} 92 93static void help_quit(FILE * out, int detail) 94{ 95 fprintf(out, "quit (not valid in local mode; use ctl-c)\n"); 96} 97 98static void help_loglevel(FILE * out, int detail) 99{ 100 fprintf(out, "loglevel [<log-level>]\n"); 101 if (detail) { 102 fprintf(out, " log-level is OR'ed from the following\n"); 103 fprintf(out, " OSM_LOG_NONE 0x%02X\n", 104 OSM_LOG_NONE); 105 fprintf(out, " OSM_LOG_ERROR 0x%02X\n", 106 OSM_LOG_ERROR); 107 fprintf(out, " OSM_LOG_INFO 0x%02X\n", 108 OSM_LOG_INFO); 109 fprintf(out, " OSM_LOG_VERBOSE 0x%02X\n", 110 OSM_LOG_VERBOSE); 111 fprintf(out, " OSM_LOG_DEBUG 0x%02X\n", 112 OSM_LOG_DEBUG); 113 fprintf(out, " OSM_LOG_FUNCS 0x%02X\n", 114 OSM_LOG_FUNCS); 115 fprintf(out, " OSM_LOG_FRAMES 0x%02X\n", 116 OSM_LOG_FRAMES); 117 fprintf(out, " OSM_LOG_ROUTING 0x%02X\n", 118 OSM_LOG_ROUTING); 119 fprintf(out, " OSM_LOG_SYS 0x%02X\n", 120 OSM_LOG_SYS); 121 fprintf(out, "\n"); 122 fprintf(out, " OSM_LOG_DEFAULT_LEVEL 0x%02X\n", 123 OSM_LOG_DEFAULT_LEVEL); 124 } 125} 126 127static void help_priority(FILE * out, int detail) 128{ 129 fprintf(out, "priority [<sm-priority>]\n"); 130} 131 132static void help_resweep(FILE * out, int detail) 133{ 134 fprintf(out, "resweep [heavy|light]\n"); 135} 136 137static void help_reroute(FILE * out, int detail) 138{ 139 fprintf(out, "reroute\n"); 140 if (detail) { 141 fprintf(out, "reroute the fabric\n"); 142 } 143} 144 145static void help_status(FILE * out, int detail) 146{ 147 fprintf(out, "status [loop]\n"); 148 if (detail) { 149 fprintf(out, " loop -- type \"q<ret>\" to quit\n"); 150 } 151} 152 153static void help_logflush(FILE * out, int detail) 154{ 155 fprintf(out, "logflush -- flush the opensm.log file\n"); 156} 157 158static void help_querylid(FILE * out, int detail) 159{ 160 fprintf(out, 161 "querylid lid -- print internal information about the lid specified\n"); 162} 163 164static void help_portstatus(FILE * out, int detail) 165{ 166 fprintf(out, "portstatus [ca|switch|router]\n"); 167 if (detail) { 168 fprintf(out, "summarize port status\n"); 169 fprintf(out, 170 " [ca|switch|router] -- limit the results to the node type specified\n"); 171 } 172 173} 174 175static void help_switchbalance(FILE * out, int detail) 176{ 177 fprintf(out, "switchbalance [verbose] [guid]\n"); 178 if (detail) { 179 fprintf(out, "output switch balancing information\n"); 180 fprintf(out, 181 " [verbose] -- verbose output\n" 182 " [guid] -- limit results to specified guid\n"); 183 } 184} 185 186static void help_lidbalance(FILE * out, int detail) 187{ 188 fprintf(out, "lidbalance [switchguid]\n"); 189 if (detail) { 190 fprintf(out, "output lid balanced forwarding information\n"); 191 fprintf(out, 192 " [switchguid] -- limit results to specified switch guid\n"); 193 } 194} 195 196static void help_dump_conf(FILE *out, int detail) 197{ 198 fprintf(out, "dump_conf\n"); 199 if (detail) { 200 fprintf(out, "dump current opensm configuration\n"); 201 } 202} 203 204#ifdef ENABLE_OSM_PERF_MGR 205static void help_perfmgr(FILE * out, int detail) 206{ 207 fprintf(out, 208 "perfmgr [enable|disable|clear_counters|dump_counters|sweep_time[seconds]]\n"); 209 if (detail) { 210 fprintf(out, 211 "perfmgr -- print the performance manager state\n"); 212 fprintf(out, 213 " [enable|disable] -- change the perfmgr state\n"); 214 fprintf(out, 215 " [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n"); 216 fprintf(out, 217 " [clear_counters] -- clear the counters stored\n"); 218 fprintf(out, 219 " [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n"); 220 fprintf(out, 221 " [print_counters <nodename|nodeguid>] -- print the counters for the specified node\n"); 222 } 223} 224#endif /* ENABLE_OSM_PERF_MGR */ 225 226/* more help routines go here */ 227 228static void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 229{ 230 char *p_cmd; 231 int i, found = 0; 232 233 p_cmd = next_token(p_last); 234 if (!p_cmd) 235 help_command(out, 0); 236 else { 237 for (i = 1; console_cmds[i].name; i++) { 238 if (!strcmp(p_cmd, console_cmds[i].name)) { 239 found = 1; 240 console_cmds[i].help_function(out, 1); 241 break; 242 } 243 } 244 if (!found) { 245 fprintf(out, "%s : Command not found\n\n", p_cmd); 246 help_command(out, 0); 247 } 248 } 249} 250 251static void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 252{ 253 char *p_cmd; 254 int level; 255 256 p_cmd = next_token(p_last); 257 if (!p_cmd) 258 fprintf(out, "Current log level is 0x%x\n", 259 osm_log_get_level(&p_osm->log)); 260 else { 261 /* Handle x, 0x, and decimal specification of log level */ 262 if (!strncmp(p_cmd, "x", 1)) { 263 p_cmd++; 264 level = strtoul(p_cmd, NULL, 16); 265 } else { 266 if (!strncmp(p_cmd, "0x", 2)) { 267 p_cmd += 2; 268 level = strtoul(p_cmd, NULL, 16); 269 } else 270 level = strtol(p_cmd, NULL, 10); 271 } 272 if ((level >= 0) && (level < 256)) { 273 fprintf(out, "Setting log level to 0x%x\n", level); 274 osm_log_set_level(&p_osm->log, level); 275 } else 276 fprintf(out, "Invalid log level 0x%x\n", level); 277 } 278} 279 280static void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 281{ 282 char *p_cmd; 283 int priority; 284 285 p_cmd = next_token(p_last); 286 if (!p_cmd) 287 fprintf(out, "Current sm-priority is %d\n", 288 p_osm->subn.opt.sm_priority); 289 else { 290 priority = strtol(p_cmd, NULL, 0); 291 if (0 > priority || 15 < priority) 292 fprintf(out, 293 "Invalid sm-priority %d; must be between 0 and 15\n", 294 priority); 295 else { 296 fprintf(out, "Setting sm-priority to %d\n", priority); 297 osm_set_sm_priority(&p_osm->sm, (uint8_t)priority); 298 } 299 } 300} 301 302static char *sm_state_str(int state) 303{ 304 switch (state) { 305 case IB_SMINFO_STATE_DISCOVERING: 306 return ("Discovering"); 307 case IB_SMINFO_STATE_STANDBY: 308 return ("Standby"); 309 case IB_SMINFO_STATE_NOTACTIVE: 310 return ("Not Active"); 311 case IB_SMINFO_STATE_MASTER: 312 return ("Master"); 313 } 314 return ("UNKNOWN"); 315} 316 317static char *sa_state_str(osm_sa_state_t state) 318{ 319 switch (state) { 320 case OSM_SA_STATE_INIT: 321 return ("Init"); 322 case OSM_SA_STATE_READY: 323 return ("Ready"); 324 } 325 return ("UNKNOWN"); 326} 327 328static void print_status(osm_opensm_t * p_osm, FILE * out) 329{ 330 cl_list_item_t *item; 331 332 if (out) { 333 cl_plock_acquire(&p_osm->lock); 334 fprintf(out, " OpenSM Version : %s\n", p_osm->osm_version); 335 fprintf(out, " SM State : %s\n", 336 sm_state_str(p_osm->subn.sm_state)); 337 fprintf(out, " SA State : %s\n", 338 sa_state_str(p_osm->sa.state)); 339 fprintf(out, " Routing Engine : %s\n", 340 osm_routing_engine_type_str(p_osm-> 341 routing_engine_used)); 342 343 fprintf(out, " Loaded event plugins :"); 344 if (cl_qlist_head(&p_osm->plugin_list) == 345 cl_qlist_end(&p_osm->plugin_list)) { 346 fprintf(out, " <none>"); 347 } 348 for (item = cl_qlist_head(&p_osm->plugin_list); 349 item != cl_qlist_end(&p_osm->plugin_list); 350 item = cl_qlist_next(item)) 351 fprintf(out, " %s", 352 ((osm_epi_plugin_t *)item)->plugin_name); 353 fprintf(out, "\n"); 354 355#ifdef ENABLE_OSM_PERF_MGR 356 fprintf(out, "\n PerfMgr state/sweep state : %s/%s\n", 357 osm_perfmgr_get_state_str(&(p_osm->perfmgr)), 358 osm_perfmgr_get_sweep_state_str(&(p_osm->perfmgr))); 359#endif 360 fprintf(out, "\n MAD stats\n" 361 " ---------\n" 362 " QP0 MADs outstanding : %d\n" 363 " QP0 MADs outstanding (on wire) : %d\n" 364 " QP0 MADs rcvd : %d\n" 365 " QP0 MADs sent : %d\n" 366 " QP0 unicasts sent : %d\n" 367 " QP0 unknown MADs rcvd : %d\n" 368 " SA MADs outstanding : %d\n" 369 " SA MADs rcvd : %d\n" 370 " SA MADs sent : %d\n" 371 " SA unknown MADs rcvd : %d\n" 372 " SA MADs ignored : %d\n", 373 p_osm->stats.qp0_mads_outstanding, 374 p_osm->stats.qp0_mads_outstanding_on_wire, 375 p_osm->stats.qp0_mads_rcvd, 376 p_osm->stats.qp0_mads_sent, 377 p_osm->stats.qp0_unicasts_sent, 378 p_osm->stats.qp0_mads_rcvd_unknown, 379 p_osm->stats.sa_mads_outstanding, 380 p_osm->stats.sa_mads_rcvd, 381 p_osm->stats.sa_mads_sent, 382 p_osm->stats.sa_mads_rcvd_unknown, 383 p_osm->stats.sa_mads_ignored); 384 fprintf(out, "\n Subnet flags\n" 385 " ------------\n" 386 " Ignore existing lfts : %d\n" 387 " Subnet Init errors : %d\n" 388 " In sweep hop 0 : %d\n" 389 " First time master sweep : %d\n" 390 " Coming out of standby : %d\n", 391 p_osm->subn.ignore_existing_lfts, 392 p_osm->subn.subnet_initialization_error, 393 p_osm->subn.in_sweep_hop_0, 394 p_osm->subn.first_time_master_sweep, 395 p_osm->subn.coming_out_of_standby); 396 fprintf(out, "\n"); 397 cl_plock_release(&p_osm->lock); 398 } 399} 400 401static int loop_command_check_time(void) 402{ 403 time_t cur = time(NULL); 404 if ((loop_command.previous + loop_command.delay_s) < cur) { 405 loop_command.previous = cur; 406 return (1); 407 } 408 return (0); 409} 410 411static void status_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 412{ 413 char *p_cmd; 414 415 p_cmd = next_token(p_last); 416 if (p_cmd) { 417 if (strcmp(p_cmd, "loop") == 0) { 418 fprintf(out, "Looping on status command...\n"); 419 fflush(out); 420 loop_command.on = 1; 421 loop_command.previous = time(NULL); 422 loop_command.loop_function = print_status; 423 } else { 424 help_status(out, 1); 425 return; 426 } 427 } 428 print_status(p_osm, out); 429} 430 431static void resweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 432{ 433 char *p_cmd; 434 435 p_cmd = next_token(p_last); 436 if (!p_cmd || 437 (strcmp(p_cmd, "heavy") != 0 && strcmp(p_cmd, "light") != 0)) { 438 fprintf(out, "Invalid resweep command\n"); 439 help_resweep(out, 1); 440 } else { 441 if (strcmp(p_cmd, "heavy") == 0) 442 p_osm->subn.force_heavy_sweep = TRUE; 443 osm_opensm_sweep(p_osm); 444 } 445} 446 447static void reroute_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 448{ 449 p_osm->subn.force_reroute = TRUE; 450 osm_opensm_sweep(p_osm); 451} 452 453static void logflush_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 454{ 455 fflush(p_osm->log.out_port); 456} 457 458static void querylid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 459{ 460 int p = 0; 461 uint16_t lid = 0; 462 osm_port_t *p_port = NULL; 463 char *p_cmd = next_token(p_last); 464 465 if (!p_cmd) { 466 fprintf(out, "no LID specified\n"); 467 help_querylid(out, 1); 468 return; 469 } 470 471 lid = (uint16_t) strtoul(p_cmd, NULL, 0); 472 cl_plock_acquire(&p_osm->lock); 473 if (lid > cl_ptr_vector_get_capacity(&(p_osm->subn.port_lid_tbl))) 474 goto invalid_lid; 475 p_port = cl_ptr_vector_get(&(p_osm->subn.port_lid_tbl), lid); 476 if (!p_port) 477 goto invalid_lid; 478 479 fprintf(out, "Query results for LID %u\n", lid); 480 fprintf(out, 481 " GUID : 0x%016" PRIx64 "\n" 482 " Node Desc : %s\n" 483 " Node Type : %s\n" 484 " Num Ports : %d\n", 485 cl_ntoh64(p_port->guid), 486 p_port->p_node->print_desc, 487 ib_get_node_type_str(osm_node_get_type(p_port->p_node)), 488 p_port->p_node->node_info.num_ports); 489 490 if (p_port->p_node->sw) 491 p = 0; 492 else 493 p = 1; 494 for ( /* see above */ ; p < p_port->p_node->physp_tbl_size; p++) { 495 fprintf(out, 496 " Port %d health : %s\n", 497 p, 498 p_port->p_node->physp_table[p]. 499 healthy ? "OK" : "ERROR"); 500 } 501 502 cl_plock_release(&p_osm->lock); 503 return; 504 505invalid_lid: 506 cl_plock_release(&p_osm->lock); 507 fprintf(out, "Invalid lid %d\n", lid); 508 return; 509} 510 511/** 512 * Data structures for the portstatus command 513 */ 514typedef struct _port_report { 515 struct _port_report *next; 516 uint64_t node_guid; 517 uint8_t port_num; 518 char print_desc[IB_NODE_DESCRIPTION_SIZE + 1]; 519} port_report_t; 520 521static void 522__tag_port_report(port_report_t ** head, uint64_t node_guid, 523 uint8_t port_num, char *print_desc) 524{ 525 port_report_t *rep = malloc(sizeof(*rep)); 526 if (!rep) 527 return; 528 529 rep->node_guid = node_guid; 530 rep->port_num = port_num; 531 memcpy(rep->print_desc, print_desc, IB_NODE_DESCRIPTION_SIZE + 1); 532 rep->next = NULL; 533 if (*head) { 534 rep->next = *head; 535 *head = rep; 536 } else 537 *head = rep; 538} 539 540static void __print_port_report(FILE * out, port_report_t * head) 541{ 542 port_report_t *item = head; 543 while (item != NULL) { 544 fprintf(out, " 0x%016" PRIx64 " %d (%s)\n", 545 item->node_guid, item->port_num, item->print_desc); 546 port_report_t *next = item->next; 547 free(item); 548 item = next; 549 } 550} 551 552typedef struct { 553 uint8_t node_type_lim; /* limit the results; 0 == ALL */ 554 uint64_t total_nodes; 555 uint64_t total_ports; 556 uint64_t ports_down; 557 uint64_t ports_active; 558 uint64_t ports_disabled; 559 port_report_t *disabled_ports; 560 uint64_t ports_1X; 561 uint64_t ports_4X; 562 uint64_t ports_8X; 563 uint64_t ports_12X; 564 uint64_t ports_unknown_width; 565 uint64_t ports_reduced_width; 566 port_report_t *reduced_width_ports; 567 uint64_t ports_sdr; 568 uint64_t ports_ddr; 569 uint64_t ports_qdr; 570 uint64_t ports_unknown_speed; 571 uint64_t ports_reduced_speed; 572 port_report_t *reduced_speed_ports; 573} fabric_stats_t; 574 575/** 576 * iterator function to get portstatus on each node 577 */ 578static void __get_stats(cl_map_item_t * const p_map_item, void *context) 579{ 580 fabric_stats_t *fs = (fabric_stats_t *) context; 581 osm_node_t *node = (osm_node_t *) p_map_item; 582 uint8_t num_ports = osm_node_get_num_physp(node); 583 uint8_t port = 0; 584 585 /* Skip nodes we are not interested in */ 586 if (fs->node_type_lim != 0 587 && fs->node_type_lim != node->node_info.node_type) 588 return; 589 590 fs->total_nodes++; 591 592 for (port = 1; port < num_ports; port++) { 593 osm_physp_t *phys = osm_node_get_physp_ptr(node, port); 594 ib_port_info_t *pi = NULL; 595 uint8_t active_speed = 0; 596 uint8_t enabled_speed = 0; 597 uint8_t active_width = 0; 598 uint8_t enabled_width = 0; 599 uint8_t port_state = 0; 600 uint8_t port_phys_state = 0; 601 602 if (!phys) 603 continue; 604 605 pi = &(phys->port_info); 606 active_speed = ib_port_info_get_link_speed_active(pi); 607 enabled_speed = ib_port_info_get_link_speed_enabled(pi); 608 active_width = pi->link_width_active; 609 enabled_width = pi->link_width_enabled; 610 port_state = ib_port_info_get_port_state(pi); 611 port_phys_state = ib_port_info_get_port_phys_state(pi); 612 613 if ((enabled_width ^ active_width) > active_width) { 614 __tag_port_report(&(fs->reduced_width_ports), 615 cl_ntoh64(node->node_info.node_guid), 616 port, node->print_desc); 617 fs->ports_reduced_width++; 618 } 619 620 if ((enabled_speed ^ active_speed) > active_speed) { 621 __tag_port_report(&(fs->reduced_speed_ports), 622 cl_ntoh64(node->node_info.node_guid), 623 port, node->print_desc); 624 fs->ports_reduced_speed++; 625 } 626 627 switch (active_speed) { 628 case IB_LINK_SPEED_ACTIVE_2_5: 629 fs->ports_sdr++; 630 break; 631 case IB_LINK_SPEED_ACTIVE_5: 632 fs->ports_ddr++; 633 break; 634 case IB_LINK_SPEED_ACTIVE_10: 635 fs->ports_qdr++; 636 break; 637 default: 638 fs->ports_unknown_speed++; 639 break; 640 } 641 switch (active_width) { 642 case IB_LINK_WIDTH_ACTIVE_1X: 643 fs->ports_1X++; 644 break; 645 case IB_LINK_WIDTH_ACTIVE_4X: 646 fs->ports_4X++; 647 break; 648 case IB_LINK_WIDTH_ACTIVE_8X: 649 fs->ports_8X++; 650 break; 651 case IB_LINK_WIDTH_ACTIVE_12X: 652 fs->ports_12X++; 653 break; 654 default: 655 fs->ports_unknown_width++; 656 break; 657 } 658 if (port_state == IB_LINK_DOWN) 659 fs->ports_down++; 660 else if (port_state == IB_LINK_ACTIVE) 661 fs->ports_active++; 662 if (port_phys_state == IB_PORT_PHYS_STATE_DISABLED) { 663 __tag_port_report(&(fs->disabled_ports), 664 cl_ntoh64(node->node_info.node_guid), 665 port, node->print_desc); 666 fs->ports_disabled++; 667 } 668 669 fs->total_ports++; 670 } 671} 672 673static void portstatus_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 674{ 675 fabric_stats_t fs; 676 struct timeval before, after; 677 char *p_cmd; 678 679 memset(&fs, 0, sizeof(fs)); 680 681 p_cmd = next_token(p_last); 682 if (p_cmd) { 683 if (strcmp(p_cmd, "ca") == 0) { 684 fs.node_type_lim = IB_NODE_TYPE_CA; 685 } else if (strcmp(p_cmd, "switch") == 0) { 686 fs.node_type_lim = IB_NODE_TYPE_SWITCH; 687 } else if (strcmp(p_cmd, "router") == 0) { 688 fs.node_type_lim = IB_NODE_TYPE_ROUTER; 689 } else { 690 fprintf(out, "Node type not understood\n"); 691 help_portstatus(out, 1); 692 return; 693 } 694 } 695 696 gettimeofday(&before, NULL); 697 698 /* for each node in the system gather the stats */ 699 cl_plock_acquire(&p_osm->lock); 700 cl_qmap_apply_func(&(p_osm->subn.node_guid_tbl), __get_stats, 701 (void *)&fs); 702 cl_plock_release(&p_osm->lock); 703 704 gettimeofday(&after, NULL); 705 706 /* report the stats */ 707 fprintf(out, "\"%s\" port status:\n", 708 fs.node_type_lim ? ib_get_node_type_str(fs. 709 node_type_lim) : "ALL"); 710 fprintf(out, 711 " %" PRIu64 " port(s) scanned on %" PRIu64 712 " nodes in %lu us\n", fs.total_ports, fs.total_nodes, 713 after.tv_usec - before.tv_usec); 714 715 if (fs.ports_down) 716 fprintf(out, " %" PRIu64 " down\n", fs.ports_down); 717 if (fs.ports_active) 718 fprintf(out, " %" PRIu64 " active\n", fs.ports_active); 719 if (fs.ports_1X) 720 fprintf(out, " %" PRIu64 " at 1X\n", fs.ports_1X); 721 if (fs.ports_4X) 722 fprintf(out, " %" PRIu64 " at 4X\n", fs.ports_4X); 723 if (fs.ports_8X) 724 fprintf(out, " %" PRIu64 " at 8X\n", fs.ports_8X); 725 if (fs.ports_12X) 726 fprintf(out, " %" PRIu64 " at 12X\n", fs.ports_12X); 727 728 if (fs.ports_sdr) 729 fprintf(out, " %" PRIu64 " at 2.5 Gbps\n", fs.ports_sdr); 730 if (fs.ports_ddr) 731 fprintf(out, " %" PRIu64 " at 5.0 Gbps\n", fs.ports_ddr); 732 if (fs.ports_qdr) 733 fprintf(out, " %" PRIu64 " at 10.0 Gbps\n", fs.ports_qdr); 734 735 if (fs.ports_disabled + fs.ports_reduced_speed + fs.ports_reduced_width 736 > 0) { 737 fprintf(out, "\nPossible issues:\n"); 738 } 739 if (fs.ports_disabled) { 740 fprintf(out, " %" PRIu64 " disabled\n", fs.ports_disabled); 741 __print_port_report(out, fs.disabled_ports); 742 } 743 if (fs.ports_reduced_speed) { 744 fprintf(out, " %" PRIu64 " with reduced speed\n", 745 fs.ports_reduced_speed); 746 __print_port_report(out, fs.reduced_speed_ports); 747 } 748 if (fs.ports_reduced_width) { 749 fprintf(out, " %" PRIu64 " with reduced width\n", 750 fs.ports_reduced_width); 751 __print_port_report(out, fs.reduced_width_ports); 752 } 753 fprintf(out, "\n"); 754} 755 756static void switchbalance_check(osm_opensm_t * p_osm, 757 osm_switch_t * p_sw, FILE * out, int verbose) 758{ 759 uint8_t port_num; 760 uint8_t num_ports; 761 const cl_qmap_t *p_port_tbl; 762 osm_port_t *p_port; 763 osm_physp_t *p_physp; 764 osm_physp_t *p_rem_physp; 765 osm_node_t *p_rem_node; 766 uint32_t count[255]; /* max ports is a uint8_t */ 767 uint8_t output_ports[255]; 768 uint8_t output_ports_count = 0; 769 uint32_t min_count = 0xFFFFFFFF; 770 uint32_t max_count = 0; 771 unsigned int i; 772 773 memset(count, '\0', sizeof(uint32_t) * 255); 774 775 /* Count port usage */ 776 p_port_tbl = &p_osm->subn.port_guid_tbl; 777 for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); 778 p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); 779 p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { 780 uint16_t min_lid_ho; 781 uint16_t max_lid_ho; 782 uint16_t lid_ho; 783 784 /* Don't count switches in port usage */ 785 if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) 786 continue; 787 788 osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 789 790 if (min_lid_ho == 0 || max_lid_ho == 0) 791 continue; 792 793 for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { 794 port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); 795 if (port_num == OSM_NO_PATH) 796 continue; 797 798 count[port_num]++; 799 } 800 } 801 802 num_ports = p_sw->num_ports; 803 for (port_num = 1; port_num < num_ports; port_num++) { 804 p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); 805 806 /* if port is down/unhealthy, don't consider it in 807 * min/max calculations 808 */ 809 if (!p_physp || !osm_physp_is_healthy(p_physp) 810 || !osm_physp_get_remote(p_physp)) 811 continue; 812 813 p_rem_physp = osm_physp_get_remote(p_physp); 814 p_rem_node = osm_physp_get_node_ptr(p_rem_physp); 815 816 /* If we are directly connected to a CA/router, its not really 817 * up for balancing consideration. 818 */ 819 if (osm_node_get_type(p_rem_node) != IB_NODE_TYPE_SWITCH) 820 continue; 821 822 output_ports[output_ports_count] = port_num; 823 output_ports_count++; 824 825 if (count[port_num] < min_count) 826 min_count = count[port_num]; 827 if (count[port_num] > max_count) 828 max_count = count[port_num]; 829 } 830 831 if (verbose || ((max_count - min_count) > 1)) { 832 if ((max_count - min_count) > 1) 833 fprintf(out, 834 "Unbalanced Switch: 0x%016" PRIx64 " (%s)\n", 835 cl_ntoh64(p_sw->p_node->node_info.node_guid), 836 p_sw->p_node->print_desc); 837 else 838 fprintf(out, 839 "Switch: 0x%016" PRIx64 " (%s)\n", 840 cl_ntoh64(p_sw->p_node->node_info.node_guid), 841 p_sw->p_node->print_desc); 842 843 for (i = 0; i < output_ports_count; i++) { 844 fprintf(out, 845 "Port %d: %d\n", 846 output_ports[i], count[output_ports[i]]); 847 } 848 } 849} 850 851static void switchbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 852{ 853 char *p_cmd; 854 uint64_t guid = 0; 855 osm_switch_t *p_sw; 856 int verbose = 0; 857 858 p_cmd = next_token(p_last); 859 if (p_cmd) { 860 char *p_end; 861 862 if (strcmp(p_cmd, "verbose") == 0) { 863 verbose++; 864 p_cmd = next_token(p_last); 865 } 866 867 if (p_cmd) { 868 guid = strtoull(p_cmd, &p_end, 0); 869 if (!guid || *p_end != '\0') { 870 fprintf(out, "Invalid guid specified\n"); 871 help_switchbalance(out, 1); 872 return; 873 } 874 } 875 } 876 877 cl_plock_acquire(&p_osm->lock); 878 if (guid) { 879 p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); 880 if (!p_sw) { 881 fprintf(out, "guid not found\n"); 882 goto lock_exit; 883 } 884 885 switchbalance_check(p_osm, p_sw, out, verbose); 886 } else { 887 cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; 888 for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); 889 p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); 890 p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) 891 switchbalance_check(p_osm, p_sw, out, verbose); 892 } 893lock_exit: 894 cl_plock_release(&p_osm->lock); 895 return; 896} 897 898static void lidbalance_check(osm_opensm_t * p_osm, 899 osm_switch_t * p_sw, FILE * out) 900{ 901 uint8_t port_num; 902 const cl_qmap_t *p_port_tbl; 903 osm_port_t *p_port; 904 905 p_port_tbl = &p_osm->subn.port_guid_tbl; 906 for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); 907 p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); 908 p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { 909 uint32_t port_count[255]; /* max ports is a uint8_t */ 910 osm_node_t *rem_node[255]; 911 uint32_t rem_node_count; 912 uint32_t rem_count[255]; 913 osm_physp_t *p_physp; 914 osm_physp_t *p_rem_physp; 915 osm_node_t *p_rem_node; 916 uint32_t port_min_count = 0xFFFFFFFF; 917 uint32_t port_max_count = 0; 918 uint32_t rem_min_count = 0xFFFFFFFF; 919 uint32_t rem_max_count = 0; 920 uint16_t min_lid_ho; 921 uint16_t max_lid_ho; 922 uint16_t lid_ho; 923 uint8_t num_ports; 924 unsigned int i; 925 926 /* we only care about non-switches */ 927 if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) 928 continue; 929 930 osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 931 932 if (min_lid_ho == 0 || max_lid_ho == 0) 933 continue; 934 935 memset(port_count, '\0', sizeof(uint32_t) * 255); 936 memset(rem_node, '\0', sizeof(osm_node_t *) * 255); 937 rem_node_count = 0; 938 memset(rem_count, '\0', sizeof(uint32_t) * 255); 939 940 for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { 941 boolean_t rem_node_found = FALSE; 942 unsigned int indx = 0; 943 944 port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); 945 if (port_num == OSM_NO_PATH) 946 continue; 947 948 p_physp = 949 osm_node_get_physp_ptr(p_sw->p_node, port_num); 950 951 /* if port is down/unhealthy, can't calculate */ 952 if (!p_physp || !osm_physp_is_healthy(p_physp) 953 || !osm_physp_get_remote(p_physp)) 954 continue; 955 956 p_rem_physp = osm_physp_get_remote(p_physp); 957 p_rem_node = osm_physp_get_node_ptr(p_rem_physp); 958 959 /* determine if we've seen this remote node before. 960 * If not, store it. If yes, update the counter 961 */ 962 for (i = 0; i < rem_node_count; i++) { 963 if (rem_node[i] == p_rem_node) { 964 rem_node_found = TRUE; 965 indx = i; 966 break; 967 } 968 } 969 970 if (!rem_node_found) { 971 rem_node[rem_node_count] = p_rem_node; 972 rem_count[rem_node_count]++; 973 indx = rem_node_count; 974 rem_node_count++; 975 } else 976 rem_count[indx]++; 977 978 port_count[port_num]++; 979 } 980 981 if (!rem_node_count) 982 continue; 983 984 for (i = 0; i < rem_node_count; i++) { 985 if (rem_count[i] < rem_min_count) 986 rem_min_count = rem_count[i]; 987 if (rem_count[i] > rem_max_count) 988 rem_max_count = rem_count[i]; 989 } 990 991 num_ports = p_sw->num_ports; 992 for (i = 0; i < num_ports; i++) { 993 if (!port_count[i]) 994 continue; 995 if (port_count[i] < port_min_count) 996 port_min_count = port_count[i]; 997 if (port_count[i] > port_max_count) 998 port_max_count = port_count[i]; 999 } 1000 1001 /* Output if this CA/router is being forwarded an unbalanced number of 1002 * times to a destination. 1003 */ 1004 if ((rem_max_count - rem_min_count) > 1) { 1005 fprintf(out, 1006 "Unbalanced Remote Forwarding: Switch 0x%016" 1007 PRIx64 " (%s): ", 1008 cl_ntoh64(p_sw->p_node->node_info.node_guid), 1009 p_sw->p_node->print_desc); 1010 if (osm_node_get_type(p_port->p_node) == 1011 IB_NODE_TYPE_CA) 1012 fprintf(out, "CA"); 1013 else if (osm_node_get_type(p_port->p_node) == 1014 IB_NODE_TYPE_ROUTER) 1015 fprintf(out, "Router"); 1016 fprintf(out, " 0x%016" PRIx64 " (%s): ", 1017 cl_ntoh64(p_port->p_node->node_info.node_guid), 1018 p_port->p_node->print_desc); 1019 for (i = 0; i < rem_node_count; i++) { 1020 fprintf(out, 1021 "Dest 0x%016" PRIx64 "(%s) - %u ", 1022 cl_ntoh64(rem_node[i]->node_info. 1023 node_guid), 1024 rem_node[i]->print_desc, rem_count[i]); 1025 } 1026 fprintf(out, "\n"); 1027 } 1028 1029 /* Output if this CA/router is being forwarded through a port 1030 * an unbalanced number of times. 1031 */ 1032 if ((port_max_count - port_min_count) > 1) { 1033 fprintf(out, 1034 "Unbalanced Port Forwarding: Switch 0x%016" 1035 PRIx64 " (%s): ", 1036 cl_ntoh64(p_sw->p_node->node_info.node_guid), 1037 p_sw->p_node->print_desc); 1038 if (osm_node_get_type(p_port->p_node) == 1039 IB_NODE_TYPE_CA) 1040 fprintf(out, "CA"); 1041 else if (osm_node_get_type(p_port->p_node) == 1042 IB_NODE_TYPE_ROUTER) 1043 fprintf(out, "Router"); 1044 fprintf(out, " 0x%016" PRIx64 " (%s): ", 1045 cl_ntoh64(p_port->p_node->node_info.node_guid), 1046 p_port->p_node->print_desc); 1047 for (i = 0; i < num_ports; i++) { 1048 if (!port_count[i]) 1049 continue; 1050 fprintf(out, "Port %u - %u: ", i, 1051 port_count[i]); 1052 } 1053 fprintf(out, "\n"); 1054 } 1055 } 1056} 1057 1058static void lidbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1059{ 1060 char *p_cmd; 1061 uint64_t guid = 0; 1062 osm_switch_t *p_sw; 1063 1064 p_cmd = next_token(p_last); 1065 if (p_cmd) { 1066 char *p_end; 1067 1068 guid = strtoull(p_cmd, &p_end, 0); 1069 if (!guid || *p_end != '\0') { 1070 fprintf(out, "Invalid switchguid specified\n"); 1071 help_lidbalance(out, 1); 1072 return; 1073 } 1074 } 1075 1076 cl_plock_acquire(&p_osm->lock); 1077 if (guid) { 1078 p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); 1079 if (!p_sw) { 1080 fprintf(out, "switchguid not found\n"); 1081 goto lock_exit; 1082 } 1083 lidbalance_check(p_osm, p_sw, out); 1084 } else { 1085 cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; 1086 for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); 1087 p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); 1088 p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) 1089 lidbalance_check(p_osm, p_sw, out); 1090 } 1091 1092lock_exit: 1093 cl_plock_release(&p_osm->lock); 1094 return; 1095} 1096 1097static void dump_conf_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1098{ 1099 osm_subn_output_conf(out, &p_osm->subn.opt); 1100} 1101 1102#ifdef ENABLE_OSM_PERF_MGR 1103static void perfmgr_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1104{ 1105 char *p_cmd; 1106 1107 p_cmd = next_token(p_last); 1108 if (p_cmd) { 1109 if (strcmp(p_cmd, "enable") == 0) { 1110 osm_perfmgr_set_state(&(p_osm->perfmgr), 1111 PERFMGR_STATE_ENABLED); 1112 } else if (strcmp(p_cmd, "disable") == 0) { 1113 osm_perfmgr_set_state(&(p_osm->perfmgr), 1114 PERFMGR_STATE_DISABLE); 1115 } else if (strcmp(p_cmd, "clear_counters") == 0) { 1116 osm_perfmgr_clear_counters(&(p_osm->perfmgr)); 1117 } else if (strcmp(p_cmd, "dump_counters") == 0) { 1118 p_cmd = next_token(p_last); 1119 if (p_cmd && (strcmp(p_cmd, "mach") == 0)) { 1120 osm_perfmgr_dump_counters(&(p_osm->perfmgr), 1121 PERFMGR_EVENT_DB_DUMP_MR); 1122 } else { 1123 osm_perfmgr_dump_counters(&(p_osm->perfmgr), 1124 PERFMGR_EVENT_DB_DUMP_HR); 1125 } 1126 } else if (strcmp(p_cmd, "print_counters") == 0) { 1127 p_cmd = next_token(p_last); 1128 if (p_cmd) { 1129 osm_perfmgr_print_counters(&(p_osm->perfmgr), 1130 p_cmd, out); 1131 } else { 1132 fprintf(out, 1133 "print_counters requires a node name to be specified\n"); 1134 } 1135 } else if (strcmp(p_cmd, "sweep_time") == 0) { 1136 p_cmd = next_token(p_last); 1137 if (p_cmd) { 1138 uint16_t time_s = atoi(p_cmd); 1139 osm_perfmgr_set_sweep_time_s(&(p_osm->perfmgr), 1140 time_s); 1141 } else { 1142 fprintf(out, 1143 "sweep_time requires a time period (in seconds) to be specified\n"); 1144 } 1145 } else { 1146 fprintf(out, "\"%s\" option not found\n", p_cmd); 1147 } 1148 } else { 1149 fprintf(out, "Performance Manager status:\n" 1150 "state : %s\n" 1151 "sweep state : %s\n" 1152 "sweep time : %us\n" 1153 "outstanding queries/max : %d/%u\n", 1154 osm_perfmgr_get_state_str(&(p_osm->perfmgr)), 1155 osm_perfmgr_get_sweep_state_str(&(p_osm->perfmgr)), 1156 osm_perfmgr_get_sweep_time_s(&(p_osm->perfmgr)), 1157 p_osm->perfmgr.outstanding_queries, 1158 p_osm->perfmgr.max_outstanding_queries); 1159 } 1160} 1161#endif /* ENABLE_OSM_PERF_MGR */ 1162 1163static void quit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1164{ 1165 osm_console_exit(&p_osm->console, &p_osm->log); 1166} 1167 1168static void help_version(FILE * out, int detail) 1169{ 1170 fprintf(out, "version -- print the OSM version\n"); 1171} 1172 1173static void version_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) 1174{ 1175 fprintf(out, "%s build %s %s\n", p_osm->osm_version, __DATE__, __TIME__); 1176} 1177 1178/* more parse routines go here */ 1179 1180static const struct command console_cmds[] = { 1181 {"help", &help_command, &help_parse}, 1182 {"quit", &help_quit, &quit_parse}, 1183 {"loglevel", &help_loglevel, &loglevel_parse}, 1184 {"priority", &help_priority, &priority_parse}, 1185 {"resweep", &help_resweep, &resweep_parse}, 1186 {"reroute", &help_reroute, &reroute_parse}, 1187 {"status", &help_status, &status_parse}, 1188 {"logflush", &help_logflush, &logflush_parse}, 1189 {"querylid", &help_querylid, &querylid_parse}, 1190 {"portstatus", &help_portstatus, &portstatus_parse}, 1191 {"switchbalance", &help_switchbalance, &switchbalance_parse}, 1192 {"lidbalance", &help_lidbalance, &lidbalance_parse}, 1193 {"dump_conf", &help_dump_conf, &dump_conf_parse}, 1194 {"version", &help_version, &version_parse}, 1195#ifdef ENABLE_OSM_PERF_MGR 1196 {"perfmgr", &help_perfmgr, &perfmgr_parse}, 1197#endif /* ENABLE_OSM_PERF_MGR */ 1198 {NULL, NULL, NULL} /* end of array */ 1199}; 1200 1201static void parse_cmd_line(char *line, osm_opensm_t * p_osm) 1202{ 1203 char *p_cmd, *p_last; 1204 int i, found = 0; 1205 FILE *out = p_osm->console.out; 1206 1207 while (isspace(*line)) 1208 line++; 1209 if (!*line) 1210 return; 1211 1212 /* find first token which is the command */ 1213 p_cmd = strtok_r(line, " \t\n\r", &p_last); 1214 if (p_cmd) { 1215 for (i = 0; console_cmds[i].name; i++) { 1216 if (loop_command.on) { 1217 if (!strcmp(p_cmd, "q")) { 1218 loop_command.on = 0; 1219 } 1220 found = 1; 1221 break; 1222 } 1223 if (!strcmp(p_cmd, console_cmds[i].name)) { 1224 found = 1; 1225 console_cmds[i].parse_function(&p_last, p_osm, 1226 out); 1227 break; 1228 } 1229 } 1230 if (!found) { 1231 fprintf(out, "%s : Command not found\n\n", p_cmd); 1232 help_command(out, 0); 1233 } 1234 } else { 1235 fprintf(out, "Error parsing command line: `%s'\n", line); 1236 } 1237 if (loop_command.on) { 1238 fprintf(out, "use \"q<ret>\" to quit loop\n"); 1239 fflush(out); 1240 } 1241} 1242 1243void osm_console(osm_opensm_t * p_osm) 1244{ 1245 struct pollfd pollfd[2]; 1246 char *p_line; 1247 size_t len; 1248 ssize_t n; 1249 struct pollfd *fds; 1250 nfds_t nfds; 1251 osm_console_t *p_oct = &p_osm->console; 1252 osm_log_t *p_log = &p_osm->log; 1253 1254 pollfd[0].fd = p_oct->socket; 1255 pollfd[0].events = POLLIN; 1256 pollfd[0].revents = 0; 1257 1258 pollfd[1].fd = p_oct->in_fd; 1259 pollfd[1].events = POLLIN; 1260 pollfd[1].revents = 0; 1261 1262 fds = p_oct->socket < 0 ? &pollfd[1] : pollfd; 1263 nfds = p_oct->socket < 0 || pollfd[1].fd < 0 ? 1 : 2; 1264 1265 if (loop_command.on && loop_command_check_time() && 1266 loop_command.loop_function) { 1267 if (p_oct->out) { 1268 loop_command.loop_function(p_osm, p_oct->out); 1269 fflush(p_oct->out); 1270 } else { 1271 loop_command.on = 0; 1272 } 1273 } 1274 1275 if (poll(fds, nfds, 1000) <= 0) 1276 return; 1277 1278#ifdef ENABLE_OSM_CONSOLE_SOCKET 1279 if (pollfd[0].revents & POLLIN) { 1280 int new_fd = 0; 1281 struct sockaddr_in sin; 1282 socklen_t len = sizeof(sin); 1283 struct hostent *hent; 1284 if ((new_fd = accept(p_oct->socket, &sin, &len)) < 0) { 1285 OSM_LOG(p_log, OSM_LOG_ERROR, 1286 "ERR 4B04: Failed to accept console socket: %s\n", 1287 strerror(errno)); 1288 p_oct->in_fd = -1; 1289 return; 1290 } 1291 if (inet_ntop 1292 (AF_INET, &sin.sin_addr, p_oct->client_ip, 1293 sizeof(p_oct->client_ip)) == NULL) { 1294 snprintf(p_oct->client_ip, 64, "STRING_UNKNOWN"); 1295 } 1296 if ((hent = gethostbyaddr((const char *)&sin.sin_addr, 1297 sizeof(struct in_addr), 1298 AF_INET)) == NULL) { 1299 snprintf(p_oct->client_hn, 128, "STRING_UNKNOWN"); 1300 } else { 1301 snprintf(p_oct->client_hn, 128, "%s", hent->h_name); 1302 } 1303 if (is_authorized(p_oct)) { 1304 cio_open(p_oct, new_fd, p_log); 1305 } else { 1306 OSM_LOG(p_log, OSM_LOG_ERROR, 1307 "ERR 4B05: Console connection denied: %s (%s)\n", 1308 p_oct->client_hn, p_oct->client_ip); 1309 close(new_fd); 1310 } 1311 return; 1312 } 1313#endif 1314 1315 if (pollfd[1].revents & POLLIN) { 1316 p_line = NULL; 1317 /* Get input line */ 1318 n = getline(&p_line, &len, p_oct->in); 1319 if (n > 0) { 1320 /* Parse and act on input */ 1321 parse_cmd_line(p_line, p_osm); 1322 if (!loop_command.on) { 1323 osm_console_prompt(p_oct->out); 1324 } 1325 } else 1326 osm_console_exit(p_oct, p_log); 1327 if (p_line) 1328 free(p_line); 1329 } 1330} 1331