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