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