]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_console.c
MFV r353623: 10473 zfs(1M) missing cross-reference to zfs-program(1M)
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_console.c
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 }