[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