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