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