diff options
author | John Forte <John.Forte@Sun.COM> | 2009-10-06 19:56:15 -0700 |
---|---|---|
committer | John Forte <John.Forte@Sun.COM> | 2009-10-06 19:56:15 -0700 |
commit | 450396635f70344c58b6b1e4db38cf17ff34445c (patch) | |
tree | fa089b0718400774602b3f29e7e9b326795e2a9b /usr/src/cmd/stmfproxy | |
parent | bd963cb9a079e6b9cd23645670bf4b0185cbfe4c (diff) | |
download | illumos-joyent-450396635f70344c58b6b1e4db38cf17ff34445c.tar.gz |
PSARC/2009/465 COMSTAR ALUA active/standby support
6862774 Add support for ALUA to COMSTAR
6878583 mem leak in stmfGetLuResource()
6850890 stmfTargetProperties.protocol is not populated for stmfGetTargetProperties()
Diffstat (limited to 'usr/src/cmd/stmfproxy')
-rw-r--r-- | usr/src/cmd/stmfproxy/Makefile | 55 | ||||
-rw-r--r-- | usr/src/cmd/stmfproxy/aluaadm/Makefile | 80 | ||||
-rw-r--r-- | usr/src/cmd/stmfproxy/aluaadm/aluaadm.c | 240 | ||||
-rw-r--r-- | usr/src/cmd/stmfproxy/stmfproxy/Makefile | 103 | ||||
-rw-r--r-- | usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c | 541 | ||||
-rw-r--r-- | usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml | 112 |
6 files changed, 1131 insertions, 0 deletions
diff --git a/usr/src/cmd/stmfproxy/Makefile b/usr/src/cmd/stmfproxy/Makefile new file mode 100644 index 0000000000..26cfe571f4 --- /dev/null +++ b/usr/src/cmd/stmfproxy/Makefile @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# cmd/aluademo/Makefile +# + +include ../Makefile.cmd + +SUBDIRS = stmfproxy aluaadm + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +cstyle := TARGET= cstyle +check := TARGET= check + +.KEEP_STATE: + +all install cstyle lint : $(SUBDIRS) + +check: stmfproxy + +clean: $(SUBDIRS) + +clobber: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/Makefile.msg.targ diff --git a/usr/src/cmd/stmfproxy/aluaadm/Makefile b/usr/src/cmd/stmfproxy/aluaadm/Makefile new file mode 100644 index 0000000000..45f528e84d --- /dev/null +++ b/usr/src/cmd/stmfproxy/aluaadm/Makefile @@ -0,0 +1,80 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# +# cmd/iscsid/Makefile +# + +PROG = aluaadm + +include ../../Makefile.cmd + +COMMONBASE = ../../../common + +DEMOBINFILES = \ + $(PROG) + +ROOTDEMODIR = $(ROOT)/usr/demo/comstar +ROOTDEMOBINDIR = $(ROOTDEMODIR)/bin +ROOTDEMOFILES = $(DEMOFILES:%=$(ROOTDEMODIR)/%) +ROOTDEMOBINFILES = $(DEMOBINFILES:%=$(ROOTDEMOBINDIR)/%) + +LOCAL_OBJS = aluaadm.o +LOCAL_SRCS = $(LOCAL_OBJS:%.o=%.c) +COMMON_OBJS = cmdparse.o +COMMON_SRCS = $(COMMON_OBJS:%.o=$(COMMONBASE)/cmdparse/%.c) +OBJS = $(LOCAL_OBJS) $(COMMON_OBJS) +SRCS = $(LOCAL_SRCS) $(COMMON_SRCS) + +CPPFLAGS += -I. -I$(COMMONBASE)/cmdparse +LDLIBS += -lstmf + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +clean: + $(RM) $(OBJS) + +install: all $(ROOTDEMOBINFILES) + +$(ROOTDEMODIR) $(ROOTDEMOBINDIR): + $(INS.dir) + +$(ROOTDEMODIR)/% $(ROOTDEMOBINDIR)/% : % + $(INS.file) + +$(ROOTDEMOBINFILES): $(ROOTDEMOBINDIR) + +cmdparse.o: $(COMMONBASE)/cmdparse/cmdparse.c + $(COMPILE.c) -o $@ $(COMMONBASE)/cmdparse/cmdparse.c + $(POST_PROCESS_O) + +lint: lint_SRCS + +include ../../Makefile.targ diff --git a/usr/src/cmd/stmfproxy/aluaadm/aluaadm.c b/usr/src/cmd/stmfproxy/aluaadm/aluaadm.c new file mode 100644 index 0000000000..5fa1504793 --- /dev/null +++ b/usr/src/cmd/stmfproxy/aluaadm/aluaadm.c @@ -0,0 +1,240 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <sys/types.h> +#include <unistd.h> +#include <wchar.h> +#include <libintl.h> +#include <errno.h> +#include <time.h> +#include <string.h> +#include <assert.h> +#include <getopt.h> +#include <cmdparse.h> +#include <libstmf.h> +#include <signal.h> +#include <pthread.h> +#include <locale.h> + +static char *getExecBasename(char *); +static int setLuStandbyFunc(int, char **, cmdOptions_t *, void *); +static int disableAluaFunc(int, char **, cmdOptions_t *, void *); +static int enableAluaFunc(int, char **, cmdOptions_t *, void *); + +#define OPERANDSTRING_LU "LU-name" +#define OPERANDSTRING_NODE_ID "node ID (0 or 1)" + +#define VERSION_STRING_MAJOR "1" +#define VERSION_STRING_MINOR "0" +#define VERSION_STRING_MAX_LEN 10 + +#define GUID_INPUT 32 + +/* tables set up based on cmdparse instructions */ + +/* add new options here */ +optionTbl_t longOptions[] = { + {NULL, 0, 0, 0} +}; + +/* + * Add new subcommands here + */ +subCommandProps_t subcommands[] = { + {"standby", setLuStandbyFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL}, + {"disable", disableAluaFunc, NULL, NULL, NULL, + OPERAND_NONE, NULL, NULL}, + {"enable", enableAluaFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_NODE_ID, NULL}, + {NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL} +}; + +/* globals */ +char *cmdName; + +/* + * setLuStandbyFunc + * + * Purpose: set lu to standby + * + */ +/*ARGSUSED*/ +static int +setLuStandbyFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + char sGuid[GUID_INPUT + 1]; + stmfGuid inGuid; + unsigned int guid[sizeof (stmfGuid)]; + int i; + int ret = 0; + + if (strlen(operands[0]) != GUID_INPUT) { + (void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, + operands[0], gettext("must be"), GUID_INPUT, + gettext("hexadecimal digits long")); + return (1); + } + + bcopy(operands[0], sGuid, GUID_INPUT); + + for (i = 0; i < GUID_INPUT; i++) + sGuid[i] = tolower(sGuid[i]); + sGuid[i] = 0; + + (void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5], + &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11], + &guid[12], &guid[13], &guid[14], &guid[15]); + + for (i = 0; i < sizeof (stmfGuid); i++) { + inGuid.guid[i] = guid[i]; + } + + ret = stmfLuStandby(&inGuid); + if (ret != STMF_STATUS_SUCCESS) { + switch (ret) { + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_NOT_FOUND: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("not found")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + break; + } + } + return (ret); +} + +/* + * disableAluaFunc + * + * Purpose: disable alua mode + * + */ +/*ARGSUSED*/ +static int +disableAluaFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + return (stmfSetAluaState(B_FALSE, 0)); +} + +/* + * enableAluaFunc + * + * Purpose: enable alua mode + * + */ +/*ARGSUSED*/ +static int +enableAluaFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + uint8_t node_id = 0; + if (operands[0][1] == '1') { + node_id = 1; + } + return (stmfSetAluaState(B_TRUE, node_id)); +} + + +/* + * input: + * execFullName - exec name of program (argv[0]) + * + * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net + * (changed name to lowerCamelCase to keep consistent with this file) + * + * Returns: + * command name portion of execFullName + */ +static char * +getExecBasename(char *execFullname) +{ + char *lastSlash, *execBasename; + + /* guard against '/' at end of command invocation */ + for (;;) { + lastSlash = strrchr(execFullname, '/'); + if (lastSlash == NULL) { + execBasename = execFullname; + break; + } else { + execBasename = lastSlash + 1; + if (*execBasename == '\0') { + *lastSlash = '\0'; + continue; + } + break; + } + } + return (execBasename); +} + +int +main(int argc, char *argv[]) +{ + synTables_t synTables; + char versionString[VERSION_STRING_MAX_LEN]; + int ret; + int funcRet; + void *subcommandArgs = NULL; + + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); + /* set global command name */ + cmdName = getExecBasename(argv[0]); + + (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s", + VERSION_STRING_MAJOR, VERSION_STRING_MINOR); + synTables.versionString = versionString; + synTables.longOptionTbl = &longOptions[0]; + synTables.subCommandPropsTbl = &subcommands[0]; + + ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); + if (ret != 0) { + return (ret); + } + + return (funcRet); +} /* end main */ diff --git a/usr/src/cmd/stmfproxy/stmfproxy/Makefile b/usr/src/cmd/stmfproxy/stmfproxy/Makefile new file mode 100644 index 0000000000..73d75ce1df --- /dev/null +++ b/usr/src/cmd/stmfproxy/stmfproxy/Makefile @@ -0,0 +1,103 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# +# cmd/stmfproxy/stmfproxy/Makefile +# + +PROG = svc-stmfproxy + +COMMONBASE = ../../common + +include ../../Makefile.cmd + +DEMOFILES = \ + stmfproxy.xml + +DEMOBINFILES = \ + $(PROG) + +ROOTDEMODIR = $(ROOT)/usr/demo/comstar +ROOTDEMOBINDIR = $(ROOTDEMODIR)/bin +ROOTDEMOFILES = $(DEMOFILES:%=$(ROOTDEMODIR)/%) +ROOTDEMOBINFILES = $(DEMOBINFILES:%=$(ROOTDEMOBINDIR)/%) + +PRODUCT= $(PROG) +SRCS= $(OBJS:%.o=./%.c) +OBJS= stmfproxy.o +LLOBJS= $(OBJS:%.o=%.ll) +#POFILES= $(OBJS:%.o=%.po) +#POFILE= stmfproxy.po + +$(ROOTDEMODIR)/stmfproxy.xml := FILEMODE = 0444 + + +CCVERBOSE = +LDLIBS += -lnsl -lstmf -lstmfproxy +CPPFLAGS += -I. -I$(COMMONBASE)/cmdparse + +# Uncomment the following to help with debugging +#CFLAGS += -g +#i386_COPTFLAG= +#i386_CCOPTFLAG= + +.KEEP_STATE: + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +LINTFLAGS += -erroff=E_FUNC_HAS_NO_RETURN_STMT +LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +.PARALLEL: $(OBJS) + +all: $(PROG) + +clean: + $(RM) $(PROG) $(OBJS) $(LLOBJS) + +lint: lint_SRCS + +#$(POFILE): $(POFILES) +# $(RM) $@ +# cat $(POFILES) > $@ + +install: all $(ROOTDEMOFILES) $(ROOTDEMOBINFILES) + +$(ROOTDEMODIR) $(ROOTDEMOBINDIR): + $(INS.dir) + +$(ROOTDEMODIR)/% $(ROOTDEMOBINDIR)/% : % + $(INS.file) + +$(ROOTDEMOFILES): $(ROOTDEMODIR) + +$(ROOTDEMOBINFILES): $(ROOTDEMOBINDIR) + +check: $(CHKMANIFEST) + $(CSTYLE) -pPc $(SRCS:%=%) + + +include ../../Makefile.targ diff --git a/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c new file mode 100644 index 0000000000..38115c2b51 --- /dev/null +++ b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c @@ -0,0 +1,541 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <errno.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/stat.h> +#include <sys/sdt.h> +#include <signal.h> +#include <fcntl.h> +#include <libnvpair.h> +#include <libstmf.h> +#include <door.h> +#include <pthread.h> +#include <libscf.h> +#include <locale.h> +#include <sys/stmf_ioctl.h> +#include <sys/pppt_ioctl.h> +#include <libstmfproxy.h> + +#define PPPT_NODE "/devices/pseudo/pppt@0:pppt" +#define USAGE "Usage: %s [-d][-f][-n nodeid] nodename\n" \ + "Note: nodename must be the same on both nodes\n" + + +/* + * static functions + */ +static void daemonInit(void); +static void killHandler(); +static int postMsg(uint_t nelem, uchar_t *aluaMsg); + + +/* + * globals + */ +void *t_handle; /* transport handle */ +char aluaNode[256]; /* one of the two alua peers */ +char myNode[256]; /* this hostname */ +int log_debug = 0; +int fore_ground = 0; +int proxy_hdl; +pt_ops_t *pt_ops; + +/* + * killHandler + * + * Terminates this process on SIGQUIT, SIGINT, SIGTERM + */ +/* ARGSUSED */ +static void +killHandler(int sig) +{ + exit(0); +} + +/* + * doorHandler + * + * Recieve data from the local proxy port provider and relay + * it to the peer node. + */ +/* ARGSUSED */ +void +doorHandler( + void *cookie, + char *args, + size_t alen, + door_desc_t *ddp, + uint_t ndid) +{ + uint32_t result = 0; + + if (ddp != NULL || ndid != 0) { + syslog(LOG_DAEMON|LOG_WARNING, + "descriptor passed to door %p %d", ddp, ndid); + result = EINVAL; + } + + if (args == NULL || alen == 0) { + syslog(LOG_DAEMON|LOG_WARNING, + "empty message passed to door %p %d", args, alen); + result = EFAULT; + } + + if (result == 0) + result = postMsg((uint_t)alen, (uchar_t *)args); + (void) door_return((char *)&result, sizeof (result), NULL, 0); + + syslog(LOG_DAEMON|LOG_WARNING, "door_return FAILED %d", errno); + exit(errno); +} + +static int +postMsg(uint_t nelem, uchar_t *aluaMsg) +{ + uint32_t buflen; + uchar_t *buf; + int ret = 0; + int ns; + + if (t_handle == NULL) { + syslog(LOG_DAEMON|LOG_WARNING, + "postMsg() no transport handle"); + exit(1); + } + + buf = malloc(nelem + sizeof (buflen)); + + buflen = htonl(nelem); /* length in network byte order */ + bcopy(&buflen, buf, sizeof (buflen)); + bcopy(aluaMsg, buf + sizeof (buflen), nelem); + + ns = pt_ops->stmf_proxy_send(t_handle, buf, nelem + sizeof (buflen)); + if (ns != nelem + sizeof (buflen)) { + ret = errno; + if (ret == 0) + ret = ENOTTY; /* something bogus */ + syslog(LOG_DAEMON|LOG_CRIT, "send() call failed: %d", ret); + } + free(buf); + return (ret); +} + +/* + * Multi-thread the data path from the peer node to the local + * proxy port provider. During discover, there can be a large + * burst of messages from the peer node proportional to the number + * of LUs. Multiple threads allow these messages to be processed + * simultaneously. + */ +typedef struct pppt_drv_queue { + struct pppt_drv_queue *next; + uint32_t buflen; + uchar_t *buf; +} pppt_drv_queue_t; + +pppt_drv_queue_t *pq_head = NULL; +pthread_mutex_t pq_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t pq_cond = PTHREAD_COND_INITIALIZER; +int pq_num_threads = 0; +int pq_avail_threads = 0; + +/*ARGSUSED*/ +void * +push_to_drv(void *arg) +{ + pppt_drv_queue_t *pq; + int rc; + + (void) pthread_mutex_lock(&pq_mutex); + pq_num_threads++; + (void) pthread_mutex_unlock(&pq_mutex); + for (;;) { + (void) pthread_mutex_lock(&pq_mutex); + while (pq_head == NULL) { + pq_avail_threads++; + (void) pthread_cond_wait(&pq_cond, &pq_mutex); + pq_avail_threads--; + } + pq = pq_head; + pq_head = pq->next; + pq->next = NULL; + (void) pthread_mutex_unlock(&pq_mutex); + /* Relay the message to the local kernel */ + rc = stmfPostProxyMsg(proxy_hdl, (void *)pq->buf, pq->buflen); + if (rc != STMF_STATUS_SUCCESS) { + /* XXX die ? */ + syslog(LOG_DAEMON|LOG_CRIT, "ioctl failed - %d", errno); + } + free(pq->buf); + free(pq); + } + /*NOTREACHED*/ + return (NULL); +} + +/* + * Receive data from peer and queue it up for the proxy driver. + */ +int message_count = 0; +static void +relay_peer_msg() +{ + uint32_t buflen; + pppt_drv_queue_t *pq, *tmpq; + pthread_t tid; + int rc; + + + /* first receive the length of the message */ + if ((pt_ops->stmf_proxy_recv(t_handle, (uchar_t *)&buflen, + sizeof (buflen))) != sizeof (buflen)) { + syslog(LOG_DAEMON|LOG_WARNING, "recv() call failed: %d", + errno); + exit(1); + } + + pq = malloc(sizeof (*pq)); + pq->next = NULL; + pq->buflen = ntohl(buflen); + pq->buf = malloc(pq->buflen+4); + if (log_debug) { + syslog(LOG_DAEMON|LOG_DEBUG, + "recvMsg: size of buffer - %d", (int)pq->buflen); + } + + if ((pt_ops->stmf_proxy_recv(t_handle, pq->buf, pq->buflen)) != + pq->buflen) { + syslog(LOG_DAEMON|LOG_WARNING, "recv() call failed: %d", + errno); + exit(1); + } + + /* Eat the first message from peer */ + if (message_count++ == 0) { + *(pq->buf+pq->buflen) = 0; + free(pq->buf); + free(pq); + return; + } + + /* Queue the message to the driver */ + (void) pthread_mutex_lock(&pq_mutex); + if (pq_head == NULL) { + pq_head = pq; + } else { + /* add to the tail */ + tmpq = pq_head; + while (tmpq->next != NULL) + tmpq = tmpq->next; + tmpq->next = pq; + } + + /* Make sure there is a thread to service this message */ + if (pq_avail_threads) { + /* wake an available thread */ + (void) pthread_cond_signal(&pq_cond); + (void) pthread_mutex_unlock(&pq_mutex); + } else { + /* no threads available, create a new thread */ + (void) pthread_mutex_unlock(&pq_mutex); + rc = pthread_create(&tid, NULL, push_to_drv, NULL); + if (rc != 0) { + syslog(LOG_DAEMON|LOG_WARNING, + "pthread_create() call failed: %d", rc); + if (pq_num_threads == 0) { + /* never created a thread */ + exit(rc); + } + } + } +} + +/* + * Initialization for a daemon process + */ +static void +daemonInit(void) +{ + pid_t pid; + int devnull; + + if (fore_ground) + return; + + if ((pid = fork()) < 0) { + syslog(LOG_DAEMON|LOG_CRIT, "Could not fork(). Exiting"); + exit(1); + } else if (pid != 0) { + /* + * XXX + * Simple approach for now - let the service go online. + * Later, set-up a pipe to the child and wait until the + * child indicates service is setup. + */ + exit(SMF_EXIT_OK); + } + + (void) setsid(); + + (void) chdir("/"); + + (void) umask(0); + + + devnull = open("/dev/null", O_RDWR); + if (devnull < 0) { + syslog(LOG_DAEMON|LOG_CRIT, + "Failed to open /dev/null. Exiting"); + exit(1); + } + + (void) dup2(devnull, STDIN_FILENO); + (void) dup2(devnull, STDOUT_FILENO); + (void) dup2(devnull, STDERR_FILENO); + (void) close(devnull); +} + +void +daemon_fini(int rc) +{ + /* + * XXX inform the parent about the service state + * For now, just exit on error. + */ + if (rc != 0) + exit(rc); +} + +static int +open_proxy_driver() +{ + int drv_door_fd; + int stmf_ret; + + /* + * Create communication channel for the driver. + */ + if ((drv_door_fd = door_create(doorHandler, NULL, 0)) < 0) { + perror("door_create"); + syslog(LOG_DAEMON|LOG_DEBUG, + "could not create door: errno %d", errno); + return (SMF_EXIT_ERR_FATAL); + } + + stmf_ret = stmfInitProxyDoor(&proxy_hdl, drv_door_fd); + if (stmf_ret != STMF_STATUS_SUCCESS) { + perror("pppt ioctl: door install"); + syslog(LOG_DAEMON|LOG_DEBUG, + "could not install door: errno %d", errno); + return (SMF_EXIT_ERR_FATAL); + } + + return (SMF_EXIT_OK); +} + +/* + * daemon entry + * + * parse arguments + * create resources to talk to child + * if !foreground + * daemonize, run as child + * open proxy driver + * install door in proxy driver + * create socket + * if server-side + * bind socket + * if !foreground + * inform parent things aok + * if parent + * exit(SMF_EXIT_OK) + * if server-side + * accept + * if client-side + * connect + * send hello + * recv hello + * loop on recieve + * XXX anyway to check in envp that we are started by SMF? + */ +int +main(int argc, char *argv[]) +{ + struct sockaddr_in sin; + int rc; + struct sigaction act; + sigset_t sigmask; + int c; + int node = 0; + int node_override = 0; + int server_node = 0; + int server_match = 0; + extern char *optarg; + int stmf_ret; + + (void) setlocale(LC_ALL, ""); + openlog("stmfproxy", LOG_PID, LOG_DAEMON); + (void) setlogmask(LOG_UPTO(LOG_INFO)); + + while ((c = getopt(argc, argv, "dfn:")) != -1) { + switch (c) { + case 'd': + (void) setlogmask(LOG_UPTO(LOG_DEBUG)); + log_debug = 1; + break; + case 'f': + fore_ground = 1; + break; + case 'n': + node_override = 1; + node = atoi(optarg); + break; + default: + /* + * Should never happen from smf + */ + (void) fprintf(stderr, USAGE, argv[0]); + exit(SMF_EXIT_ERR_CONFIG); + break; + } + } + /* + * After the options, only the server argument should remain. + */ + if (optind != argc-1) { + (void) fprintf(stderr, USAGE, argv[0]); + exit(SMF_EXIT_ERR_CONFIG); + } + (void) strcpy(aluaNode, argv[optind]); + syslog(LOG_DAEMON|LOG_DEBUG, "aluaNode %s", aluaNode); + if (gethostname(myNode, 255)) { + perror("gethostname"); + exit(1); + } + if ((inet_aton(aluaNode, &sin.sin_addr)) == 0) { + /* + * Not ipaddr, try hostname match. + */ + server_match = (strcmp(aluaNode, myNode)) ? 0 : 1; + } else { + /* + * see if this is our ip address + */ + (void) fprintf(stderr, "Sorry, cannot use ip adress format\n"); + } + if (server_match) { + server_node = 1; + if (!node_override) + node = 1; + } + + + /* + * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us + */ + act.sa_handler = killHandler; + (void) sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + /* Install the signal handler */ + (void) sigaction(SIGQUIT, &act, NULL); + (void) sigaction(SIGINT, &act, NULL); + (void) sigaction(SIGTERM, &act, NULL); + (void) sigaction(SIGHUP, &act, NULL); + + /* block all signals */ + (void) sigfillset(&sigmask); + + /* unblock SIGQUIT, SIGINT, SIGTERM */ + (void) sigdelset(&sigmask, SIGQUIT); + (void) sigdelset(&sigmask, SIGINT); + (void) sigdelset(&sigmask, SIGTERM); + (void) sigdelset(&sigmask, SIGHUP); + + (void) sigprocmask(SIG_SETMASK, &sigmask, NULL); + + /* time to go backstage */ + daemonInit(); + + if ((rc = open_proxy_driver()) != 0) + daemon_fini(rc); + + if ((rc = stmf_proxy_transport_init("sockets", &pt_ops)) != 0) + daemon_fini(rc); + + /* + * Establish connection + * + * At this point, the parent has exited and the service + * is online. But there are no real proxy services until + * this connect call succeeds. That could take a long time if + * the peer node is down. + */ + t_handle = pt_ops->stmf_proxy_connect(server_node, aluaNode); + if (t_handle == NULL) { + syslog(LOG_DAEMON|LOG_WARNING, + "socket() call failed: %d", errno); + exit(1); + } + + /* The first message is a greeting */ + (void) postMsg((uint_t)strlen(myNode)+1, (uchar_t *)myNode); + /* Read the greeting from peer node */ + relay_peer_msg(); + /* + * Set the alua state in stmf. No need to keep + * the device open since the proxy driver has a reference. + */ + stmf_ret = stmfSetAluaState(B_TRUE, node); + if (stmf_ret != STMF_STATUS_SUCCESS) { + syslog(LOG_DAEMON|LOG_CRIT, "stmf ioctl failed - %x", stmf_ret); + exit(1); + } + + /* service is online */ + daemon_fini(0); + + /* + * Loop relaying data from the peer daemon to the local kernel. + * Data coming from the local kernel is handled asynchronously + * by the door server. + */ + for (;;) { /* loop forever */ + relay_peer_msg(); + } +} diff --git a/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml new file mode 100644 index 0000000000..32913ba0be --- /dev/null +++ b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml @@ -0,0 +1,112 @@ +<?xml version='1.0'?> +<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> + +<!-- + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + Copyright 2009 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + Service manifests for the stmfproxy daemon +--> + +<service_bundle type='manifest' name='SUNWstmfu:svc-stmfproxy'> + +<service + name='system/stmfproxy' + type='service' + version='1'> + + <single_instance/> + + <dependency + name='stmf' + grouping='require_all' + restart_on='none' + type='service'> + <service_fmri value='svc:/system/stmf' /> + </dependency> + + <!-- + Set a timeout of -1 to signify to inetd that we don't want + to timeout this service, since the forked process is the + one that does the services work. This is the case for most/all + legacy inetd services; for services written to take advantage + of Greenlines capabilities, the start method should fork + off a process to handle the request and return a success code. + --> + <exec_method + type='method' + name='start' + exec='/usr/demo/comstar/bin/svc-stmfproxy %{config/proxy_host}' + timeout_seconds='600'> + <method_context> + <method_credential + user='root' + group='root' + privileges='basic,sys_devices' + /> + </method_context> + </exec_method> + + <exec_method + type='method' + name='stop' + exec=':kill' + timeout_seconds='600'> + <method_context> + <method_credential + user='root' + group='root' + privileges='basic,sys_devices' + /> + </method_context> + </exec_method> + + <property_group name='config' type='application' > + <stability value='Unstable' /> + <propval name='proxy_host' type='astring' + value='no:host:set' /> + <propval name='proxy_port' type='integer' + value='6543' /> + </property_group> + + <!-- + Create an enabled instance. + --> + <instance + name='default' + enabled='false' > + </instance> + + <stability value='Evolving' /> + + <template> + <common_name> + <loctext xml:lang='C'> + stmfproxy daemon + </loctext> + </common_name> + + </template> +</service> + +</service_bundle> |