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