[openib-general] [PATCH 1/2] OpenSM: Add socket support to OpenSM console

Hal Rosenstock halr at voltaire.com
Mon Jan 8 04:20:17 PST 2007


OpenSM: Add socket support to OpenSM console

Signed-off-by: Ira Weiny <weiny2 at llnl.gov>
Signed-off-by: Hal Rosenstock <halr at voltaire.com>

diff --git a/osm/include/opensm/osm_console.h b/osm/include/opensm/osm_console.h
index 705f918..2d212f2 100644
--- a/osm/include/opensm/osm_console.h
+++ b/osm/include/opensm/osm_console.h
@@ -38,6 +38,11 @@
 #include <opensm/osm_subnet.h>
 #include <opensm/osm_opensm.h>
 
+#define OSM_COMMAND_LINE_LEN	 120
+#define OSM_COMMAND_PROMPT	 "$ "
+#define OSM_DEFAULT_CONSOLE_PORT 10000
+#define OSM_DAEMON_NAME          "opensm"
+
 #ifdef __cplusplus
 #  define BEGIN_C_DECLS extern "C" {
 #  define END_C_DECLS   }
@@ -48,8 +53,10 @@
 
 BEGIN_C_DECLS
 
+void osm_console_init(osm_subn_opt_t *opt, osm_opensm_t *p_osm);
 void osm_console(osm_opensm_t *p_osm);
-void osm_console_prompt(void);
+void osm_console_prompt(FILE *out);
+void osm_console_close_socket(osm_opensm_t *p_osm);
 
 END_C_DECLS
 
diff --git a/osm/include/opensm/osm_opensm.h b/osm/include/opensm/osm_opensm.h
index 16fef37..482de28 100644
--- a/osm/include/opensm/osm_opensm.h
+++ b/osm/include/opensm/osm_opensm.h
@@ -48,6 +48,7 @@
 #ifndef _OSM_OPENSM_H_
 #define _OSM_OPENSM_H_
 
+#include <stdio.h>
 #include <signal.h>
 #include <complib/cl_dispatcher.h>
 #include <complib/cl_passivelock.h>
@@ -130,6 +131,15 @@ struct osm_routing_engine {
 *		internals cleanup.
 */
 
+typedef struct _osm_console_t
+{
+  int   socket;
+  int   in_fd;
+  int   out_fd;
+  FILE *in;
+  FILE *out;
+} osm_console_t;
+
 /****s* OpenSM: OpenSM/osm_opensm_t
 * NAME
 *	osm_opensm_t
@@ -156,6 +166,7 @@ typedef struct _osm_opensm_t
   cl_plock_t		lock;
   struct osm_routing_engine routing_engine;
   osm_stats_t		stats;
+  osm_console_t		console;
 } osm_opensm_t;
 /*
 * FIELDS
diff --git a/osm/include/opensm/osm_subnet.h b/osm/include/opensm/osm_subnet.h
index 79796e5..c9b04eb 100644
--- a/osm/include/opensm/osm_subnet.h
+++ b/osm/include/opensm/osm_subnet.h
@@ -266,6 +266,7 @@ typedef struct _osm_subn_opt
   boolean_t                no_qos;
   boolean_t                accum_log_file;
   boolean_t                console;
+  uint16_t                 console_port;
   cl_map_t                 port_prof_ignore_guids;
   boolean_t                port_profile_switch_nodes;
   osm_pfn_ui_extension_t   pfn_ui_pre_lid_assign;
diff --git a/osm/opensm/configure.in b/osm/opensm/configure.in
index 1ccf5c6..2d52675 100644
--- a/osm/opensm/configure.in
+++ b/osm/opensm/configure.in
@@ -62,6 +62,22 @@ AC_ARG_ENABLE(debug,
 esac],[debug=false])
 AM_CONDITIONAL(DEBUG, test x$debug = xtrue)
 
+dnl Console over a socket connection
+AC_ARG_ENABLE(console-socket,
+[  --enable-console-socket Enable a console socket, requires tcp_wrappers (default yes)],
+[case $enableval in
+     yes) console_socket=yes ;;
+     no)  console_socket=no ;;
+   esac],
+   console_socket=yes)
+if test $console_socket = yes; then
+  AC_CHECK_LIB(wrap, request_init, [],
+ 	AC_MSG_ERROR([request_init() not found. console-socket requires libwrap.]))
+  AC_DEFINE(ENABLE_OSM_CONSOLE_SOCKET,
+	    1,
+	    [Define as 1 if you want to enable a console on a socket connection])
+fi
+
 dnl Provide user option to select vendor
 OPENIB_APP_OSMV_SEL
 
diff --git a/osm/opensm/main.c b/osm/opensm/main.c
index 374d323..90432be 100644
--- a/osm/opensm/main.c
+++ b/osm/opensm/main.c
@@ -217,6 +217,11 @@ show_usage(void)
           "          4 outstanding SMPs.\n\n" );
   printf( "-console\n"
           "          This option brings up the OpenSM console.\n\n" );
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+  printf( "--console_port <port>\n"
+          "          Specify an alternate telnet port for the console (default %d).\n\n",
+	  OSM_DEFAULT_CONSOLE_PORT);
+#endif
   printf( "-i <equalize-ignore-guids-file>\n"
           "-ignore-guids <equalize-ignore-guids-file>\n"
           "          This option provides the means to define a set of ports\n"
@@ -578,6 +583,9 @@ main(
       {  "cache-options", 0, NULL, 'c'},
       {  "stay_on_fatal", 0, NULL, 'y'},
       {  "honor_guid2lid", 0, NULL, 'x'},
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+      {  "console_port",  1, NULL, 'C'},
+#endif
       {  NULL,            0, NULL,  0 }  /* Required at the end of the array */
     };
 
@@ -679,6 +687,12 @@ main(
       printf(" Enabling OpenSM interactive console\n");
       break;
 
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+    case 'C':
+      opt.console_port = strtol(optarg, NULL, 0);
+      break;
+#endif
+
     case 'd':
       dbg_lvl = strtol(optarg, NULL, 0);
       printf(" d level = 0x%x\n", dbg_lvl);
@@ -931,15 +945,11 @@ main(
   }
   else
   {
+    osm_console_init(&opt, &osm);
+
     /*
       Sit here forever
-      In the future, some sort of console interactivity could
-      be implemented in this loop.
     */
-    if (opt.console) {
-      printf("\nOpenSM Console\n\n");
-      osm_console_prompt();
-    }
     while( !osm_exit_flag ) {
       if (opt.console)
         osm_console(&osm);
@@ -953,6 +963,7 @@ main(
         osm_opensm_sweep( &osm );
       }
     }
+    osm_console_close_socket(&osm);
   }
 
 #if 0
diff --git a/osm/opensm/osm_console.c b/osm/opensm/osm_console.c
index a1a5eec..420acc2 100644
--- a/osm/opensm/osm_console.c
+++ b/osm/opensm/osm_console.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -39,78 +39,91 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+#include <tcpd.h>
+#endif
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <errno.h>
 #include <opensm/osm_console.h>
 
-#define OSM_COMMAND_LINE_LEN	120
-#define OSM_COMMAND_PROMPT	"$ "
-
 struct command {
 	char *name;
-	void (*help_function)(void);
-	void (*parse_function)(char **p_last, osm_opensm_t *p_osm);
+	void (*help_function)(FILE *out, int detail);
+	void (*parse_function)(char **p_last, osm_opensm_t *p_osm, FILE *out);
 };
 
 static const struct command console_cmds[];
 
 static inline char *next_token(char **p_last)
 {
-	return strtok_r(NULL, " \t\n", p_last);
+	return strtok_r(NULL, " \t\n\r", p_last);
 }
 
-static void help_command()
+static void help_command(FILE *out, int detail)
 {
 	int i;
 
-	printf("Supported commands and syntax:\n");
-	printf("help [<command>]\n");
+	fprintf(out, "Supported commands and syntax:\n");
+	fprintf(out, "help [<command>]\n");
 	/* skip help command */
 	for (i = 1; console_cmds[i].name; i++)
-		console_cmds[i].help_function();
+		console_cmds[i].help_function(out, 0);
+}
+
+static void help_quit(FILE *out, int detail)
+{
+	fprintf(out, "quit\n");
 }
 
-static void help_loglevel()
+
+static void help_loglevel(FILE *out, int detail)
 {
-	printf("loglevel [<log-level>]\n");
+	fprintf(out, "loglevel [<log-level>]\n");
 }
 
-static void help_priority()
+static void help_priority(FILE *out, int detail)
 {
-	printf("priority [<sm-priority>]\n");
+	fprintf(out, "priority [<sm-priority>]\n");
 }
 
 /* more help routines go here */
 
-static void help_parse(char **p_last, osm_opensm_t *p_osm)
+static void help_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
 {
 	char *p_cmd;
 	int i, found = 0;
 
 	p_cmd = next_token(p_last);
 	if (!p_cmd)
-		help_command();
+		help_command(out, 0);
 	else {
 		for (i = 1; console_cmds[i].name; i++) {
 			if (!strcmp(p_cmd, console_cmds[i].name)) {
 				found = 1;
-				console_cmds[i].help_function();
+				console_cmds[i].help_function(out, 1);
 				break;
 			}
 		}
 		if (!found) {
-			printf("Command %s not found\n\n", p_cmd);
-			help_command();
+			fprintf(out, "%s : Command not found\n\n", p_cmd);
+			help_command(out, 0);
 		}
 	}
 }
 
-static void loglevel_parse(char **p_last, osm_opensm_t *p_osm)
+static void loglevel_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
 {
 	char *p_cmd;
 	int level;
 
 	p_cmd = next_token(p_last);
 	if (!p_cmd)
-		printf("Current log level is 0x%x\n", osm_log_get_level(&p_osm->log));
+		fprintf(out, "Current log level is 0x%x\n", osm_log_get_level(&p_osm->log));
 	else {
 		/* Handle x, 0x, and decimal specification of log level */
 		if (!strncmp(p_cmd, "x", 1)) { 
@@ -124,38 +137,57 @@ static void loglevel_parse(char **p_last
 				level = strtol(p_cmd, NULL, 10);
 		}
 		if ((level >= 0) && (level < 256)) {
-			printf("Setting log level to 0x%x\n", level);
+			fprintf(out, "Setting log level to 0x%x\n", level);
 			osm_log_set_level(&p_osm->log, level);
 		} else
-			printf("Invalid log level 0x%x\n", level);
+			fprintf(out, "Invalid log level 0x%x\n", level);
 	}
 }
 
-static void priority_parse(char **p_last, osm_opensm_t *p_osm)
+static void priority_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
 {
 	char *p_cmd;
 	int priority;
 
 	p_cmd = next_token(p_last);
 	if (!p_cmd)
-		printf("Current sm-priority is %d\n", p_osm->subn.opt.sm_priority);
+		fprintf(out, "Current sm-priority is %d\n", p_osm->subn.opt.sm_priority);
 	else {
 		priority = strtol(p_cmd, NULL, 0);
 		if (0 > priority || 15 < priority)
-			printf("Invalid sm-priority %d; must be between 0 and 15\n", priority);
+			fprintf(out, "Invalid sm-priority %d; must be between 0 and 15\n", priority);
 		else {
-			printf("Setting sm-priority to %d\n", priority);
+			fprintf(out, "Setting sm-priority to %d\n", priority);
 			p_osm->subn.opt.sm_priority = (uint8_t)priority;
 			/* Does the SM state machine need a kick now ? */
 		}
 	}
 }
 
+/* This is public to be able to close it on exit */
+void osm_console_close_socket(osm_opensm_t *p_osm)
+{
+	if (p_osm->console.socket > 0) {
+		close(p_osm->console.in_fd);
+		p_osm->console.in_fd = -1;
+		p_osm->console.out_fd = -1;
+		p_osm->console.in = NULL;
+		p_osm->console.out = NULL;
+	}
+}
+
+static void quit_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
+{
+	osm_console_close_socket(p_osm);
+}
+
+
 /* more parse routines go here */
 
 static const struct command console_cmds[] =
 {
 	{ "help",	&help_command,		&help_parse},
+	{ "quit",	&help_quit,		&quit_parse},
 	{ "loglevel",	&help_loglevel,		&loglevel_parse},	
 	{ "priority",	&help_priority,		&priority_parse},
 	{ NULL,		NULL,			NULL}	/* end of array */
@@ -165,60 +197,196 @@ static void parse_cmd_line(char *line, o
 {
 	char *p_cmd, *p_last;
 	int i, found = 0;
+	FILE *out = p_osm->console.out;
+
 
 	/* find first token which is the command */
-	p_cmd = strtok_r(line, " \t\n", &p_last);
+	p_cmd = strtok_r(line, " \t\n\r", &p_last);
 	if (p_cmd) {
 		for (i = 0; console_cmds[i].name; i++) {
 			if (!strcmp(p_cmd, console_cmds[i].name)) {
 				found = 1;
-				console_cmds[i].parse_function(&p_last, p_osm);
+				console_cmds[i].parse_function(&p_last, p_osm, out);
 				break;
 			}
 		}
 		if (!found) {
-			printf("Command %s not found\n\n", p_cmd);
-			help_command();
+			fprintf(out, "%s : Command not found\n\n", p_cmd);
+			help_command(out, 0);
 		}
 	} else {
-		printf("Error parsing command line: %s\n", line);
+		fprintf(out, "Error parsing command line: %s\n", line);
 		return;
 	}
 }
 
-void osm_console_prompt(void)
+void osm_console_prompt(FILE *out)
 {
-	printf("%s", OSM_COMMAND_PROMPT);
-	fflush(stdout);
+	if (out) {
+		fprintf(out, "OpenSM %s", OSM_COMMAND_PROMPT);
+		fflush(out);
+	}
 }
 
+void osm_console_init(osm_subn_opt_t *opt, osm_opensm_t *p_osm)
+{
+	p_osm->console.socket = -1;
+	/* set up the file descriptors for the console */
+    	if (opt->console) {
+		p_osm->console.in = stdin;
+		p_osm->console.out = stdout;
+		p_osm->console.in_fd = fileno(stdin);
+		p_osm->console.out_fd = fileno(stdout);
+
+		osm_console_prompt(p_osm->console.out);
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+    	} else {
+		struct sockaddr_in  sin;
+		int optval = 1;
+
+		if ((p_osm->console.socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+		{
+			osm_log(&(p_osm->log), OSM_LOG_ERROR,
+				"osm_console_init: Failed to open console socket : %s\n",
+				strerror(errno));
+			return;
+		}
+		setsockopt(p_osm->console.socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(opt->console_port);
+		sin.sin_addr.s_addr = htonl(INADDR_ANY);
+		if (bind(p_osm->console.socket, &sin, sizeof(sin)) < 0)
+		{
+			osm_log(&(p_osm->log), OSM_LOG_ERROR,
+				"osm_console_init: Failed to bind console socket : %s\n",
+				strerror(errno));
+			return;
+		}
+		if (listen(p_osm->console.socket, 1) < 0)
+		{
+			osm_log(&(p_osm->log), OSM_LOG_ERROR,
+				"osm_console_init: Failed to listen on socket : %s\n",
+				strerror(errno));
+			return;
+		}
+
+		p_osm->console.in = NULL;
+		p_osm->console.out = NULL;
+		p_osm->console.in_fd = -1;
+		p_osm->console.out_fd = -1;
+    		opt->console = 1;
+		osm_log(&(p_osm->log), OSM_LOG_INFO,
+				"osm_console_init: Console listening on port %d\n", opt->console_port);
+#endif
+	}
+}
+
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+static void handle_osm_connection(osm_opensm_t *p_osm, int new_fd,
+				char *client_ip, char *client_hn)
+{
+	char          *p_line;
+	size_t         len;
+	ssize_t        n;
+
+	if (p_osm->console.in_fd >= 0)
+	{
+		FILE *file = fdopen(new_fd, "w+");
+		fprintf(file, "OpenSM Console connection already in use\n"
+				"   kill other session (y/n)? ");
+		fflush(file);
+		p_line = NULL;
+		n = getline(&p_line, &len, file);
+		if (n > 0 && (p_line[0] == 'y' || p_line[0] == 'Y'))
+		{
+			osm_console_close_socket(p_osm);
+		} else {
+			close(new_fd);
+			return;
+		}
+	}
+	p_osm->console.in_fd = new_fd;
+	p_osm->console.out_fd = p_osm->console.in_fd;
+	p_osm->console.in = fdopen(p_osm->console.in_fd, "w+");
+	p_osm->console.out = p_osm->console.in;
+	osm_console_prompt(p_osm->console.out);
+	osm_log(&(p_osm->log), OSM_LOG_INFO,
+			"osm_console_init: Console connection accepted : %s (%s)\n",
+			client_hn, client_ip);
+}
+
+static int connection_ok(char *client_ip, char *client_hn)
+{
+	return (hosts_ctl(OSM_DAEMON_NAME, client_hn, client_ip, "STRING_UNKNOWN"));
+}
+#endif
+
 void osm_console(osm_opensm_t *p_osm)
 {
-	struct pollfd pollfd;
-	char *p_line;
-	size_t len;
-	ssize_t n;
+	struct pollfd  pollfd[2];
+	char          *p_line;
+	size_t         len;
+	ssize_t        n;
 
-	pollfd.fd = 0;
-	pollfd.events = POLLIN;
-	pollfd.revents = 0;
+	pollfd[0].fd = p_osm->console.socket;
+	pollfd[0].events = POLLIN|POLLOUT;
+	pollfd[0].revents = 0;
 
-	if (poll(&pollfd, 1, 10000) <= 0)
+	pollfd[1].fd = p_osm->console.in_fd;
+	pollfd[1].events = POLLIN|POLLOUT;
+	pollfd[1].revents = 0;
+
+	if (poll(pollfd, 2, 10000) <= 0)
 		return;
 
-	if (pollfd.revents|POLLIN) {
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+	if (pollfd[0].revents & POLLIN) {
+		int new_fd = 0;
+		struct sockaddr_in  sin;
+		socklen_t len = sizeof(sin);
+		char client_ip[64];
+		char client_hn[128];
+		struct hostent *hent;
+		if ((new_fd = accept(p_osm->console.socket, &sin, &len)) < 0) {
+			osm_log(&(p_osm->log), OSM_LOG_ERROR,
+				"osm_console: Failed to accept console socket : %s\n",
+				strerror(errno));
+			p_osm->console.in_fd = -1;
+			return;
+		}
+		if (inet_ntop(AF_INET, &sin.sin_addr, client_ip, sizeof(client_ip)) == NULL) {
+			snprintf(client_ip, 64, "STRING_UNKNOWN");
+		}
+    		if ((hent = gethostbyaddr((const char *) &sin.sin_addr,
+                              sizeof(struct in_addr), AF_INET)) == NULL) {
+			snprintf(client_hn, 128, "STRING_UNKNOWN");
+		} else {
+			snprintf(client_hn, 128, "%s", hent->h_name);
+		}
+		if (connection_ok(client_ip, client_hn)) {
+			handle_osm_connection(p_osm, new_fd, client_ip, client_hn);
+		} else {
+			osm_log(&(p_osm->log), OSM_LOG_ERROR,
+				"osm_console: Console connection denied : %s (%s)\n",
+				client_hn, client_ip);
+			close(new_fd);
+		}
+		return;
+	}
+#endif
+
+	if (pollfd[1].revents & POLLIN) {
 		p_line = NULL;
 		/* Get input line */
-		n = getline(&p_line, &len, stdin);
+		n = getline(&p_line, &len, p_osm->console.in);
 		if (n > 0) {
 			/* Parse and act on input */
 			parse_cmd_line(p_line, p_osm);
 			free(p_line);
 		} else {
-			printf("Input error\n");
-			fflush(stdin);
+			fprintf(p_osm->console.out, "Input error\n");
+			fflush(p_osm->console.out);
 		}
-		osm_console_prompt();
+		osm_console_prompt(p_osm->console.out);
 	}
 }
-
diff --git a/osm/opensm/osm_subnet.c b/osm/opensm/osm_subnet.c
index aec4ff2..aff2130 100644
--- a/osm/opensm/osm_subnet.c
+++ b/osm/opensm/osm_subnet.c
@@ -63,6 +63,7 @@
 #include <opensm/osm_node.h>
 #include <opensm/osm_multicast.h>
 #include <opensm/osm_inform.h>
+#include <opensm/osm_console.h>
 
 /**********************************************************************
  **********************************************************************/
@@ -444,6 +445,7 @@ osm_subn_set_default_opt(
   p_opt->sweep_interval = OSM_DEFAULT_SWEEP_INTERVAL_SECS;
   p_opt->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE;
   p_opt->console = FALSE;
+  p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT;
   p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;
   /* by default we will consider waiting for 50x transaction timeout normal */
   p_opt->max_msg_fifo_timeout = 50*OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;







More information about the general mailing list