summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Chartre <Alexandre.Chartre@Sun.COM>2009-09-09 16:49:57 -0700
committerAlexandre Chartre <Alexandre.Chartre@Sun.COM>2009-09-09 16:49:57 -0700
commit49bfb42b00abac0958a1308f4233e366fd083366 (patch)
tree0de0400b1b0b1b2b6fc2d23632b73a951d4769ad
parent5f964b32847bbf776eb679b1688c38a4c7c31877 (diff)
downloadillumos-joyent-49bfb42b00abac0958a1308f4233e366fd083366.tar.gz
FWARC 2009/426 Logical Domains Agents
PSARC 2009/459 Logical Domains Agents on Solaris 6813200 Logical Domains Agents 6669994 Add a domain service to support OS identification - solaris
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/Makefile.check1
-rw-r--r--usr/src/cmd/ldmad/Makefile67
-rw-r--r--usr/src/cmd/ldmad/ldma.h167
-rw-r--r--usr/src/cmd/ldmad/ldma_device.c287
-rw-r--r--usr/src/cmd/ldmad/ldma_log.c154
-rw-r--r--usr/src/cmd/ldmad/ldma_system.c128
-rw-r--r--usr/src/cmd/ldmad/ldmad.c558
-rw-r--r--usr/src/cmd/ldmad/ldoms-agents80
-rw-r--r--usr/src/cmd/ldmad/ldoms-agents.xml85
-rw-r--r--usr/src/cmd/svc/profile/platform_sun4v.xml37
-rw-r--r--usr/src/pkgdefs/SUNWldomr.v/prototype_sparc2
-rw-r--r--usr/src/pkgdefs/SUNWldomu.v/prototype_sparc3
-rw-r--r--usr/src/tools/scripts/bfu.sh5
15 files changed, 1557 insertions, 19 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index b2872fbe54..480dd36483 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -484,6 +484,7 @@ sparc_SUBDIRS= \
cmd/drd \
cmd/fps \
cmd/fruadm \
+ cmd/ldmad \
cmd/prtdscp \
cmd/prtfru \
cmd/sckmd \
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index f7684de607..dffdf532db 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -498,6 +498,7 @@ sparc_SUBDIRS= \
drd \
fps \
fruadm \
+ ldmad \
oplhpd \
prtdscp \
prtfru \
diff --git a/usr/src/cmd/Makefile.check b/usr/src/cmd/Makefile.check
index b6c3b8a7cc..de191712d2 100644
--- a/usr/src/cmd/Makefile.check
+++ b/usr/src/cmd/Makefile.check
@@ -49,6 +49,7 @@ MANIFEST_TOPDIRS= \
kbd \
keyserv \
ldapcachemgr \
+ ldmad \
lms \
mms \
dlmgmtd \
diff --git a/usr/src/cmd/ldmad/Makefile b/usr/src/cmd/ldmad/Makefile
new file mode 100644
index 0000000000..1db449789c
--- /dev/null
+++ b/usr/src/cmd/ldmad/Makefile
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+
+PROG= ldmad
+MANIFEST= ldoms-agents.xml
+SVCMETHOD= ldoms-agents
+
+include ../Makefile.cmd
+
+SRCS= ldmad.c \
+ ldma_log.c \
+ ldma_device.c \
+ ldma_system.c
+
+
+OBJS= $(SRCS:%.c=%.o)
+
+ROOTCMDDIR= $(ROOTLIB)/ldoms
+ROOTMANIFESTDIR= $(ROOTSVCPLATFORMSUN4V)
+$(ROOTMANIFEST) := FILEMODE= 444
+
+LDLIBS += -lds -ldladm
+INCS += -I$(ROOT)/usr/platform/sun4v/include/sys
+CPPFLAGS += $(INCS)
+C99MODE = $(C99_ENABLE)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all .WAIT $(ROOTCMD) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+
+check: $(CHKMANIFEST)
+
+lint: lint_SRCS
+
+clean:
+ $(RM) $(PROG) $(OBJS) $(LINT_FILES)
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/ldmad/ldma.h b/usr/src/cmd/ldmad/ldma.h
new file mode 100644
index 0000000000..92abc954ee
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldma.h
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#ifndef _LDMA_H
+#define _LDMA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libds.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+
+/*
+ * The following definitions are part of the LDoms Agent specification.
+ */
+
+/* reply message types */
+#define LDMA_MSG_RESULT 0x8000 /* result message */
+#define LDMA_MSG_ERROR 0x8001 /* error message */
+
+/* error codes for error messages */
+#define LDMA_MSGERR_FAIL 0x0000 /* request has failed */
+#define LDMA_MSGERR_INVALID 0x8001 /* request is invalid */
+#define LDMA_MSGERR_NOTSUP 0x8002 /* request is not supported */
+#define LDMA_MSGERR_DENY 0x8003 /* request is denied */
+
+/*
+ * LDoms Device Agent
+ */
+#define LDMA_NAME_DEVICE "agent-device"
+
+#define LDMA_MSGDEV_VALIDATE_PATH 0x01 /* validate path */
+#define LDMA_MSGDEV_VALIDATE_NIC 0x02 /* validate network interface */
+
+#define LDMA_DEVPATH_EXIST 0x01 /* path is accessible */
+#define LDMA_DEVPATH_OPENRW 0x02 /* path can be opened rw */
+#define LDMA_DEVPATH_OPENRO 0x04 /* path can be opened ro */
+
+#define LDMA_DEVPATH_TYPE_UNKNOWN 0x00 /* path points to unknown */
+#define LDMA_DEVPATH_TYPE_FILE 0x01 /* path points to a file */
+#define LDMA_DEVPATH_TYPE_DEVICE 0x02 /* path points to a device */
+
+#define LDMA_DEVNIC_EXIST 0x01 /* nic is accessible */
+
+/*
+ * LDoms System Agent
+ */
+#define LDMA_NAME_SYSTEM "agent-system"
+
+#define LDMA_MSGSYS_GET_SYSINFO 0x01 /* get system info request */
+
+/*
+ * Size of the header of an agent message. This is the minimal size that
+ * a message can have.
+ */
+#define LDMA_MESSAGE_HEADER_SIZE (sizeof (ldma_message_header_t))
+
+/*
+ * Macro to compute the size of a message with a msg_data of size dlen.
+ * The size of the msg_data field must be a multiple of 8-bytes so dlen
+ * is roundup to an 8-bytes multiple.
+ */
+#define LDMA_MESSAGE_SIZE(dlen) (LDMA_MESSAGE_HEADER_SIZE + P2ROUNDUP(dlen, 8))
+
+/*
+ * Macro to compute the size of the msg_data field from the size of the message.
+ */
+#define LDMA_MESSAGE_DLEN(msgsize) ((msgsize) - LDMA_MESSAGE_HEADER_SIZE)
+
+/*
+ * Handy macros for using the message and header structures.
+ */
+#define LDMA_HDR2MSG(hdr) ((ldma_message_t *)(hdr))
+#define LDMA_HDR2DATA(hdr) (LDMA_HDR2MSG(hdr)->msg_data)
+#define LDMA_MSG2HDR(msg) ((ldma_message_header_t *)(msg))
+
+/* agent message header structure */
+typedef struct ldma_message_header {
+ uint64_t msg_num; /* message number */
+ uint32_t msg_type; /* message type */
+ uint32_t msg_info; /* message info */
+} ldma_message_header_t;
+
+/* agent message structure */
+typedef struct ldma_message {
+ ldma_message_header_t msg_hdr; /* message header */
+ char msg_data[1]; /* message data */
+} ldma_message_t;
+
+/*
+ * Additional structures and definition for the implementation.
+ */
+typedef enum ldma_request_status_t {
+ LDMA_REQ_COMPLETED, /* request was completed */
+ LDMA_REQ_FAILED, /* request has failed */
+ LDMA_REQ_INVALID, /* request is invalid */
+ LDMA_REQ_NOTSUP, /* request is not supported */
+ LDMA_REQ_DENIED /* request was denied */
+} ldma_request_status_t;
+
+typedef ldma_request_status_t (ldm_msg_func_t)(ds_ver_t *,
+ ldma_message_header_t *, size_t, ldma_message_header_t **, size_t *);
+
+typedef struct ldma_msg_handler {
+ uint32_t msg_type; /* message type */
+ ldm_msg_func_t *msg_handler; /* message handler */
+} ldma_msg_handler_t;
+
+typedef struct ldma_agent_info {
+ char *name; /* agent name */
+ ds_ver_t *vers; /* supported versions */
+ int nvers; /* number of versions */
+ ldma_msg_handler_t *handlers; /* message handlers */
+ int nhandlers; /* number of handlers */
+} ldma_agent_info_t;
+
+/*
+ * Helper functions for the daemon and agents.
+ */
+
+/* function to allocate a result message */
+ldma_message_header_t *ldma_alloc_result_msg(ldma_message_header_t *, size_t);
+
+/* functions to log messages */
+void ldma_err(char *module, char *fmt, ...);
+void ldma_info(char *module, char *fmt, ...);
+void ldma_dbg(char *module, char *fmt, ...);
+
+/*
+ * Macros to log messages. Each module/file using these macros should define
+ * LDMA_MODULE as the name under which messages are logged. For a given agent,
+ * LDMA_MODULE should be set to the name of the agent.
+ */
+#define LDMA_ERR(...) ldma_err(LDMA_MODULE, __VA_ARGS__)
+#define LDMA_INFO(...) ldma_info(LDMA_MODULE, __VA_ARGS__)
+#define LDMA_DBG(...) ldma_dbg(LDMA_MODULE, __VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDMA_H */
diff --git a/usr/src/cmd/ldmad/ldma_device.c b/usr/src/cmd/ldmad/ldma_device.c
new file mode 100644
index 0000000000..94e4831262
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldma_device.c
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+/*
+ * Logical Domains Device Agent
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <libds.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ldma.h"
+
+#define LDMA_MODULE LDMA_NAME_DEVICE
+
+#define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t))
+#define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
+
+static ldm_msg_func_t ldma_dev_validate_path;
+static ldm_msg_func_t ldma_dev_validate_nic;
+
+static ds_ver_t ldma_versions[] = { { 1, 0 } };
+
+static ldma_msg_handler_t ldma_handlers[] = {
+ { LDMA_MSGDEV_VALIDATE_PATH, ldma_dev_validate_path },
+ { LDMA_MSGDEV_VALIDATE_NIC, ldma_dev_validate_nic }
+};
+
+ldma_agent_info_t ldma_device_info = {
+ LDMA_NAME_DEVICE,
+ ldma_versions, LDMA_NVERSIONS,
+ ldma_handlers, LDMA_NHANDLERS
+};
+
+/*ARGSUSED*/
+static ldma_request_status_t
+ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request,
+ size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
+{
+ ldma_message_header_t *reply = NULL;
+ ldma_request_status_t status;
+ struct stat st;
+ char *path = NULL;
+ uint32_t *path_type, reply_dlen;
+ uint32_t plen;
+ int fd;
+
+ plen = request->msg_info;
+ if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) {
+ status = LDMA_REQ_INVALID;
+ goto done;
+ }
+
+ path = malloc(plen + 1);
+ if (path == NULL) {
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ (void) strncpy(path, LDMA_HDR2DATA(request), plen);
+ path[plen] = '\0';
+
+ LDMA_DBG("VALIDATE_PATH(%s)", path);
+
+ reply_dlen = sizeof (uint32_t);
+ reply = ldma_alloc_result_msg(request, reply_dlen);
+ if (reply == NULL) {
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ path_type = (uint32_t *)(LDMA_HDR2DATA(reply));
+
+ reply->msg_info = 0x0;
+
+ /* check if path exists */
+ if (stat(path, &st) != 0) {
+
+ LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d",
+ path, errno);
+
+ switch (errno) {
+
+ case EACCES:
+ case ELOOP:
+ case ENOENT:
+ case ENOLINK:
+ case ENOTDIR:
+ /* path is inaccessible, the request is completed */
+ status = LDMA_REQ_COMPLETED;
+ break;
+
+ case ENAMETOOLONG:
+ status = LDMA_REQ_INVALID;
+ break;
+
+ default:
+ /* request has failed */
+ status = LDMA_REQ_FAILED;
+ break;
+ }
+
+ goto done;
+ }
+
+ status = LDMA_REQ_COMPLETED;
+
+ reply->msg_info |= LDMA_DEVPATH_EXIST;
+
+ LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%x", path, st.st_mode);
+
+ switch (st.st_mode & S_IFMT) {
+
+ case S_IFREG:
+ *path_type = LDMA_DEVPATH_TYPE_FILE;
+ break;
+
+ case S_IFCHR:
+ case S_IFBLK:
+ *path_type = LDMA_DEVPATH_TYPE_DEVICE;
+ break;
+
+ default:
+ /* we don't advertise other types (fifo, directory...) */
+ *path_type = 0;
+ }
+
+ /* check if path can be opened read/write */
+ if ((fd = open(path, O_RDWR)) != -1) {
+ reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO;
+ (void) close(fd);
+ } else {
+ LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d",
+ path, errno);
+
+ /* check if path can be opened read only */
+ if ((fd = open(path, O_RDONLY)) != -1) {
+ reply->msg_info |= LDMA_DEVPATH_OPENRO;
+ (void) close(fd);
+ } else {
+ LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed "
+ "with error %d", path, errno);
+ }
+ }
+
+done:
+ if (status != LDMA_REQ_COMPLETED) {
+ /*
+ * We don't provide a reply message if the request has not
+ * been completed. The LDoms agent daemon will send an
+ * appropriate reply based on the return code of this function.
+ */
+ free(reply);
+ reply = NULL;
+ reply_dlen = 0;
+
+ LDMA_DBG("VALIDATE_PATH(%s): return error %d",
+ (path)? path : "<none>", status);
+ } else {
+ LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x",
+ path, reply->msg_info, *path_type);
+ }
+
+ free(path);
+ *replyp = reply;
+ *reply_dlenp = reply_dlen;
+
+ return (status);
+}
+
+/*
+ * We check that the device is a network interface (NIC) using libdladm.
+ */
+/*ARGSUSED*/
+static ldma_request_status_t
+ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request,
+ size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
+{
+ dladm_handle_t dlhandle;
+ datalink_id_t linkid;
+ uint32_t flag, media;
+ datalink_class_t class;
+ ldma_message_header_t *reply = NULL;
+ ldma_request_status_t status;
+ char *nic = NULL;
+ uint32_t nlen, reply_dlen;
+
+ nlen = request->msg_info;
+ if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) {
+ status = LDMA_REQ_INVALID;
+ goto done;
+ }
+
+ nic = malloc(nlen + 1);
+ if (nic == NULL) {
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ (void) strncpy(nic, LDMA_HDR2DATA(request), nlen);
+ nic[nlen] = '\0';
+
+ LDMA_DBG("VALIDATE_NIC(%s)", nic);
+
+ reply_dlen = 0;
+ reply = ldma_alloc_result_msg(request, reply_dlen);
+ if (reply == NULL) {
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ reply->msg_info = 0x0;
+
+ if (dladm_open(&dlhandle) != DLADM_STATUS_OK) {
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class,
+ &media) != DLADM_STATUS_OK) {
+ LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic);
+ } else {
+ LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media);
+ reply->msg_info = LDMA_DEVNIC_EXIST;
+ }
+
+ dladm_close(dlhandle);
+
+ status = LDMA_REQ_COMPLETED;
+
+done:
+ if (status != LDMA_REQ_COMPLETED) {
+ /*
+ * We don't provide a reply message if the request has not
+ * been completed. The LDoms agent daemon will send an
+ * appropriate reply based on the return code of this function.
+ */
+ free(reply);
+ reply = NULL;
+ reply_dlen = 0;
+
+ LDMA_DBG("VALIDATE_NIC(%s): return error %d",
+ (nic)? nic : "<none>", status);
+ } else {
+ LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x",
+ nic, reply->msg_info);
+ }
+
+ free(nic);
+ *replyp = reply;
+ *reply_dlenp = reply_dlen;
+
+ return (status);
+}
diff --git a/usr/src/cmd/ldmad/ldma_log.c b/usr/src/cmd/ldmad/ldma_log.c
new file mode 100644
index 0000000000..ca5e423207
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldma_log.c
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+/*
+ * Logging support for the LDoms Agent daemon
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+
+#define LDMA_MAX_MSG_LEN 512
+#define LDMA_MAX_TIME_LEN 32
+
+extern boolean_t ldma_debug;
+extern boolean_t ldma_daemon;
+
+static char *log_prio_str[] = {
+ "EMERG", /* LOG_EMERG */
+ "ALERT", /* LOG_ALERT */
+ "CRIT", /* LOG_CRIT */
+ "ERROR", /* LOG_ERR */
+ "WARNING", /* LOG_WARNING */
+ "NOTICE", /* LOG_NOTICE */
+ "INFO", /* LOG_INFO */
+ "DEBUG" /* LOG_DEBUG */
+};
+
+/*
+ * Generate a timestamp string in the provided buffer.
+ * If any errors are encountered, the function returns
+ * with the buffer containing an empty string.
+ */
+static void
+ldma_timestamp(char *buf, size_t buflen)
+{
+ struct tm ltime;
+ struct timeval now;
+
+ if ((buf == NULL) || (buflen == 0))
+ return;
+
+ buf[0] = '\0';
+
+ if (gettimeofday(&now, NULL) != 0) {
+ (void) fprintf(stderr, "gettimeofday failed: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ if (localtime_r(&now.tv_sec, &ltime) == NULL) {
+ (void) fprintf(stderr, "localtime_r failed: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ if (strftime(buf, buflen, "%b %e %T ", &ltime) == 0) {
+ (void) fprintf(stderr, "strftime failed: buffer[%d] too "
+ "small\n", buflen);
+ /*
+ * On failure, the contents of the buffer
+ * are indeterminate. Restore it to a known
+ * state before returning.
+ */
+ buf[0] = '\0';
+ }
+}
+
+static void
+ldma_log_msg(int prio, char *module, char *fmt, va_list vap)
+{
+ char msgbuf[LDMA_MAX_MSG_LEN];
+ char timebuf[LDMA_MAX_TIME_LEN] = "";
+
+ /* generate a timestamp for the SMF log */
+ ldma_timestamp(timebuf, sizeof (timebuf));
+
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) vsnprintf(msgbuf, LDMA_MAX_MSG_LEN, fmt, vap);
+
+ /*
+ * Print the message to stderr. In daemon mode, it
+ * will be sent to the SMF log. In standalone mode,
+ * it will be sent to the controlling terminal.
+ */
+ (void) fprintf(stderr, "%s%s.%s: %s\n", timebuf, module,
+ log_prio_str[prio], msgbuf);
+
+ if (ldma_daemon && prio != LOG_DEBUG) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ syslog(prio, msgbuf);
+ }
+}
+
+void
+ldma_err(char *module, char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ ldma_log_msg(LOG_ERR, module, fmt, vap);
+ va_end(vap);
+}
+
+void
+ldma_info(char *module, char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ ldma_log_msg(LOG_INFO, module, fmt, vap);
+ va_end(vap);
+}
+
+void
+ldma_dbg(char *module, char *fmt, ...)
+{
+ va_list vap;
+
+ if (!ldma_debug) {
+ /* not debugging */
+ return;
+ }
+
+ va_start(vap, fmt);
+ ldma_log_msg(LOG_DEBUG, module, fmt, vap);
+ va_end(vap);
+}
diff --git a/usr/src/cmd/ldmad/ldma_system.c b/usr/src/cmd/ldmad/ldma_system.c
new file mode 100644
index 0000000000..1db750e650
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldma_system.c
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/*
+ * Logical Domains System Agent
+ */
+
+#include <errno.h>
+#include <libds.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/utsname.h>
+
+#include "ldma.h"
+
+#define LDMA_MODULE LDMA_NAME_SYSTEM
+
+#define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t))
+#define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
+
+static ldm_msg_func_t ldma_sys_get_sysinfo;
+
+static ds_ver_t ldma_versions[] = { { 1, 0 } };
+
+static ldma_msg_handler_t ldma_handlers[] = {
+ { LDMA_MSGSYS_GET_SYSINFO, ldma_sys_get_sysinfo }
+};
+
+ldma_agent_info_t ldma_system_info = {
+ LDMA_NAME_SYSTEM,
+ ldma_versions, LDMA_NVERSIONS,
+ ldma_handlers, LDMA_NHANDLERS
+};
+
+/*ARGSUSED*/
+static ldma_request_status_t
+ldma_sys_get_sysinfo(ds_ver_t *ver, ldma_message_header_t *request,
+ size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
+{
+ ldma_message_header_t *reply;
+ struct utsname name;
+ size_t syslen, nodlen, rellen, maclen, verlen;
+ size_t rlen;
+ char *data;
+ int status;
+
+ LDMA_DBG("GET_SYSINFO");
+
+ if (request->msg_info != 0 || request_dlen != 0) {
+ status = LDMA_REQ_INVALID;
+ goto done;
+ }
+
+ if (uname(&name) == -1) {
+ LDMA_DBG("GET_SYSINFO: uname failed with error %d", errno);
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ syslen = strlen(name.sysname) + 1;
+ nodlen = strlen(name.nodename) + 1;
+ rellen = strlen(name.release) + 1;
+ verlen = strlen(name.version) + 1;
+ maclen = strlen(name.machine) + 1;
+
+ rlen = syslen + nodlen + rellen + verlen + maclen;
+
+ reply = ldma_alloc_result_msg(request, rlen);
+
+ if (reply == NULL) {
+ status = LDMA_REQ_FAILED;
+ goto done;
+ }
+
+ reply->msg_info = rlen;
+
+ data = LDMA_HDR2DATA(reply);
+
+ (void) strcpy(data, name.sysname);
+ data += syslen;
+
+ (void) strcpy(data, name.nodename);
+ data += nodlen;
+
+ (void) strcpy(data, name.release);
+ data += rellen;
+
+ (void) strcpy(data, name.version);
+ data += verlen;
+
+ (void) strcpy(data, name.machine);
+
+ LDMA_DBG("GET_SYSINFO: return info=%u, {%s, %s, %s, %s, %s}", rlen,
+ name.sysname, name.nodename, name.release, name.version,
+ name.machine);
+
+ *replyp = reply;
+ *reply_dlenp = rlen;
+
+ return (LDMA_REQ_COMPLETED);
+
+done:
+ LDMA_DBG("GET_SYSINFO: return error %d", status);
+ return (status);
+}
diff --git a/usr/src/cmd/ldmad/ldmad.c b/usr/src/cmd/ldmad/ldmad.c
new file mode 100644
index 0000000000..2403cd2cd7
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldmad.c
@@ -0,0 +1,558 @@
+/*
+ * 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.
+ */
+
+/*
+ * Logical Domains (LDoms) Agents Daemon
+ *
+ * The LDoms agents daemon (ldmad) runs on LDoms domains and provides
+ * information to the control domain. It is composed of a set of agents
+ * which can send and receive messages to and from the control domain.
+ * Each agent is registered as a domain service using the libds library,
+ * and is able to handle requests coming from the control domain.
+ *
+ * The control domain sends requests to an agent as messages on the
+ * corresponding domain service (identified by the agent name). All requests
+ * are received by the ldmad daemon which dispatches them to the appropriate
+ * handler function of the agent depending on the type of the message.
+ *
+ * After the request has been processed by the handler, the ldmad daemon sent
+ * a reply message back to the control domain. The reply is either a result
+ * message if the request was successfully completed, or an error message
+ * describing the failure.
+ */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
+#include <libds.h>
+#include <libgen.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include "ldma.h"
+
+#define LDMA_MODULE "ldm-agent-daemon"
+
+#define LDMA_CONTROL_DOMAIN_DHDL 0 /* id of the control domain */
+#define LDMA_DOMAIN_NAME_MAXLEN MAXNAMELEN
+
+typedef struct ldma_agent {
+ ldma_agent_info_t *info; /* agent information */
+ ds_hdl_t conn_hdl; /* connexion handler */
+ ds_ver_t conn_ver; /* connexion version */
+} ldma_agent_t;
+
+/* information about existing agents */
+extern ldma_agent_info_t ldma_device_info;
+extern ldma_agent_info_t ldma_system_info;
+
+boolean_t ldma_debug = B_FALSE;
+boolean_t ldma_daemon = B_FALSE;
+
+static ldma_agent_info_t *ldma_agent_infos[] = {
+ &ldma_device_info,
+ &ldma_system_info,
+ NULL
+};
+
+static char *cmdname;
+static pid_t daemon_pid;
+
+/*
+ * Allocate a new message with the specified message number (msg_num),
+ * message type (msg_type) and message data length (msg_dlen). Return
+ * NULL if the allocation has failed.
+ */
+static ldma_message_header_t *
+ldma_alloc_msg(uint64_t msg_num, uint32_t msg_type, size_t msg_dlen)
+{
+ ldma_message_header_t *msg;
+ size_t msg_len;
+
+ msg_len = LDMA_MESSAGE_SIZE(msg_dlen);
+ msg = malloc(msg_len);
+ if (msg == NULL)
+ return (NULL);
+
+ msg->msg_num = msg_num;
+ msg->msg_type = msg_type;
+ msg->msg_info = 0;
+
+ return (msg);
+}
+
+/*
+ * Allocate a result message (LDMA_MSG_REQ_RESULT) with the specified message
+ * data length (msg_dlen). If the request argument is not NULL then the message
+ * is created with the same message number as the request, otherwise the message
+ * number is set to 0. Return NULL if the allocation has failed.
+ */
+ldma_message_header_t *
+ldma_alloc_result_msg(ldma_message_header_t *request, size_t msg_dlen)
+{
+ uint64_t msg_num;
+
+ msg_num = (request == NULL)? 0 : request->msg_num;
+
+ return (ldma_alloc_msg(msg_num, LDMA_MSG_RESULT, msg_dlen));
+}
+
+/*
+ * Agent register callback. This callback is invoked when a client is registered
+ * for using the service provided by an agent. An agent will only have one
+ * consumer which is coming from the control domain.
+ */
+static void
+ldma_reg_cb(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
+ ds_domain_hdl_t dhdl)
+{
+ ldma_agent_t *agent = (ldma_agent_t *)arg;
+ char dname[LDMA_DOMAIN_NAME_MAXLEN];
+
+ if (ds_dom_hdl_to_name(dhdl, dname, LDMA_DOMAIN_NAME_MAXLEN) != 0) {
+ (void) strcpy(dname, "<unknown>");
+ }
+
+ LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd",
+ agent->info->name, hdl, dhdl, dname, ver->major, ver->minor);
+
+ /*
+ * Record client information if the connexion is from the control
+ * domain. The domain service framework only allows connexion of a
+ * domain with the control domain. However, if the agent is running
+ * on the control domain then it can see connexions coming from any
+ * domains. That's why we explicitly have to check if the connexion
+ * is effectively with the control domain.
+ */
+ if (dhdl == LDMA_CONTROL_DOMAIN_DHDL) {
+ agent->conn_hdl = hdl;
+ agent->conn_ver.major = ver->major;
+ agent->conn_ver.minor = ver->minor;
+ } else {
+ LDMA_INFO("agent %s will ignore any request from distrusted "
+ "domain %s", agent->info->name, dname);
+ }
+}
+
+/*
+ * Agent unregister callback. This callback is invoked when a client is
+ * unregistered and stops using the service provided by an agent.
+ */
+static void
+ldma_unreg_cb(ds_hdl_t hdl, ds_cb_arg_t arg)
+{
+ ldma_agent_t *agent = (ldma_agent_t *)arg;
+
+ LDMA_DBG("%s: UNREGISTER hdl=%llx", agent->info->name, hdl);
+
+ if (agent->conn_hdl == hdl) {
+ agent->conn_hdl = 0;
+ agent->conn_ver.major = 0;
+ agent->conn_ver.minor = 0;
+ } else {
+ LDMA_INFO("agent %s has unregistered consumer from "
+ "distrusted domain", agent->info->name);
+ }
+}
+
+/*
+ * Agent data callback. This callback is invoked when an agent receives a new
+ * message from a client. Any request from a client which is not the control
+ * domain is immediatly rejected. Otherwise the message is forwarded to the
+ * appropriate handler function provided by the agent, depending on the message
+ * type.
+ */
+static void
+ldma_data_cb(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, size_t len)
+{
+ ldma_agent_t *agent = (ldma_agent_t *)arg;
+ ldma_msg_handler_t *handler;
+ ldma_message_header_t *request = buf;
+ ldma_message_header_t *reply = NULL;
+ ldma_request_status_t status;
+ size_t request_dlen, reply_len, reply_dlen = 0;
+ int i;
+
+ /* check the message size */
+ if (len < LDMA_MESSAGE_HEADER_SIZE) {
+ LDMA_INFO("agent %s has ignored message with an invalid "
+ "size of %d bytes", agent->info->name, len);
+ return;
+ }
+
+ request_dlen = LDMA_MESSAGE_DLEN(len);
+
+ LDMA_DBG("%s: DATA hdl=%llx, request num=%llu type=0x%x info=0x%x "
+ "dlen=%d", agent->info->name, hdl, request->msg_num,
+ request->msg_type, request->msg_info, request_dlen);
+
+ /* reject any request which is not from the control domain */
+ if (hdl != agent->conn_hdl) {
+ LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a "
+ "distrusted domain", agent->info->name, hdl);
+ status = LDMA_REQ_DENIED;
+ goto do_reply;
+ }
+
+ handler = NULL;
+
+ for (i = 0; i < agent->info->nhandlers; i++) {
+ if (agent->info->handlers[i].msg_type == request->msg_type) {
+ handler = &agent->info->handlers[i];
+ break;
+ }
+ }
+
+ if (handler == NULL) {
+ /* this type of message is not defined by the agent */
+ LDMA_DBG("%s: DATA hdl=%llx, unknown message type %x",
+ agent->info->name, hdl, request->msg_type);
+ status = LDMA_REQ_NOTSUP;
+ goto do_reply;
+ }
+
+ if (handler->msg_handler == NULL) {
+ /*
+ * This type of message is defined by the agent but it
+ * has no handler. That means there is no processing to
+ * do, the message is just ignored, but the request is
+ * successfully completed.
+ */
+ LDMA_DBG("%s: DATA hdl=%llx, no handler",
+ agent->info->name, hdl);
+ status = LDMA_REQ_COMPLETED;
+ goto do_reply;
+ }
+
+ /* invoke the message handler of the agent */
+ status = (*handler->msg_handler)(&agent->conn_ver, request,
+ request_dlen, &reply, &reply_dlen);
+
+ LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d",
+ agent->info->name, hdl, status, (void *)reply, reply_dlen);
+
+do_reply:
+ /*
+ * If the handler has provided a reply message, we use it directly.
+ * Otherwise, we build a reply depending on the status of the request.
+ * In that case, we re-use the request buffer to build the reply
+ * message.
+ */
+ if (reply == NULL) {
+
+ reply = request;
+ reply_dlen = 0;
+
+ if (status == LDMA_REQ_COMPLETED) {
+ /*
+ * The request was successful but no result message was
+ * provided so we send an empty result message.
+ */
+ reply->msg_type = LDMA_MSG_RESULT;
+ reply->msg_info = 0;
+
+ } else {
+ /*
+ * The request has failed but no error message was
+ * provided so we send an error message based on the
+ * request status.
+ */
+ reply->msg_type = LDMA_MSG_ERROR;
+ reply->msg_info =
+ (status == LDMA_REQ_NOTSUP)? LDMA_MSGERR_NOTSUP :
+ (status == LDMA_REQ_INVALID)? LDMA_MSGERR_INVALID :
+ (status == LDMA_REQ_DENIED)? LDMA_MSGERR_DENY :
+ LDMA_MSGERR_FAIL;
+ }
+ }
+
+ reply_len = LDMA_MESSAGE_SIZE(reply_dlen);
+
+ LDMA_DBG("%s: DATA hdl=%llx, reply num=%llu type=0x%x info=0x%x "
+ "dlen=%d", agent->info->name, hdl, reply->msg_num,
+ reply->msg_type, reply->msg_info, reply_dlen);
+
+ if (ds_send_msg(hdl, reply, reply_len) != 0) {
+ LDMA_ERR("agent %s has failed to send reply for request %llu",
+ agent->info->name, request->msg_num);
+ }
+
+ if (reply != request)
+ free(reply);
+}
+
+/*
+ * Register an agent. Return 0 if the agent was successfully registered.
+ */
+static int
+ldma_register(ldma_agent_info_t *agent_info)
+{
+ ldma_agent_t *agent;
+ ds_capability_t ds_cap;
+ ds_ops_t ds_ops;
+
+ agent = malloc(sizeof (ldma_agent_t));
+ if (agent == NULL)
+ goto register_fail;
+
+ agent->info = agent_info;
+ agent->conn_hdl = 0;
+ agent->conn_ver.major = 0;
+ agent->conn_ver.minor = 0;
+
+ ds_cap.svc_id = agent_info->name;
+ ds_cap.vers = agent_info->vers;
+ ds_cap.nvers = agent_info->nvers;
+
+ ds_ops.ds_reg_cb = ldma_reg_cb;
+ ds_ops.ds_unreg_cb = ldma_unreg_cb;
+ ds_ops.ds_data_cb = ldma_data_cb;
+ ds_ops.cb_arg = agent;
+
+ if (ds_svc_reg(&ds_cap, &ds_ops) == 0) {
+ LDMA_INFO("agent %s registered", agent_info->name);
+ return (0);
+ }
+
+register_fail:
+
+ LDMA_ERR("agent %s has failed to register", agent_info->name);
+ free(agent);
+ return (-1);
+}
+
+/*
+ * Register all known agents. Return the number of agents successfully
+ * registered.
+ */
+static int
+ldma_register_agents()
+{
+ int count = 0;
+ ldma_agent_info_t **agent_infop;
+
+ for (agent_infop = ldma_agent_infos;
+ *agent_infop != NULL; agent_infop++) {
+
+ if (ldma_register(*agent_infop) == 0)
+ count++;
+ }
+
+ return (count);
+}
+
+/*ARGSUSED*/
+static void
+ldma_sigusr_handler(int sig, siginfo_t *sinfo, void *ucontext)
+{
+ if (daemon_pid <= 0 || sig != SIGUSR1 || sinfo->si_code != SI_USER ||
+ sinfo->si_pid != daemon_pid)
+ return;
+
+ /*
+ * The parent process has received a USR1 signal from the child.
+ * This means that the daemon has correctly started and the parent
+ * can exit.
+ */
+ exit(0);
+}
+
+static void
+ldma_start(boolean_t standalone)
+{
+ int stat, rv;
+ struct sigaction action;
+
+ if (!standalone) {
+ /*
+ * Some configuration of the daemon has to be done in the
+ * child, but we want the parent to report if the daemon
+ * has successfully started or not. So we setup a signal
+ * handler, and the child will notify the parent using the
+ * USR1 signal if the setup was successful. Otherwise the
+ * child will exit.
+ */
+ action.sa_sigaction = ldma_sigusr_handler;
+ action.sa_flags = SA_SIGINFO;
+
+ if (sigemptyset(&action.sa_mask) == -1) {
+ LDMA_ERR("sigemptyset error (%d)", errno);
+ exit(1);
+ }
+
+ if (sigaction(SIGUSR1, &action, NULL) == -1) {
+ LDMA_ERR("sigaction() error (%d)", errno);
+ exit(1);
+ }
+
+ if (sigrelse(SIGUSR1) == -1) {
+ LDMA_ERR("sigrelse() error (%d)", errno);
+ exit(1);
+ }
+
+ if ((daemon_pid = fork()) == -1) {
+ LDMA_ERR("fork() error (%d)", errno);
+ exit(1);
+ }
+
+ if (daemon_pid != 0) {
+ /*
+ * The parent process waits until the child exits (in
+ * case of an error) or sends a USR1 signal (if the
+ * daemon has correctly started).
+ */
+ for (;;) {
+ rv = waitpid(daemon_pid, &stat, 0);
+ if ((rv == daemon_pid && WIFEXITED(stat)) ||
+ (rv == -1 && errno != EINTR)) {
+ /* child has exited or error */
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * Initialize child process
+ */
+ if (sighold(SIGUSR1) == -1) {
+ LDMA_ERR("sighold error (%d)", errno);
+ exit(1);
+ }
+
+ if (sigignore(SIGUSR1) == -1) {
+ LDMA_ERR("sigignore error (%d)", errno);
+ exit(1);
+ }
+
+ if (setsid() == -1) {
+ LDMA_ERR("setsid error (%d)", errno);
+ exit(1);
+ }
+
+ if (chdir("/") == -1) {
+ LDMA_ERR("chdir error (%d)", errno);
+ exit(1);
+ }
+ (void) umask(0);
+
+ /*
+ * Initialize file descriptors. Do not touch stderr
+ * which is initialized by SMF to point to the daemon
+ * specific log file.
+ */
+ (void) close(STDIN_FILENO);
+ if (open("/dev/null", O_RDWR) == -1) {
+ LDMA_ERR("open /dev/null error (%d)", errno);
+ exit(1);
+ }
+ if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) {
+ LDMA_ERR("dup2 error (%d)", errno);
+ exit(1);
+ }
+ closefrom(STDERR_FILENO + 1);
+
+ /* initialize logging */
+ openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
+
+ ldma_daemon = B_TRUE;
+ }
+
+ /*
+ * Register the agents. It would be easier to do this before
+ * daemonizing so that any start error is directly reported. But
+ * this can not be done because agents are registered using libds
+ * and this will subscribe the daemon to some sysevents which is
+ * a process based subscription. Instead we notify the parent process
+ * either by exiting, or by sending a SIGUSR1 signal.
+ */
+ if (ldma_register_agents() == 0) {
+ /* no agent registered */
+ LDMA_ERR("Unable to register any agent", cmdname);
+ exit(1);
+ }
+
+ if (!standalone) {
+ /* signal parent that startup was successful */
+ if (kill(getppid(), SIGUSR1) == -1)
+ exit(1);
+ }
+}
+
+static void
+ldma_usage()
+{
+ (void) fprintf(stderr, "usage: %s\n", cmdname);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ boolean_t standalone = B_FALSE;
+
+ cmdname = basename(argv[0]);
+
+ /* disable getopt error messages */
+ opterr = 0;
+
+ while ((opt = getopt(argc, argv, "ds")) != EOF) {
+
+ switch (opt) {
+ case 'd':
+ ldma_debug = B_TRUE;
+ break;
+ case 's':
+ standalone = B_TRUE;
+ break;
+ default:
+ ldma_usage();
+ exit(1);
+ }
+ }
+
+ ldma_start(standalone);
+
+ /*
+ * Loop forever. Any incoming message will be received by libds and
+ * forwarded to the agent data callback (ldma_data_cb()) where it
+ * will be processed.
+ */
+ for (;;) {
+ (void) pause();
+ }
+
+ /*NOTREACHED*/
+ return (0);
+}
diff --git a/usr/src/cmd/ldmad/ldoms-agents b/usr/src/cmd/ldmad/ldoms-agents
new file mode 100644
index 0000000000..58ef419dca
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldoms-agents
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# 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.
+#
+
+. /lib/svc/share/smf_include.sh
+
+SVCNAME='Logical Domains agents'
+LDMAD='/usr/lib/ldoms/ldmad'
+VLDS='/devices/virtual-devices@100/channel-devices@200/virtual-domain-service@0:vlds'
+mach=`/sbin/uname -m`
+
+if [ "$mach" != "sun4v" ]; then
+ echo "The $SVCNAME service is not supported on this platform."
+ exit "$SMF_EXIT_ERR_FATAL"
+fi
+
+if smf_is_nonglobalzone; then
+ echo "The $SVCNAME service has been disabled because " \
+ "it is not supported in a local zone."
+ /usr/sbin/svcadm disable "$SMF_FMRI"
+ sleep 5 &
+ exit "$SMF_EXIT_OK"
+fi
+
+#
+# The Logical Domains agents service is enabled by default on sun4v platforms.
+# However it can fail to start if the domain has a machine description in which
+# the vlds node is not defined (because it has an old MD or firmware). So we
+# check if a vlds device is effectively defined. If not then we disable the
+# service for this session. We don't return an error so that the service does
+# not go into the maintenance state and generate spurious error (especially if
+# the system is not configured with LDoms). The service is not permanently
+# disabled so that the service can come up if the domain is restarted with a
+# compatible MD.
+#
+if [ ! -c "$VLDS" ]; then
+ echo "The $SVCNAME service has been disabled because the system" \
+ "has no virtual domain service (vlds) device."
+ /usr/sbin/svcadm disable -t "$SMF_FMRI"
+ sleep 5 &
+ exit "$SMF_EXIT_OK"
+fi
+
+if [ ! -x "$LDMAD" ]; then
+ echo "The $SVCNAME service requires the $LDMAD executable."
+ exit "$SMF_EXIT_ERR_CONFIG"
+fi
+
+$LDMAD
+
+EXIT=$?
+
+if [ "$EXIT" != 0 ]; then
+ exit "$EXIT"
+fi
+
+exit "$SMF_EXIT_OK"
diff --git a/usr/src/cmd/ldmad/ldoms-agents.xml b/usr/src/cmd/ldmad/ldoms-agents.xml
new file mode 100644
index 0000000000..d968745f19
--- /dev/null
+++ b/usr/src/cmd/ldmad/ldoms-agents.xml
@@ -0,0 +1,85 @@
+<?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.
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different file.
+-->
+
+<service_bundle type='manifest' name='SUNWldomu:ldmad'>
+
+<service
+ name='ldoms/agents'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance />
+
+ <dependency
+ name='filesystem-minimal'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='syslog'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/system-log' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/ldoms-agents'
+ timeout_seconds='60' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='30' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Logical Domains agents service
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='ldmad' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/profile/platform_sun4v.xml b/usr/src/cmd/svc/profile/platform_sun4v.xml
index e52039ec13..521767b48d 100644
--- a/usr/src/cmd/svc/profile/platform_sun4v.xml
+++ b/usr/src/cmd/svc/profile/platform_sun4v.xml
@@ -1,29 +1,27 @@
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<!--
- Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- Use is subject to license terms.
+ CDDL HEADER START
- 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.
- 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.
- 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]
- 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
- CDDL HEADER END
-
- ident "%Z%%M% %I% %E% SMI"
+ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
NOTE: This service profile is not editable; its contents will be
overwritten by package or patch operations, including operating
@@ -38,4 +36,7 @@
<service name='platform/sun4v/efdaemon' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
+ <service name='ldoms/agents' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
</service_bundle>
diff --git a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc
index 13e14c5e7a..4a2de64c35 100644
--- a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc
@@ -50,6 +50,7 @@
d none lib 755 root bin
d none lib/svc 0755 root bin
d none lib/svc/method 0755 root bin
+f none lib/svc/method/ldoms-agents 0555 root bin
f none lib/svc/method/svc-drd 0555 root bin
f none lib/svc/method/svc-vntsd 0555 root bin
d none platform 755 root sys
@@ -86,4 +87,5 @@ d none var/svc/manifest 755 root sys
d none var/svc/manifest/platform 755 root sys
d none var/svc/manifest/platform/sun4v 755 root sys
f manifest var/svc/manifest/platform/sun4v/drd.xml 0444 root sys
+f manifest var/svc/manifest/platform/sun4v/ldoms-agents.xml 0444 root sys
f manifest var/svc/manifest/platform/sun4v/vntsd.xml 0444 root sys
diff --git a/usr/src/pkgdefs/SUNWldomu.v/prototype_sparc b/usr/src/pkgdefs/SUNWldomu.v/prototype_sparc
index 413badcb41..434b07454d 100644
--- a/usr/src/pkgdefs/SUNWldomu.v/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWldomu.v/prototype_sparc
@@ -20,7 +20,7 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
@@ -51,6 +51,7 @@ d none usr 755 root sys
d none usr/lib 755 root bin
d none usr/lib/ldoms 755 root bin
f none usr/lib/ldoms/drd 555 root bin
+f none usr/lib/ldoms/ldmad 555 root bin
f none usr/lib/ldoms/vntsd 555 root bin
f none usr/lib/libpri.so.1 755 root bin
f none usr/lib/libds.so.1 755 root bin
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index 7d1d0447fc..fe9f110a99 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -306,6 +306,7 @@ superfluous_nonglobal_zone_files="
lib/svc/method/devices-audio
lib/svc/method/fc-fabric
lib/svc/method/iscsi-initiator
+ lib/svc/method/ldoms-agents
lib/svc/method/npivconfig
lib/svc/method/sf880dr
lib/svc/method/svc-cvcd
@@ -1613,6 +1614,10 @@ smf_handle_new_services () {
-f $rootprefix/etc/pooladm.conf ]]; then
smf_enable svc:/system/pools:default
fi
+ if [[ $zone = global && $karch = sun4v &&
+ ! -f $rootprefix/var/svc/manifest/platforms/sun4v/ldoms-agents.xml ]]; then
+ smf_enable svc:/ldoms/agents:default
+ fi
}
smf_copy_manifest() {