2 * Copyright (c) 2005-2008 Voltaire, Inc. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
36 #endif /* HAVE_CONFIG_H */
38 #define _GNU_SOURCE /* for getline */
42 #include <sys/types.h>
43 #include <sys/socket.h>
45 #ifdef ENABLE_OSM_CONSOLE_SOCKET
46 #include <arpa/inet.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>
59 void (*help_function) (FILE * out, int detail);
60 void (*parse_function) (char **p_last, osm_opensm_t * p_osm,
68 void (*loop_function) (osm_opensm_t * p_osm, FILE * out);
70 on: 0, delay_s: 2, loop_function:NULL};
72 static const struct command console_cmds[];
74 static inline char *next_token(char **p_last)
76 return strtok_r(NULL, " \t\n\r", p_last);
79 static void help_command(FILE * out, int detail)
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);
90 static void help_quit(FILE * out, int detail)
92 fprintf(out, "quit (not valid in local mode; use ctl-c)\n");
95 static void help_loglevel(FILE * out, int detail)
97 fprintf(out, "loglevel [<log-level>]\n");
99 fprintf(out, " log-level is OR'ed from the following\n");
100 fprintf(out, " OSM_LOG_NONE 0x%02X\n",
102 fprintf(out, " OSM_LOG_ERROR 0x%02X\n",
104 fprintf(out, " OSM_LOG_INFO 0x%02X\n",
106 fprintf(out, " OSM_LOG_VERBOSE 0x%02X\n",
108 fprintf(out, " OSM_LOG_DEBUG 0x%02X\n",
110 fprintf(out, " OSM_LOG_FUNCS 0x%02X\n",
112 fprintf(out, " OSM_LOG_FRAMES 0x%02X\n",
114 fprintf(out, " OSM_LOG_ROUTING 0x%02X\n",
116 fprintf(out, " OSM_LOG_SYS 0x%02X\n",
119 fprintf(out, " OSM_LOG_DEFAULT_LEVEL 0x%02X\n",
120 OSM_LOG_DEFAULT_LEVEL);
124 static void help_priority(FILE * out, int detail)
126 fprintf(out, "priority [<sm-priority>]\n");
129 static void help_resweep(FILE * out, int detail)
131 fprintf(out, "resweep [heavy|light]\n");
134 static void help_reroute(FILE * out, int detail)
136 fprintf(out, "reroute\n");
138 fprintf(out, "reroute the fabric\n");
142 static void help_status(FILE * out, int detail)
144 fprintf(out, "status [loop]\n");
146 fprintf(out, " loop -- type \"q<ret>\" to quit\n");
150 static void help_logflush(FILE * out, int detail)
152 fprintf(out, "logflush -- flush the opensm.log file\n");
155 static void help_querylid(FILE * out, int detail)
158 "querylid lid -- print internal information about the lid specified\n");
161 static void help_portstatus(FILE * out, int detail)
163 fprintf(out, "portstatus [ca|switch|router]\n");
165 fprintf(out, "summarize port status\n");
167 " [ca|switch|router] -- limit the results to the node type specified\n");
172 static void help_switchbalance(FILE * out, int detail)
174 fprintf(out, "switchbalance [verbose] [guid]\n");
176 fprintf(out, "output switch balancing information\n");
178 " [verbose] -- verbose output\n"
179 " [guid] -- limit results to specified guid\n");
183 static void help_lidbalance(FILE * out, int detail)
185 fprintf(out, "lidbalance [switchguid]\n");
187 fprintf(out, "output lid balanced forwarding information\n");
189 " [switchguid] -- limit results to specified switch guid\n");
193 static void help_dump_conf(FILE *out, int detail)
195 fprintf(out, "dump_conf\n");
197 fprintf(out, "dump current opensm configuration\n");
201 #ifdef ENABLE_OSM_PERF_MGR
202 static void help_perfmgr(FILE * out, int detail)
205 "perfmgr [enable|disable|clear_counters|dump_counters|sweep_time[seconds]]\n");
208 "perfmgr -- print the performance manager state\n");
210 " [enable|disable] -- change the perfmgr state\n");
212 " [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n");
214 " [clear_counters] -- clear the counters stored\n");
216 " [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n");
218 " [print_counters <nodename|nodeguid>] -- print the counters for the specified node\n");
221 #endif /* ENABLE_OSM_PERF_MGR */
223 /* more help routines go here */
225 static void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
230 p_cmd = next_token(p_last);
232 help_command(out, 0);
234 for (i = 1; console_cmds[i].name; i++) {
235 if (!strcmp(p_cmd, console_cmds[i].name)) {
237 console_cmds[i].help_function(out, 1);
242 fprintf(out, "%s : Command not found\n\n", p_cmd);
243 help_command(out, 0);
248 static void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
253 p_cmd = next_token(p_last);
255 fprintf(out, "Current log level is 0x%x\n",
256 osm_log_get_level(&p_osm->log));
258 /* Handle x, 0x, and decimal specification of log level */
259 if (!strncmp(p_cmd, "x", 1)) {
261 level = strtoul(p_cmd, NULL, 16);
263 if (!strncmp(p_cmd, "0x", 2)) {
265 level = strtoul(p_cmd, NULL, 16);
267 level = strtol(p_cmd, NULL, 10);
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);
273 fprintf(out, "Invalid log level 0x%x\n", level);
277 static void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
282 p_cmd = next_token(p_last);
284 fprintf(out, "Current sm-priority is %d\n",
285 p_osm->subn.opt.sm_priority);
287 priority = strtol(p_cmd, NULL, 0);
288 if (0 > priority || 15 < priority)
290 "Invalid sm-priority %d; must be between 0 and 15\n",
293 fprintf(out, "Setting sm-priority to %d\n", priority);
294 osm_set_sm_priority(&p_osm->sm, (uint8_t)priority);
299 static char *sm_state_str(int state)
302 case IB_SMINFO_STATE_DISCOVERING:
303 return ("Discovering");
304 case IB_SMINFO_STATE_STANDBY:
306 case IB_SMINFO_STATE_NOTACTIVE:
307 return ("Not Active");
308 case IB_SMINFO_STATE_MASTER:
314 static char *sa_state_str(osm_sa_state_t state)
317 case OSM_SA_STATE_INIT:
319 case OSM_SA_STATE_READY:
325 static void print_status(osm_opensm_t * p_osm, FILE * out)
327 cl_list_item_t *item;
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));
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>");
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))
349 ((osm_epi_plugin_t *)item)->plugin_name);
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)));
357 fprintf(out, "\n MAD stats\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"
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);
394 cl_plock_release(&p_osm->lock);
398 static int loop_command_check_time(void)
400 time_t cur = time(NULL);
401 if ((loop_command.previous + loop_command.delay_s) < cur) {
402 loop_command.previous = cur;
408 static void status_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
412 p_cmd = next_token(p_last);
414 if (strcmp(p_cmd, "loop") == 0) {
415 fprintf(out, "Looping on status command...\n");
418 loop_command.previous = time(NULL);
419 loop_command.loop_function = print_status;
425 print_status(p_osm, out);
428 static void resweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
432 p_cmd = next_token(p_last);
434 (strcmp(p_cmd, "heavy") != 0 && strcmp(p_cmd, "light") != 0)) {
435 fprintf(out, "Invalid resweep command\n");
436 help_resweep(out, 1);
438 if (strcmp(p_cmd, "heavy") == 0)
439 p_osm->subn.force_heavy_sweep = TRUE;
440 osm_opensm_sweep(p_osm);
444 static void reroute_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
446 p_osm->subn.force_reroute = TRUE;
447 osm_opensm_sweep(p_osm);
450 static void logflush_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
452 fflush(p_osm->log.out_port);
455 static void querylid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
459 osm_port_t *p_port = NULL;
460 char *p_cmd = next_token(p_last);
463 fprintf(out, "no LID specified\n");
464 help_querylid(out, 1);
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)))
472 p_port = cl_ptr_vector_get(&(p_osm->subn.port_lid_tbl), lid);
476 fprintf(out, "Query results for LID %u\n", lid);
478 " GUID : 0x%016" PRIx64 "\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);
487 if (p_port->p_node->sw)
491 for ( /* see above */ ; p < p_port->p_node->physp_tbl_size; p++) {
493 " Port %d health : %s\n",
495 p_port->p_node->physp_table[p].
496 healthy ? "OK" : "ERROR");
499 cl_plock_release(&p_osm->lock);
503 cl_plock_release(&p_osm->lock);
504 fprintf(out, "Invalid lid %d\n", lid);
509 * Data structures for the portstatus command
511 typedef struct _port_report {
512 struct _port_report *next;
515 char print_desc[IB_NODE_DESCRIPTION_SIZE + 1];
519 __tag_port_report(port_report_t ** head, uint64_t node_guid,
520 uint8_t port_num, char *print_desc)
522 port_report_t *rep = malloc(sizeof(*rep));
526 rep->node_guid = node_guid;
527 rep->port_num = port_num;
528 memcpy(rep->print_desc, print_desc, IB_NODE_DESCRIPTION_SIZE + 1);
537 static void __print_port_report(FILE * out, port_report_t * head)
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;
550 uint8_t node_type_lim; /* limit the results; 0 == ALL */
551 uint64_t total_nodes;
552 uint64_t total_ports;
554 uint64_t ports_active;
555 uint64_t ports_disabled;
556 port_report_t *disabled_ports;
561 uint64_t ports_unknown_width;
562 uint64_t ports_reduced_width;
563 port_report_t *reduced_width_ports;
567 uint64_t ports_unknown_speed;
568 uint64_t ports_reduced_speed;
569 port_report_t *reduced_speed_ports;
573 * iterator function to get portstatus on each node
575 static void __get_stats(cl_map_item_t * const p_map_item, void *context)
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);
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)
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;
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);
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++;
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++;
624 switch (active_speed) {
625 case IB_LINK_SPEED_ACTIVE_2_5:
628 case IB_LINK_SPEED_ACTIVE_5:
631 case IB_LINK_SPEED_ACTIVE_10:
635 fs->ports_unknown_speed++;
638 switch (active_width) {
639 case IB_LINK_WIDTH_ACTIVE_1X:
642 case IB_LINK_WIDTH_ACTIVE_4X:
645 case IB_LINK_WIDTH_ACTIVE_8X:
648 case IB_LINK_WIDTH_ACTIVE_12X:
652 fs->ports_unknown_width++;
655 if (port_state == IB_LINK_DOWN)
657 else if (port_state == IB_LINK_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++;
670 static void portstatus_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
673 struct timeval before, after;
676 memset(&fs, 0, sizeof(fs));
678 p_cmd = next_token(p_last);
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;
687 fprintf(out, "Node type not understood\n");
688 help_portstatus(out, 1);
693 gettimeofday(&before, NULL);
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,
699 cl_plock_release(&p_osm->lock);
701 gettimeofday(&after, NULL);
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");
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);
713 fprintf(out, " %" PRIu64 " down\n", fs.ports_down);
715 fprintf(out, " %" PRIu64 " active\n", fs.ports_active);
717 fprintf(out, " %" PRIu64 " at 1X\n", fs.ports_1X);
719 fprintf(out, " %" PRIu64 " at 4X\n", fs.ports_4X);
721 fprintf(out, " %" PRIu64 " at 8X\n", fs.ports_8X);
723 fprintf(out, " %" PRIu64 " at 12X\n", fs.ports_12X);
726 fprintf(out, " %" PRIu64 " at 2.5 Gbps\n", fs.ports_sdr);
728 fprintf(out, " %" PRIu64 " at 5.0 Gbps\n", fs.ports_ddr);
730 fprintf(out, " %" PRIu64 " at 10.0 Gbps\n", fs.ports_qdr);
732 if (fs.ports_disabled + fs.ports_reduced_speed + fs.ports_reduced_width
734 fprintf(out, "\nPossible issues:\n");
736 if (fs.ports_disabled) {
737 fprintf(out, " %" PRIu64 " disabled\n", fs.ports_disabled);
738 __print_port_report(out, fs.disabled_ports);
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);
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);
753 static void switchbalance_check(osm_opensm_t * p_osm,
754 osm_switch_t * p_sw, FILE * out, int verbose)
758 const cl_qmap_t *p_port_tbl;
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;
770 memset(count, '\0', sizeof(uint32_t) * 255);
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)) {
781 /* Don't count switches in port usage */
782 if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH)
785 osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
787 if (min_lid_ho == 0 || max_lid_ho == 0)
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)
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);
803 /* if port is down/unhealthy, don't consider it in
804 * min/max calculations
806 if (!p_physp || !osm_physp_is_healthy(p_physp)
807 || !osm_physp_get_remote(p_physp))
810 p_rem_physp = osm_physp_get_remote(p_physp);
811 p_rem_node = osm_physp_get_node_ptr(p_rem_physp);
813 /* If we are directly connected to a CA/router, its not really
814 * up for balancing consideration.
816 if (osm_node_get_type(p_rem_node) != IB_NODE_TYPE_SWITCH)
819 output_ports[output_ports_count] = port_num;
820 output_ports_count++;
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];
828 if (verbose || ((max_count - min_count) > 1)) {
829 if ((max_count - min_count) > 1)
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);
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);
840 for (i = 0; i < output_ports_count; i++) {
843 output_ports[i], count[output_ports[i]]);
848 static void switchbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
855 p_cmd = next_token(p_last);
859 if (strcmp(p_cmd, "verbose") == 0) {
861 p_cmd = next_token(p_last);
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);
874 cl_plock_acquire(&p_osm->lock);
876 p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid));
878 fprintf(out, "guid not found\n");
882 switchbalance_check(p_osm, p_sw, out, verbose);
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);
891 cl_plock_release(&p_osm->lock);
895 static void lidbalance_check(osm_opensm_t * p_osm,
896 osm_switch_t * p_sw, FILE * out)
899 const cl_qmap_t *p_port_tbl;
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;
923 /* we only care about non-switches */
924 if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH)
927 osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
929 if (min_lid_ho == 0 || max_lid_ho == 0)
932 memset(port_count, '\0', sizeof(uint32_t) * 255);
933 memset(rem_node, '\0', sizeof(osm_node_t *) * 255);
935 memset(rem_count, '\0', sizeof(uint32_t) * 255);
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;
941 port_num = osm_switch_get_port_by_lid(p_sw, lid_ho);
942 if (port_num == OSM_NO_PATH)
946 osm_node_get_physp_ptr(p_sw->p_node, port_num);
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))
953 p_rem_physp = osm_physp_get_remote(p_physp);
954 p_rem_node = osm_physp_get_node_ptr(p_rem_physp);
956 /* determine if we've seen this remote node before.
957 * If not, store it. If yes, update the counter
959 for (i = 0; i < rem_node_count; i++) {
960 if (rem_node[i] == p_rem_node) {
961 rem_node_found = TRUE;
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;
975 port_count[port_num]++;
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];
988 num_ports = p_sw->num_ports;
989 for (i = 0; i < num_ports; i++) {
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];
998 /* Output if this CA/router is being forwarded an unbalanced number of
999 * times to a destination.
1001 if ((rem_max_count - rem_min_count) > 1) {
1003 "Unbalanced Remote Forwarding: Switch 0x%016"
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) ==
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++) {
1018 "Dest 0x%016" PRIx64 "(%s) - %u ",
1019 cl_ntoh64(rem_node[i]->node_info.
1021 rem_node[i]->print_desc, rem_count[i]);
1026 /* Output if this CA/router is being forwarded through a port
1027 * an unbalanced number of times.
1029 if ((port_max_count - port_min_count) > 1) {
1031 "Unbalanced Port Forwarding: Switch 0x%016"
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) ==
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++) {
1047 fprintf(out, "Port %u - %u: ", i,
1055 static void lidbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
1061 p_cmd = next_token(p_last);
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);
1073 cl_plock_acquire(&p_osm->lock);
1075 p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid));
1077 fprintf(out, "switchguid not found\n");
1080 lidbalance_check(p_osm, p_sw, out);
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);
1090 cl_plock_release(&p_osm->lock);
1094 static void dump_conf_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
1096 osm_subn_output_conf(out, &p_osm->subn.opt);
1099 #ifdef ENABLE_OSM_PERF_MGR
1100 static void perfmgr_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
1104 p_cmd = next_token(p_last);
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);
1120 osm_perfmgr_dump_counters(&(p_osm->perfmgr),
1121 PERFMGR_EVENT_DB_DUMP_HR);
1123 } else if (strcmp(p_cmd, "print_counters") == 0) {
1124 p_cmd = next_token(p_last);
1126 osm_perfmgr_print_counters(&(p_osm->perfmgr),
1130 "print_counters requires a node name to be specified\n");
1132 } else if (strcmp(p_cmd, "sweep_time") == 0) {
1133 p_cmd = next_token(p_last);
1135 uint16_t time_s = atoi(p_cmd);
1136 osm_perfmgr_set_sweep_time_s(&(p_osm->perfmgr),
1140 "sweep_time requires a time period (in seconds) to be specified\n");
1143 fprintf(out, "\"%s\" option not found\n", p_cmd);
1146 fprintf(out, "Performance Manager status:\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);
1158 #endif /* ENABLE_OSM_PERF_MGR */
1160 static void quit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
1162 osm_console_exit(&p_osm->console, &p_osm->log);
1165 static void help_version(FILE * out, int detail)
1167 fprintf(out, "version -- print the OSM version\n");
1170 static void version_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
1172 fprintf(out, "%s build %s %s\n", p_osm->osm_version, __DATE__, __TIME__);
1175 /* more parse routines go here */
1177 static 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 */
1198 static void parse_cmd_line(char *line, osm_opensm_t * p_osm)
1200 char *p_cmd, *p_last;
1202 FILE *out = p_osm->console.out;
1204 while (isspace(*line))
1209 /* find first token which is the command */
1210 p_cmd = strtok_r(line, " \t\n\r", &p_last);
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;
1220 if (!strcmp(p_cmd, console_cmds[i].name)) {
1222 console_cmds[i].parse_function(&p_last, p_osm,
1228 fprintf(out, "%s : Command not found\n\n", p_cmd);
1229 help_command(out, 0);
1232 fprintf(out, "Error parsing command line: `%s'\n", line);
1234 if (loop_command.on) {
1235 fprintf(out, "use \"q<ret>\" to quit loop\n");
1240 void osm_console(osm_opensm_t * p_osm)
1242 struct pollfd pollfd[2];
1248 osm_console_t *p_oct = &p_osm->console;
1249 osm_log_t *p_log = &p_osm->log;
1251 pollfd[0].fd = p_oct->socket;
1252 pollfd[0].events = POLLIN;
1253 pollfd[0].revents = 0;
1255 pollfd[1].fd = p_oct->in_fd;
1256 pollfd[1].events = POLLIN;
1257 pollfd[1].revents = 0;
1259 fds = p_oct->socket < 0 ? &pollfd[1] : pollfd;
1260 nfds = p_oct->socket < 0 || pollfd[1].fd < 0 ? 1 : 2;
1262 if (loop_command.on && loop_command_check_time() &&
1263 loop_command.loop_function) {
1265 loop_command.loop_function(p_osm, p_oct->out);
1268 loop_command.on = 0;
1272 if (poll(fds, nfds, 1000) <= 0)
1275 #ifdef ENABLE_OSM_CONSOLE_SOCKET
1276 if (pollfd[0].revents & POLLIN) {
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",
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");
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");
1298 snprintf(p_oct->client_hn, 128, "%s", hent->h_name);
1300 if (is_authorized(p_oct)) {
1301 cio_open(p_oct, new_fd, p_log);
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);
1312 if (pollfd[1].revents & POLLIN) {
1314 /* Get input line */
1315 n = getline(&p_line, &len, p_oct->in);
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);
1323 osm_console_exit(p_oct, p_log);