summaryrefslogtreecommitdiff
path: root/usr/src/lib/libipmp
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libipmp
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libipmp')
-rw-r--r--usr/src/lib/libipmp/Makefile66
-rw-r--r--usr/src/lib/libipmp/Makefile.com52
-rw-r--r--usr/src/lib/libipmp/common/ipmp.c114
-rw-r--r--usr/src/lib/libipmp/common/ipmp.h73
-rw-r--r--usr/src/lib/libipmp/common/ipmp_impl.h58
-rw-r--r--usr/src/lib/libipmp/common/ipmp_mpathd.c267
-rw-r--r--usr/src/lib/libipmp/common/ipmp_mpathd.h174
-rw-r--r--usr/src/lib/libipmp/common/ipmp_query.c755
-rw-r--r--usr/src/lib/libipmp/common/ipmp_query.h108
-rw-r--r--usr/src/lib/libipmp/common/ipmp_query_impl.h93
-rw-r--r--usr/src/lib/libipmp/common/llib-lipmp34
-rw-r--r--usr/src/lib/libipmp/i386/Makefile31
-rw-r--r--usr/src/lib/libipmp/sparc/Makefile31
-rw-r--r--usr/src/lib/libipmp/spec/Makefile29
-rw-r--r--usr/src/lib/libipmp/spec/Makefile.targ32
-rw-r--r--usr/src/lib/libipmp/spec/amd64/Makefile32
-rw-r--r--usr/src/lib/libipmp/spec/i386/Makefile35
-rw-r--r--usr/src/lib/libipmp/spec/ipmp.spec159
-rw-r--r--usr/src/lib/libipmp/spec/sparc/Makefile35
-rw-r--r--usr/src/lib/libipmp/spec/sparcv9/Makefile32
-rw-r--r--usr/src/lib/libipmp/spec/versions42
21 files changed, 2252 insertions, 0 deletions
diff --git a/usr/src/lib/libipmp/Makefile b/usr/src/lib/libipmp/Makefile
new file mode 100644
index 0000000000..596c39e922
--- /dev/null
+++ b/usr/src/lib/libipmp/Makefile
@@ -0,0 +1,66 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+HDRS = ipmp.h ipmp_mpathd.h ipmp_query.h ipmp_query_impl.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+
+POFILE = libipmp.po
+MSGFILES = common/ipmp.c
+XGETFLAGS = -a
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: spec .WAIT $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(SUBDIRS) spec: FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libipmp/Makefile.com b/usr/src/lib/libipmp/Makefile.com
new file mode 100644
index 0000000000..5bce4ce86e
--- /dev/null
+++ b/usr/src/lib/libipmp/Makefile.com
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libipmp.a
+VERS = .1
+OBJECTS = ipmp_query.o ipmp_mpathd.o ipmp.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+LDLIBS += -lsocket -lc
+
+SRCDIR = ../common
+MAPDIR = ../spec/$(TRANSMACH)
+SPECMAPFILE = $(MAPDIR)/mapfile
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I$(SRCDIR)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libipmp/common/ipmp.c b/usr/src/lib/libipmp/common/ipmp.c
new file mode 100644
index 0000000000..b9a7984889
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp.c
@@ -0,0 +1,114 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * IPMP general interfaces (PSARC/2002/615).
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+
+#include "ipmp_impl.h"
+
+/*
+ * Allocate a handle and store it in `*handlep' upon success. Returns an IPMP
+ * error code.
+ */
+int
+ipmp_open(ipmp_handle_t *handlep)
+{
+ ipmp_state_t *statep;
+
+ statep = malloc(sizeof (ipmp_state_t));
+ if (statep == NULL)
+ return (IPMP_ENOMEM);
+
+ statep->st_fd = -1;
+ statep->st_snap = NULL;
+ statep->st_magic = IPMP_MAGIC;
+
+ *handlep = statep;
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Destroy the IPMP handle named by `handle'.
+ */
+void
+ipmp_close(ipmp_handle_t handle)
+{
+ ipmp_state_t *statep = handle;
+
+ /*
+ * If this assertion triggers, someone called ipmp_close() twice in
+ * a row or stomped on us.
+ */
+ assert(statep->st_magic == IPMP_MAGIC);
+
+ /*
+ * If this assertion triggers, something's gone wrong internally.
+ */
+ assert(statep->st_fd == -1);
+
+ if (statep->st_snap != NULL)
+ ipmp_snap_free(statep->st_snap);
+
+ statep->st_magic = 0;
+ free(statep);
+}
+
+/*
+ * Error messages; must be in the same order as the codes in <ipmp.h>
+ */
+static char *errmsgs[IPMP_NERR] = {
+ "operation succeeded", /* 0 IPMP_SUCCESS */
+ "operation failed", /* 1 IPMP_FAILURE */
+ "minimum failover redundancy not met", /* 2 IPMP_EMINRED */
+ "failback disabled", /* 3 IPMP_EFBDISABLED */
+ "unable to completely fail back", /* 4 IPMP_EFBPARTIAL */
+ "invalid argument", /* 5 IPMP_EINVAL */
+ "out of memory", /* 6 IPMP_ENOMEM */
+ "cannot contact in.mpathd", /* 7 IPMP_ENOMPATHD */
+ "unknown IPMP group", /* 8 IPMP_EUNKGROUP */
+ "interface is not using IPMP", /* 9 IPMP_EUNKIF */
+ "unable to communicate with in.mpathd" /* 10 IPMP_EPROTO */
+};
+
+/*
+ * Return a string describing the IPMP error code named by `error'.
+ */
+const char *
+ipmp_errmsg(int error)
+{
+ if (error >= IPMP_NERR || error < 0)
+ return (dgettext(TEXT_DOMAIN, "<unknown error>"));
+
+ return (dgettext(TEXT_DOMAIN, errmsgs[error]));
+}
diff --git a/usr/src/lib/libipmp/common/ipmp.h b/usr/src/lib/libipmp/common/ipmp.h
new file mode 100644
index 0000000000..0112615a84
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp.h
@@ -0,0 +1,73 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPMP_H
+#define _IPMP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General IPMP-related definitions and functions.
+ *
+ * These interfaces may only be used within ON or after signing a contract
+ * with ON. For documentation, refer to PSARC/2002/615.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/sysevent/ipmp.h>
+
+/*
+ * IPMP library error codes.
+ */
+enum {
+ IPMP_SUCCESS, /* operation succeeded */
+ IPMP_FAILURE, /* operation failed (check errno) */
+ IPMP_EMINRED, /* minimum failover redundancy not met */
+ IPMP_EFBDISABLED, /* failback disabled */
+ IPMP_EFBPARTIAL, /* unable to completely fail back */
+ IPMP_EINVAL, /* invalid argument */
+ IPMP_ENOMEM, /* out of memory */
+ IPMP_ENOMPATHD, /* cannot contact in.mpathd */
+ IPMP_EUNKGROUP, /* unknown IPMP group */
+ IPMP_EUNKIF, /* interface is not using IPMP */
+ IPMP_EPROTO, /* unable to communicate with in.mpathd */
+ IPMP_NERR /* number of error codes */
+};
+
+typedef struct ipmp_state *ipmp_handle_t;
+
+extern int ipmp_open(ipmp_handle_t *);
+extern void ipmp_close(ipmp_handle_t);
+extern const char *ipmp_errmsg(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPMP_H */
diff --git a/usr/src/lib/libipmp/common/ipmp_impl.h b/usr/src/lib/libipmp/common/ipmp_impl.h
new file mode 100644
index 0000000000..3e7e90b43f
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp_impl.h
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPMP_IMPL_H
+#define _IPMP_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ipmp.h>
+#include <ipmp_query_impl.h>
+
+/*
+ * Implementation-private definitions for the IPMP library.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Private IPMP state structure.
+ */
+typedef struct ipmp_state {
+ uint32_t st_magic; /* magic tag */
+ int st_fd; /* socket to in.mpathd */
+ ipmp_snap_t *st_snap; /* current snapshot, if any */
+} ipmp_state_t;
+
+#define IPMP_MAGIC 0x49504D50 /* "IPMP" */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPMP_IMPL_H */
diff --git a/usr/src/lib/libipmp/common/ipmp_mpathd.c b/usr/src/lib/libipmp/common/ipmp_mpathd.c
new file mode 100644
index 0000000000..ee1d35de33
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp_mpathd.c
@@ -0,0 +1,267 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Low-level interfaces for communicating with in.mpathd(1M).
+ *
+ * These routines are not intended for use outside of libipmp.
+ */
+
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/types.h>
+
+#include "ipmp.h"
+#include "ipmp_mpathd.h"
+
+/*
+ * Connect to the multipathing daemon. Returns an IPMP error code; upon
+ * success, `fdp' points to the newly opened socket.
+ */
+int
+ipmp_connect(int *fdp)
+{
+ int fd;
+ int error;
+ int on = 1;
+ int flags;
+ struct sockaddr_in sin;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ return (IPMP_FAILURE);
+
+ /*
+ * Enable TCP_ANONPRIVBIND so the kernel will choose our source port.
+ * Since we're using loopback sockets, requiring use of privileged
+ * source ports is sufficient for security.
+ */
+ if (setsockopt(fd, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
+ sizeof (on)) == -1)
+ goto fail;
+
+ /*
+ * Bind to a privileged port chosen by the kernel.
+ */
+ (void) memset(&sin, 0, sizeof (struct sockaddr_in));
+ sin.sin_port = htons(0);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(fd, (struct sockaddr *)&sin, sizeof (sin)) == -1)
+ goto fail;
+
+ /*
+ * Attempt to connect to in.mpathd.
+ */
+ sin.sin_port = htons(MPATHD_PORT);
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (connect(fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) {
+ if (errno == ECONNREFUSED) {
+ (void) close(fd);
+ return (IPMP_ENOMPATHD);
+ }
+ goto fail;
+ }
+
+ /*
+ * Kick the socket into nonblocking mode.
+ */
+ flags = fcntl(fd, F_GETFL, 0);
+ if (flags != -1)
+ (void) fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ *fdp = fd;
+ return (IPMP_SUCCESS);
+fail:
+ error = errno;
+ (void) close(fd);
+ errno = error;
+ return (IPMP_FAILURE);
+}
+
+/*
+ * Read the TLV triplet from descriptor `fd' and store its type, length and
+ * value in `*typep', `*lenp', and `*valuep' respectively, before the current
+ * time becomes `endtp'. The buffer pointed to by `*valuep' will be
+ * dynamically allocated. Returns an IPMP error code.
+ */
+int
+ipmp_readtlv(int fd, ipmp_infotype_t *typep, size_t *lenp, void **valuep,
+ const struct timeval *endtp)
+{
+ int retval;
+ void *value;
+
+ retval = ipmp_read(fd, typep, sizeof (*typep), endtp);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_read(fd, lenp, sizeof (*lenp), endtp);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ value = malloc(*lenp);
+ if (value == NULL) {
+ /*
+ * Even though we cannot allocate space for the value, we
+ * still slurp it off so the input stream doesn't get left
+ * in a weird place.
+ */
+ value = alloca(*lenp);
+ (void) ipmp_read(fd, value, *lenp, endtp);
+ return (IPMP_ENOMEM);
+ }
+
+ retval = ipmp_read(fd, value, *lenp, endtp);
+ if (retval != IPMP_SUCCESS) {
+ free(value);
+ return (retval);
+ }
+
+ *valuep = value;
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Write `buflen' bytes from `buffer' to open file `fd'. Returns IPMP_SUCCESS
+ * if all requested bytes were written, or an error code if not.
+ */
+int
+ipmp_write(int fd, const void *buffer, size_t buflen)
+{
+ size_t nwritten;
+ ssize_t nbytes;
+ const char *buf = buffer;
+
+ for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
+ nbytes = write(fd, &buf[nwritten], buflen - nwritten);
+ if (nbytes == -1)
+ return (IPMP_FAILURE);
+ if (nbytes == 0) {
+ errno = EIO;
+ return (IPMP_FAILURE);
+ }
+ }
+
+ assert(nwritten == buflen);
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Write the TLV triplet named by `type', `len' and `value' to file descriptor
+ * `fd'. Returns an IPMP error code.
+ */
+int
+ipmp_writetlv(int fd, ipmp_infotype_t type, size_t len, void *value)
+{
+ int retval;
+
+ retval = ipmp_write(fd, &type, sizeof (type));
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_write(fd, &len, sizeof (len));
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ return (ipmp_write(fd, value, len));
+}
+
+/*
+ * Attempt to read `buflen' worth of bytes from `fd' into the buffer pointed
+ * to by `buf' before the current time becomes `endtp'; a `endtp' of NULL
+ * means forever. Returns an IPMP error code.
+ */
+int
+ipmp_read(int fd, void *buffer, size_t buflen, const struct timeval *endtp)
+{
+ int retval;
+ int timeleft = -1;
+ struct timeval curtime;
+ ssize_t nbytes = 0; /* total bytes processed */
+ ssize_t prbytes; /* per-round bytes processed */
+ struct pollfd pfd;
+
+ while (nbytes < buflen) {
+ /*
+ * If a timeout was specified, then compute the amount of time
+ * left before timing out.
+ */
+ if (endtp != NULL) {
+ if (gettimeofday(&curtime, NULL) == -1)
+ break;
+
+ timeleft = (endtp->tv_sec - curtime.tv_sec) * MILLISEC;
+ timeleft += (endtp->tv_usec - curtime.tv_usec) / 1000;
+
+ /*
+ * If we should've already timed out, then just
+ * have poll() return immediately.
+ */
+ if (timeleft < 0)
+ timeleft = 0;
+ }
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ /*
+ * Wait for data to come in or for the timeout to fire.
+ */
+ retval = poll(&pfd, 1, timeleft);
+ if (retval <= 0) {
+ if (retval == 0)
+ errno = ETIME;
+ break;
+ }
+
+ /*
+ * Descriptor is ready; have at it.
+ */
+ prbytes = read(fd, (caddr_t)buffer + nbytes, buflen - nbytes);
+ if (prbytes <= 0) {
+ if (prbytes == -1 && errno == EINTR)
+ continue;
+ break;
+ }
+ nbytes += prbytes;
+ }
+
+ return (nbytes == buflen ? IPMP_SUCCESS : IPMP_FAILURE);
+}
diff --git a/usr/src/lib/libipmp/common/ipmp_mpathd.h b/usr/src/lib/libipmp/common/ipmp_mpathd.h
new file mode 100644
index 0000000000..61ae71b78f
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp_mpathd.h
@@ -0,0 +1,174 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 1999-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPMP_MPATHD_H
+#define _IPMP_MPATHD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Definitions for the messaging protocol between in.mpathd and libipmp.
+ * This interface is loosely documented in PSARC/2000/306.
+ *
+ * PLEASE NOTE: Although this interface is officially consolidation-private,
+ * we will be reclassifying it as project-private in the future, and
+ * transitioning any existing consumers to use higher-level libipmp routines.
+ *
+ * Put another way: treat this as if it was project-private!
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h> /* needed for <net/if.h> */
+#include <net/if.h> /* needed for LIFNAMSIZ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MPATHD_PORT 5999
+#define MPATHD_PATH "/usr/lib/inet/in.mpathd"
+
+/*
+ * Supported commands.
+ */
+enum {
+ MI_PING = 0, /* sanity test */
+ MI_OFFLINE = 1, /* offline the interface */
+ MI_UNDO_OFFLINE = 2, /* undo the offline */
+ MI_SETOINDEX = 3, /* set original interface index */
+ MI_QUERY = 4, /* query ipmp-related information */
+ MI_NCMD /* total number of commands */
+};
+
+/*
+ * Types of information which can be requested and received (except for
+ * IPMP_IFLIST, which can only be received).
+ */
+typedef enum {
+ IPMP_GROUPLIST = 1,
+ IPMP_GROUPINFO = 2,
+ IPMP_IFINFO = 3,
+ IPMP_IFLIST = 4,
+ IPMP_SNAP = 5
+} ipmp_infotype_t;
+
+/*
+ * Interface offline request; `mio_ifname' is the interface to offline;
+ * `mio_min_redundancy' is the minimum amount of usable interfaces after
+ * offline that must exist for the operation to succeed.
+ */
+typedef struct mi_offline {
+ uint32_t mio_command;
+ char mio_ifname[LIFNAMSIZ];
+ char mio_move_to_if[LIFNAMSIZ]; /* currently unused */
+ uint32_t mio_min_redundancy;
+} mi_offline_t;
+
+/*
+ * Interface undo-offline request; `miu_uname' is the interface to
+ * undo-offline.
+ */
+typedef struct mi_undo_offline {
+ uint32_t miu_command;
+ char miu_ifname[LIFNAMSIZ];
+} mi_undo_offline_t;
+
+/*
+ * Set original interface index request: `mis_lifname' is the name of the
+ * logical interface that is having its index reset; `mis_new_pifname' is the
+ * name of the interface whose index will be associated with `mis_lifname';
+ * `mis_iftype' is the interface type.
+ */
+typedef struct mi_setoindex {
+ uint32_t mis_command;
+ char mis_lifname[LIFNAMSIZ];
+ char mis_new_pifname[LIFNAMSIZ];
+ uint32_t mis_iftype;
+} mi_setoindex_t;
+
+/*
+ * Retrieve IPMP-related information: `miq_inforeq' is the type of information
+ * being request (see above for the list of types). If the request is for
+ * either IPMP_GROUPINFO or IPMP_IFINFO, then either `miq_grname' or
+ * `miq_ifname' should be set (respectively) to indicate the name of the
+ * group or interface to retrieve the information for.
+ */
+typedef struct mi_query {
+ uint32_t miq_command;
+ ipmp_infotype_t miq_inforeq;
+ union {
+ char miqu_ifname[LIFNAMSIZ];
+ char miqu_grname[LIFGRNAMSIZ];
+ } miq_infodata;
+} mi_query_t;
+#define miq_ifname miq_infodata.miqu_ifname
+#define miq_grname miq_infodata.miqu_grname
+
+/*
+ * Union of all commands. Can be used to estimate the maximum buffer size
+ * requirement for receiving any command.
+ */
+union mi_commands {
+ uint32_t mi_command;
+ mi_offline_t mi_ocmd;
+ mi_undo_offline_t mi_ucmd;
+ mi_setoindex_t mi_scmd;
+ mi_query_t mi_qcmd;
+};
+
+/*
+ * Result structure returned by in.mpathd.
+ */
+typedef struct mi_result {
+ uint32_t me_sys_error; /* System error (errno.h) */
+ uint32_t me_mpathd_error; /* Mpathd error */
+} mi_result_t;
+
+/*
+ * Legacy values for me_mpathd_error; the daemon now returns the IPMP
+ * error codes defined in <ipmp.h>, which are compatible with these error
+ * codes. These will be removed in the future.
+ */
+enum {
+ MPATHD_SUCCESS = 0, /* operation succeeded */
+ MPATHD_SYS_ERROR = 1, /* check me_sys_error for the errno */
+ MPATHD_MIN_RED_ERROR = 2, /* minimum redundancy not met */
+ MPATHD_FAILBACK_DISABLED = 3, /* failback administratively disabled */
+ MPATHD_FAILBACK_PARTIAL = 4 /* unable to completely failback */
+};
+
+extern int ipmp_connect(int *);
+extern int ipmp_read(int, void *, size_t, const struct timeval *);
+extern int ipmp_write(int, const void *, size_t);
+extern int ipmp_writetlv(int, ipmp_infotype_t, size_t, void *);
+extern int ipmp_readtlv(int, ipmp_infotype_t *, size_t *, void **,
+ const struct timeval *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPMP_MPATHD_H */
diff --git a/usr/src/lib/libipmp/common/ipmp_query.c b/usr/src/lib/libipmp/common/ipmp_query.c
new file mode 100644
index 0000000000..8a7dc7ee69
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp_query.c
@@ -0,0 +1,755 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * IPMP query interfaces (PSARC/2002/615).
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "ipmp_impl.h"
+#include "ipmp_mpathd.h"
+#include "ipmp_query_impl.h"
+
+#define IPMP_REQTIMEOUT 5 /* seconds */
+
+static ipmp_ifinfo_t *ipmp_ifinfo_clone(ipmp_ifinfo_t *);
+static ipmp_grouplist_t *ipmp_grouplist_clone(ipmp_grouplist_t *);
+static ipmp_groupinfo_t *ipmp_groupinfo_clone(ipmp_groupinfo_t *);
+static ipmp_groupinfo_t *ipmp_snap_getgroupinfo(ipmp_snap_t *, const char *);
+static ipmp_ifinfo_t *ipmp_snap_getifinfo(ipmp_snap_t *, const char *);
+static int ipmp_snap_take(ipmp_state_t *, ipmp_snap_t **);
+static boolean_t ipmp_checktlv(ipmp_infotype_t, size_t, void *);
+static int ipmp_querydone(ipmp_state_t *, int);
+
+/*
+ * Using `statep', send a query request for `type' to in.mpathd, and if
+ * necessary wait until at least `endtp' for a response. Returns an IPMP
+ * error code. If successful, the caller may then read additional query
+ * information through ipmp_readinfo(), and must eventually call
+ * ipmp_querydone() to complete the query operation. Only one query may be
+ * outstanding on a given `statep' at a time.
+ */
+static int
+ipmp_sendquery(ipmp_state_t *statep, ipmp_infotype_t type, const char *name,
+ struct timeval *endtp)
+{
+ mi_query_t query;
+ mi_result_t result;
+ int retval;
+
+ query.miq_command = MI_QUERY;
+ query.miq_inforeq = type;
+
+ switch (type) {
+ case IPMP_GROUPINFO:
+ (void) strlcpy(query.miq_grname, name, LIFGRNAMSIZ);
+ break;
+
+ case IPMP_IFINFO:
+ (void) strlcpy(query.miq_ifname, name, LIFNAMSIZ);
+ break;
+
+ case IPMP_GROUPLIST:
+ case IPMP_SNAP:
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (gettimeofday(endtp, NULL) == -1)
+ return (IPMP_FAILURE);
+
+ endtp->tv_sec += IPMP_REQTIMEOUT;
+
+ assert(statep->st_fd == -1);
+ retval = ipmp_connect(&statep->st_fd);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_write(statep->st_fd, &query, sizeof (query));
+ if (retval != IPMP_SUCCESS)
+ return (ipmp_querydone(statep, retval));
+
+ retval = ipmp_read(statep->st_fd, &result, sizeof (result), endtp);
+ if (retval != IPMP_SUCCESS)
+ return (ipmp_querydone(statep, retval));
+
+ if (result.me_mpathd_error != IPMP_SUCCESS)
+ return (ipmp_querydone(statep, result.me_mpathd_error));
+
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Using `statep', read a query response of type `infotype' into a dynamically
+ * allocated buffer pointed to by `*infop', before the current time becomes
+ * `endtp'. Returns an IPMP error code.
+ */
+static int
+ipmp_readinfo(ipmp_state_t *statep, ipmp_infotype_t infotype, void **infop,
+ const struct timeval *endtp)
+{
+ int retval;
+ size_t len;
+ ipmp_infotype_t type;
+
+ retval = ipmp_readtlv(statep->st_fd, &type, &len, infop, endtp);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ if (type != infotype || !ipmp_checktlv(type, len, *infop)) {
+ free(*infop);
+ return (IPMP_EPROTO);
+ }
+
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Complete the query operation started in ipmp_sendquery(). The interface is
+ * designed to be easy to use in the `return' statement of a function, and
+ * thus returns the passed in `retval' and preserves `errno'.
+ */
+static int
+ipmp_querydone(ipmp_state_t *statep, int retval)
+{
+ int error = errno;
+
+ (void) close(statep->st_fd);
+ statep->st_fd = -1;
+ errno = error;
+ return (retval);
+}
+
+/*
+ * Using `handle', get the group list and store the results in a dynamically
+ * allocated buffer pointed to by `*grlistpp'. Returns an IPMP error code.
+ */
+int
+ipmp_getgrouplist(ipmp_handle_t handle, ipmp_grouplist_t **grlistpp)
+{
+ ipmp_state_t *statep = handle;
+ struct timeval end;
+ int retval;
+
+ if (statep->st_snap != NULL) {
+ *grlistpp = ipmp_grouplist_clone(statep->st_snap->sn_grlistp);
+ return (*grlistpp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
+ }
+
+ retval = ipmp_sendquery(statep, IPMP_GROUPLIST, NULL, &end);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_readinfo(statep, IPMP_GROUPLIST, (void **)grlistpp, &end);
+ return (ipmp_querydone(statep, retval));
+}
+
+/*
+ * Free the group list pointed to by `grlistp'.
+ */
+void
+ipmp_freegrouplist(ipmp_grouplist_t *grlistp)
+{
+ free(grlistp);
+}
+
+/*
+ * Using `handle', get the group information associated with group `name' and
+ * store the results in a dynamically allocated buffer pointed to by
+ * `*grinfopp'. Returns an IPMP error code.
+ */
+int
+ipmp_getgroupinfo(ipmp_handle_t handle, const char *name,
+ ipmp_groupinfo_t **grinfopp)
+{
+ ipmp_state_t *statep = handle;
+ ipmp_iflist_t *iflistp;
+ int retval;
+ struct timeval end;
+ ipmp_groupinfo_t *grinfop;
+
+ if (statep->st_snap != NULL) {
+ grinfop = ipmp_snap_getgroupinfo(statep->st_snap, name);
+ if (grinfop == NULL)
+ return (IPMP_EUNKGROUP);
+
+ *grinfopp = ipmp_groupinfo_clone(grinfop);
+ return (*grinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
+ }
+
+ retval = ipmp_sendquery(statep, IPMP_GROUPINFO, name, &end);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_readinfo(statep, IPMP_GROUPINFO, (void **)grinfopp, &end);
+ if (retval != IPMP_SUCCESS)
+ return (ipmp_querydone(statep, retval));
+
+ retval = ipmp_readinfo(statep, IPMP_IFLIST, (void **)&iflistp, &end);
+ if (retval != IPMP_SUCCESS)
+ free(*grinfopp);
+ else
+ (*grinfopp)->gr_iflistp = iflistp;
+
+ return (ipmp_querydone(statep, retval));
+}
+
+/*
+ * Free the group information pointed to by `grinfop'.
+ */
+void
+ipmp_freegroupinfo(ipmp_groupinfo_t *grinfop)
+{
+ free(grinfop->gr_iflistp);
+ free(grinfop);
+}
+
+/*
+ * Using `handle', get the interface information associated with interface
+ * `name' and store the results in a dynamically allocated buffer pointed to
+ * by `*ifinfopp'. Returns an IPMP error code.
+ */
+int
+ipmp_getifinfo(ipmp_handle_t handle, const char *name, ipmp_ifinfo_t **ifinfopp)
+{
+ ipmp_state_t *statep = handle;
+ ipmp_ifinfo_t *ifinfop;
+ int retval;
+ struct timeval end;
+
+ if (statep->st_snap != NULL) {
+ ifinfop = ipmp_snap_getifinfo(statep->st_snap, name);
+ if (ifinfop == NULL)
+ return (IPMP_EUNKIF);
+
+ *ifinfopp = ipmp_ifinfo_clone(ifinfop);
+ return (*ifinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
+ }
+
+ retval = ipmp_sendquery(statep, IPMP_IFINFO, name, &end);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_readinfo(statep, IPMP_IFINFO, (void **)ifinfopp, &end);
+ return (ipmp_querydone(statep, retval));
+}
+
+/*
+ * Free the interface information pointed to by `ifinfop'.
+ */
+void
+ipmp_freeifinfo(ipmp_ifinfo_t *ifinfop)
+{
+ free(ifinfop);
+}
+
+/*
+ * Check if `buf' has a NUL byte in its first `bufsize' bytes.
+ */
+static boolean_t
+hasnulbyte(const char *buf, size_t bufsize)
+{
+ while (bufsize-- > 0) {
+ if (buf[bufsize] == '\0')
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Check that the TLV triplet named by `type', `len' and `value' is correctly
+ * formed.
+ */
+static boolean_t
+ipmp_checktlv(ipmp_infotype_t type, size_t len, void *value)
+{
+ ipmp_iflist_t *iflistp;
+ ipmp_ifinfo_t *ifinfop;
+ ipmp_grouplist_t *grlistp;
+ ipmp_groupinfo_t *grinfop;
+ unsigned int i;
+
+ switch (type) {
+ case IPMP_IFLIST:
+ iflistp = (ipmp_iflist_t *)value;
+ if (len < IPMP_IFLIST_MINSIZE ||
+ len < IPMP_IFLIST_SIZE(iflistp->il_nif))
+ return (B_FALSE);
+
+ for (i = 0; i < iflistp->il_nif; i++)
+ if (!hasnulbyte(iflistp->il_ifs[i], LIFNAMSIZ))
+ return (B_FALSE);
+ break;
+
+ case IPMP_IFINFO:
+ ifinfop = (ipmp_ifinfo_t *)value;
+ if (len != sizeof (ipmp_ifinfo_t))
+ return (B_FALSE);
+
+ if (!hasnulbyte(ifinfop->if_name, LIFNAMSIZ) ||
+ !hasnulbyte(ifinfop->if_group, LIFGRNAMSIZ))
+ return (B_FALSE);
+ break;
+
+ case IPMP_GROUPLIST:
+ grlistp = (ipmp_grouplist_t *)value;
+ if (len < IPMP_GROUPLIST_MINSIZE ||
+ len < IPMP_GROUPLIST_SIZE(grlistp->gl_ngroup))
+ return (B_FALSE);
+
+ for (i = 0; i < grlistp->gl_ngroup; i++)
+ if (!hasnulbyte(grlistp->gl_groups[i], LIFGRNAMSIZ))
+ return (B_FALSE);
+ break;
+
+ case IPMP_GROUPINFO:
+ grinfop = (ipmp_groupinfo_t *)value;
+ if (len != sizeof (ipmp_groupinfo_t))
+ return (B_FALSE);
+
+ if (!hasnulbyte(grinfop->gr_name, LIFGRNAMSIZ))
+ return (B_FALSE);
+ break;
+
+ case IPMP_SNAP:
+ if (len != sizeof (ipmp_snap_t))
+ return (B_FALSE);
+ break;
+
+ default:
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * Create a group list with signature `sig' containing `ngroup' groups named
+ * by `groups'. Returns a pointer to the new group list on success, or NULL
+ * on failure.
+ */
+ipmp_grouplist_t *
+ipmp_grouplist_create(uint64_t sig, unsigned int ngroup,
+ char (*groups)[LIFGRNAMSIZ])
+{
+ unsigned int i;
+ ipmp_grouplist_t *grlistp;
+
+ grlistp = malloc(IPMP_GROUPLIST_SIZE(ngroup));
+ if (grlistp == NULL)
+ return (NULL);
+
+ grlistp->gl_sig = sig;
+ grlistp->gl_ngroup = ngroup;
+ for (i = 0; i < ngroup; i++)
+ (void) strlcpy(grlistp->gl_groups[i], groups[i], LIFGRNAMSIZ);
+
+ return (grlistp);
+}
+
+/*
+ * Clone the group list named by `grlistp'. Returns a pointer to the clone on
+ * success, or NULL on failure.
+ */
+ipmp_grouplist_t *
+ipmp_grouplist_clone(ipmp_grouplist_t *grlistp)
+{
+ return (ipmp_grouplist_create(grlistp->gl_sig, grlistp->gl_ngroup,
+ grlistp->gl_groups));
+}
+
+/*
+ * Create an interface information structure for interface `name' and
+ * associate `group', `state' and `type' with it. Returns a pointer to the
+ * interface information on success, or NULL on failure.
+ */
+ipmp_ifinfo_t *
+ipmp_ifinfo_create(const char *name, const char *group, ipmp_if_state_t state,
+ ipmp_if_type_t type)
+{
+ ipmp_ifinfo_t *ifinfop;
+
+ ifinfop = malloc(sizeof (ipmp_ifinfo_t));
+ if (ifinfop == NULL)
+ return (NULL);
+
+ (void) strlcpy(ifinfop->if_name, name, LIFNAMSIZ);
+ (void) strlcpy(ifinfop->if_group, group, LIFGRNAMSIZ);
+ ifinfop->if_state = state;
+ ifinfop->if_type = type;
+
+ return (ifinfop);
+}
+
+/*
+ * Clone the interface information named by `ifinfop'. Returns a pointer to
+ * the clone on success, or NULL on failure.
+ */
+ipmp_ifinfo_t *
+ipmp_ifinfo_clone(ipmp_ifinfo_t *ifinfop)
+{
+ return (ipmp_ifinfo_create(ifinfop->if_name, ifinfop->if_group,
+ ifinfop->if_state, ifinfop->if_type));
+}
+
+/*
+ * Create a group named `name' with signature `sig', in state `state', and
+ * with the `nif' interfaces named by `ifs' as members. Returns a pointer
+ * to the new group on success, or NULL on failure.
+ */
+ipmp_groupinfo_t *
+ipmp_groupinfo_create(const char *name, uint64_t sig, ipmp_group_state_t state,
+ unsigned int nif, char (*ifs)[LIFNAMSIZ])
+{
+ ipmp_groupinfo_t *grinfop;
+ ipmp_iflist_t *iflistp;
+ unsigned int i;
+
+ grinfop = malloc(sizeof (ipmp_groupinfo_t));
+ if (grinfop == NULL)
+ return (NULL);
+
+ iflistp = malloc(IPMP_IFLIST_SIZE(nif));
+ if (iflistp == NULL) {
+ free(grinfop);
+ return (NULL);
+ }
+
+ grinfop->gr_sig = sig;
+ grinfop->gr_state = state;
+ grinfop->gr_iflistp = iflistp;
+ (void) strlcpy(grinfop->gr_name, name, LIFGRNAMSIZ);
+
+ iflistp->il_nif = nif;
+ for (i = 0; i < nif; i++)
+ (void) strlcpy(iflistp->il_ifs[i], ifs[i], LIFNAMSIZ);
+
+ return (grinfop);
+}
+
+/*
+ * Clone the group information named by `grinfop'. Returns a pointer to
+ * the clone on success, or NULL on failure.
+ */
+ipmp_groupinfo_t *
+ipmp_groupinfo_clone(ipmp_groupinfo_t *grinfop)
+{
+ return (ipmp_groupinfo_create(grinfop->gr_name, grinfop->gr_sig,
+ grinfop->gr_state, grinfop->gr_iflistp->il_nif,
+ grinfop->gr_iflistp->il_ifs));
+}
+
+/*
+ * Set the query context associated with `handle' to `qcontext', which must be
+ * either IPMP_QCONTEXT_LIVE or IPMP_QCONTEXT_SNAP. Upon success, any
+ * previous snapshot associated with `handle' is discarded. Returns an IPMP
+ * error code.
+ */
+int
+ipmp_setqcontext(ipmp_handle_t handle, ipmp_qcontext_t qcontext)
+{
+ ipmp_state_t *statep = handle;
+ ipmp_snap_t *snap;
+ int retval;
+
+ switch (qcontext) {
+ case IPMP_QCONTEXT_LIVE:
+ snap = NULL;
+ break;
+
+ case IPMP_QCONTEXT_SNAP:
+ retval = ipmp_snap_take(statep, &snap);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+ break;
+
+ default:
+ return (IPMP_EINVAL);
+ }
+
+ if (statep->st_snap != NULL)
+ ipmp_snap_free(statep->st_snap);
+ statep->st_snap = snap;
+
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Create an empty snapshot. Returns a pointer to the snapshot on success,
+ * or NULL on failure.
+ */
+ipmp_snap_t *
+ipmp_snap_create(void)
+{
+ ipmp_snap_t *snap;
+
+ snap = malloc(sizeof (ipmp_snap_t));
+ if (snap == NULL)
+ return (NULL);
+
+ snap->sn_grlistp = NULL;
+ snap->sn_grinfolistp = NULL;
+ snap->sn_ifinfolistp = NULL;
+ snap->sn_ngroup = 0;
+ snap->sn_nif = 0;
+
+ return (snap);
+}
+
+/*
+ * Free all of the resources associated with snapshot `snap'.
+ */
+void
+ipmp_snap_free(ipmp_snap_t *snap)
+{
+ ipmp_ifinfolist_t *iflp, *ifnext;
+ ipmp_groupinfolist_t *grlp, *grnext;
+
+ ipmp_freegrouplist(snap->sn_grlistp);
+
+ for (grlp = snap->sn_grinfolistp; grlp != NULL; grlp = grnext) {
+ grnext = grlp->grl_next;
+ ipmp_freegroupinfo(grlp->grl_grinfop);
+ free(grlp);
+ }
+
+ for (iflp = snap->sn_ifinfolistp; iflp != NULL; iflp = ifnext) {
+ ifnext = iflp->ifl_next;
+ ipmp_freeifinfo(iflp->ifl_ifinfop);
+ free(iflp);
+ }
+
+ free(snap);
+}
+
+/*
+ * Add the group information in `grinfop' to the snapshot named by `snap'.
+ * Returns an IPMP error code.
+ */
+int
+ipmp_snap_addgroupinfo(ipmp_snap_t *snap, ipmp_groupinfo_t *grinfop)
+{
+ ipmp_groupinfolist_t *grlp;
+
+ /*
+ * If the information for this group is already in the snapshot,
+ * in.mpathd is broken.
+ */
+ if (ipmp_snap_getgroupinfo(snap, grinfop->gr_name) != NULL)
+ return (IPMP_EPROTO);
+
+ grlp = malloc(sizeof (ipmp_groupinfolist_t));
+ if (grlp == NULL)
+ return (IPMP_ENOMEM);
+
+ grlp->grl_grinfop = grinfop;
+ grlp->grl_next = snap->sn_grinfolistp;
+ snap->sn_grinfolistp = grlp;
+ snap->sn_ngroup++;
+
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Add the interface information in `ifinfop' to the snapshot named by `snap'.
+ * Returns an IPMP error code.
+ */
+int
+ipmp_snap_addifinfo(ipmp_snap_t *snap, ipmp_ifinfo_t *ifinfop)
+{
+ ipmp_ifinfolist_t *iflp;
+
+ /*
+ * If the information for this interface is already in the snapshot,
+ * in.mpathd is broken.
+ */
+ if (ipmp_snap_getifinfo(snap, ifinfop->if_name) != NULL)
+ return (IPMP_EPROTO);
+
+ iflp = malloc(sizeof (ipmp_ifinfolist_t));
+ if (iflp == NULL)
+ return (IPMP_ENOMEM);
+
+ iflp->ifl_ifinfop = ifinfop;
+ iflp->ifl_next = snap->sn_ifinfolistp;
+ snap->sn_ifinfolistp = iflp;
+ snap->sn_nif++;
+
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Retrieve the information for the group `name' in snapshot `snap'.
+ * Returns a pointer to the group information on success, or NULL on failure.
+ */
+static ipmp_groupinfo_t *
+ipmp_snap_getgroupinfo(ipmp_snap_t *snap, const char *name)
+{
+ ipmp_groupinfolist_t *grlp;
+
+ for (grlp = snap->sn_grinfolistp; grlp != NULL; grlp = grlp->grl_next) {
+ if (strcmp(grlp->grl_grinfop->gr_name, name) == 0)
+ break;
+ }
+
+ return (grlp != NULL ? grlp->grl_grinfop : NULL);
+}
+
+/*
+ * Retrieve the information for the interface `name' in snapshot `snap'.
+ * Returns a pointer to the interface information on success, or NULL on
+ * failure.
+ */
+static ipmp_ifinfo_t *
+ipmp_snap_getifinfo(ipmp_snap_t *snap, const char *name)
+{
+ ipmp_ifinfolist_t *iflp;
+
+ for (iflp = snap->sn_ifinfolistp; iflp != NULL; iflp = iflp->ifl_next) {
+ if (strcmp(iflp->ifl_ifinfop->if_name, name) == 0)
+ break;
+ }
+
+ return (iflp != NULL ? iflp->ifl_ifinfop : NULL);
+}
+
+/*
+ * Using `statep', take a snapshot of the IPMP subsystem and if successful
+ * return it in a dynamically allocated snapshot pointed to by `*snapp'.
+ * Returns an IPMP error code.
+ */
+static int
+ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
+{
+ ipmp_snap_t *snap, *osnap;
+ ipmp_infotype_t type;
+ ipmp_iflist_t *iflistp;
+ int retval;
+ size_t len;
+ void *infop;
+ struct timeval end;
+
+ snap = ipmp_snap_create();
+ if (snap == NULL)
+ return (IPMP_ENOMEM);
+
+ retval = ipmp_sendquery(statep, IPMP_SNAP, NULL, &end);
+ if (retval != IPMP_SUCCESS) {
+ ipmp_snap_free(snap);
+ return (retval);
+ }
+
+ retval = ipmp_readinfo(statep, IPMP_SNAP, (void **)&osnap, &end);
+ if (retval != IPMP_SUCCESS) {
+ ipmp_snap_free(snap);
+ return (ipmp_querydone(statep, retval));
+ }
+
+ /*
+ * Using the information in the passed `osnap' snapshot, build up our
+ * own snapshot. If we receive more than one grouplist, or more than
+ * the expected number of interfaces or groups, then bail out. Note
+ * that there's only so much we can do to check that the information
+ * sent by in.mpathd makes sense. We know there will always be at
+ * least one TLV (IPMP_GROUPLIST).
+ */
+ do {
+ infop = NULL;
+ retval = ipmp_readtlv(statep->st_fd, &type, &len, &infop, &end);
+ if (retval != IPMP_SUCCESS)
+ goto fail;
+
+ if (!ipmp_checktlv(type, len, infop)) {
+ retval = IPMP_EPROTO;
+ goto fail;
+ }
+
+ switch (type) {
+ case IPMP_GROUPLIST:
+ if (snap->sn_grlistp != NULL) {
+ retval = IPMP_EPROTO;
+ break;
+ }
+ snap->sn_grlistp = infop;
+ break;
+
+ case IPMP_IFINFO:
+ if (snap->sn_nif == osnap->sn_nif) {
+ retval = IPMP_EPROTO;
+ break;
+ }
+ retval = ipmp_snap_addifinfo(snap, infop);
+ break;
+
+ case IPMP_GROUPINFO:
+ if (snap->sn_ngroup == osnap->sn_ngroup) {
+ retval = IPMP_EPROTO;
+ break;
+ }
+
+ /*
+ * An IPMP_IFLIST TLV always follows the
+ * IPMP_GROUPINFO TLV; read it in.
+ */
+ retval = ipmp_readinfo(statep, IPMP_IFLIST,
+ (void **)&iflistp, &end);
+ if (retval != IPMP_SUCCESS)
+ break;
+
+ ((ipmp_groupinfo_t *)infop)->gr_iflistp = iflistp;
+ retval = ipmp_snap_addgroupinfo(snap, infop);
+ if (retval != IPMP_SUCCESS)
+ free(iflistp);
+ break;
+
+ default:
+ retval = IPMP_EPROTO;
+ break;
+ }
+fail:
+ if (retval != IPMP_SUCCESS) {
+ free(infop);
+ free(osnap);
+ ipmp_snap_free(snap);
+ return (ipmp_querydone(statep, retval));
+ }
+ } while (snap->sn_grlistp == NULL || snap->sn_nif < osnap->sn_nif ||
+ snap->sn_ngroup < osnap->sn_ngroup);
+
+ free(osnap);
+ *snapp = snap;
+ return (ipmp_querydone(statep, IPMP_SUCCESS));
+}
diff --git a/usr/src/lib/libipmp/common/ipmp_query.h b/usr/src/lib/libipmp/common/ipmp_query.h
new file mode 100644
index 0000000000..d92554887a
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp_query.h
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPMP_QUERY_H
+#define _IPMP_QUERY_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h> /* needed by <net/if.h> */
+#include <net/if.h> /* for LIF*NAMSIZ */
+#include <ipmp.h>
+
+/*
+ * IPMP query interfaces.
+ *
+ * These interfaces may only be used within ON or after signing a contract
+ * with ON. For documentation, refer to PSARC/2002/615.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Data type describing a list of IPMP groups.
+ */
+typedef struct ipmp_grouplist {
+ uint64_t gl_sig;
+ unsigned int gl_ngroup;
+ char gl_groups[1][LIFGRNAMSIZ];
+} ipmp_grouplist_t;
+
+#define IPMP_GROUPLIST_MINSIZE (sizeof (ipmp_grouplist_t) - LIFGRNAMSIZ)
+#define IPMP_GROUPLIST_SIZE(ngr) (IPMP_GROUPLIST_MINSIZE + (ngr) * LIFGRNAMSIZ)
+
+/*
+ * Data type describing a list of interfaces.
+ */
+typedef struct ipmp_iflist {
+ unsigned int il_nif;
+ char il_ifs[1][LIFNAMSIZ];
+} ipmp_iflist_t;
+
+#define IPMP_IFLIST_MINSIZE (sizeof (ipmp_iflist_t) - LIFNAMSIZ)
+#define IPMP_IFLIST_SIZE(nif) (IPMP_IFLIST_MINSIZE + (nif) * LIFNAMSIZ)
+
+/*
+ * Data type describing the state of an IPMP group.
+ */
+typedef struct ipmp_groupinfo {
+ char gr_name[LIFGRNAMSIZ];
+ uint64_t gr_sig;
+ ipmp_group_state_t gr_state;
+ ipmp_iflist_t *gr_iflistp;
+} ipmp_groupinfo_t;
+
+/*
+ * Data type describing the IPMP-related state of an interface.
+ */
+typedef struct ipmp_ifinfo {
+ char if_name[LIFNAMSIZ];
+ char if_group[LIFGRNAMSIZ];
+ ipmp_if_state_t if_state;
+ ipmp_if_type_t if_type;
+} ipmp_ifinfo_t;
+
+typedef enum {
+ IPMP_QCONTEXT_LIVE,
+ IPMP_QCONTEXT_SNAP
+} ipmp_qcontext_t;
+
+extern int ipmp_setqcontext(ipmp_handle_t, ipmp_qcontext_t);
+extern int ipmp_getgrouplist(ipmp_handle_t, ipmp_grouplist_t **);
+extern void ipmp_freegrouplist(ipmp_grouplist_t *);
+extern int ipmp_getgroupinfo(ipmp_handle_t, const char *, ipmp_groupinfo_t **);
+extern void ipmp_freegroupinfo(ipmp_groupinfo_t *);
+extern int ipmp_getifinfo(ipmp_handle_t, const char *, ipmp_ifinfo_t **);
+extern void ipmp_freeifinfo(ipmp_ifinfo_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPMP_QUERY_H */
diff --git a/usr/src/lib/libipmp/common/ipmp_query_impl.h b/usr/src/lib/libipmp/common/ipmp_query_impl.h
new file mode 100644
index 0000000000..03ecb5cd84
--- /dev/null
+++ b/usr/src/lib/libipmp/common/ipmp_query_impl.h
@@ -0,0 +1,93 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPMP_QUERY_IMPL_H
+#define _IPMP_QUERY_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ipmp_query.h>
+
+/*
+ * Private IPMP query interfaces and structures.
+ *
+ * These are *only* for use by in.mpathd and libipmp itself.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * List of ipmp_groupinfo_t structures.
+ */
+typedef struct ipmp_groupinfolist {
+ struct ipmp_groupinfolist *grl_next;
+ ipmp_groupinfo_t *grl_grinfop;
+} ipmp_groupinfolist_t;
+
+/*
+ * List of ipmp_ifinfo_t structures.
+ */
+typedef struct ipmp_ifinfolist {
+ struct ipmp_ifinfolist *ifl_next;
+ ipmp_ifinfo_t *ifl_ifinfop;
+} ipmp_ifinfolist_t;
+
+/*
+ * Snapshot of IPMP state.
+ */
+typedef struct ipmp_snap {
+ ipmp_grouplist_t *sn_grlistp;
+ ipmp_groupinfolist_t *sn_grinfolistp;
+ ipmp_ifinfolist_t *sn_ifinfolistp;
+ unsigned int sn_ngroup;
+ unsigned int sn_nif;
+} ipmp_snap_t;
+
+/*
+ * Snapshot-related routines.
+ */
+extern ipmp_snap_t *ipmp_snap_create(void);
+extern void ipmp_snap_free(ipmp_snap_t *);
+extern int ipmp_snap_addifinfo(ipmp_snap_t *, ipmp_ifinfo_t *);
+extern int ipmp_snap_addgroupinfo(ipmp_snap_t *, ipmp_groupinfo_t *);
+
+/*
+ * IPMP structure creation routines.
+ */
+extern ipmp_ifinfo_t *ipmp_ifinfo_create(const char *, const char *,
+ ipmp_if_state_t, ipmp_if_type_t);
+extern ipmp_groupinfo_t *ipmp_groupinfo_create(const char *, uint64_t,
+ ipmp_group_state_t, unsigned int, char (*)[LIFNAMSIZ]);
+extern ipmp_grouplist_t *ipmp_grouplist_create(uint64_t, unsigned int,
+ char (*)[LIFGRNAMSIZ]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPMP_QUERY_IMPL_H */
diff --git a/usr/src/lib/libipmp/common/llib-lipmp b/usr/src/lib/libipmp/common/llib-lipmp
new file mode 100644
index 0000000000..a16011745a
--- /dev/null
+++ b/usr/src/lib/libipmp/common/llib-lipmp
@@ -0,0 +1,34 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <ipmp.h>
+#include <ipmp_mpathd.h>
+#include <ipmp_query_impl.h>
diff --git a/usr/src/lib/libipmp/i386/Makefile b/usr/src/lib/libipmp/i386/Makefile
new file mode 100644
index 0000000000..0c05212571
--- /dev/null
+++ b/usr/src/lib/libipmp/i386/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libipmp/sparc/Makefile b/usr/src/lib/libipmp/sparc/Makefile
new file mode 100644
index 0000000000..0c05212571
--- /dev/null
+++ b/usr/src/lib/libipmp/sparc/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libipmp/spec/Makefile b/usr/src/lib/libipmp/spec/Makefile
new file mode 100644
index 0000000000..5df87a9a92
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/Makefile
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/libipmp/spec/Makefile.targ b/usr/src/lib/libipmp/spec/Makefile.targ
new file mode 100644
index 0000000000..48aa2df3e3
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/Makefile.targ
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libipmp.a
+VERS = .1
+OBJECTS = ipmp.o
+SPECCPP =
diff --git a/usr/src/lib/libipmp/spec/amd64/Makefile b/usr/src/lib/libipmp/spec/amd64/Makefile
new file mode 100644
index 0000000000..4ee7613aaf
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+all clean clobber install lint:
+ @echo "Nothing to $@ on amd64"
diff --git a/usr/src/lib/libipmp/spec/i386/Makefile b/usr/src/lib/libipmp/spec/i386/Makefile
new file mode 100644
index 0000000000..01df11b35b
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/i386/Makefile
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB)
diff --git a/usr/src/lib/libipmp/spec/ipmp.spec b/usr/src/lib/libipmp/spec/ipmp.spec
new file mode 100644
index 0000000000..d2cb5c473e
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/ipmp.spec
@@ -0,0 +1,159 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+function ipmp_open
+include <ipmp.h>
+declaration int ipmp_open(ipmp_handle_t *handlep);
+version SUNWprivate_1.1
+end
+
+function ipmp_close
+include <ipmp.h>
+declaration void ipmp_close(ipmp_handle_t handle);
+version SUNWprivate_1.1
+end
+
+function ipmp_errmsg
+include <ipmp.h>
+declaration const char *ipmp_errmsg(int error);
+version SUNWprivate_1.1
+end
+
+function ipmp_setqcontext
+include <ipmp_query.h>
+declaration int ipmp_setqcontext(ipmp_handle_t handle, \
+ ipmp_qcontext_t qcontext);
+version SUNWprivate_1.1
+end
+
+function ipmp_getgrouplist
+include <ipmp_query.h>
+declaration int ipmp_getgrouplist(ipmp_handle_t handle, \
+ ipmp_grouplist_t **grlistpp);
+version SUNWprivate_1.1
+end
+
+function ipmp_freegrouplist
+include <ipmp_query.h>
+declaration void ipmp_freegrouplist(ipmp_grouplist_t *grlistp);
+version SUNWprivate_1.1
+end
+
+function ipmp_getgroupinfo
+include <ipmp_query.h>
+declaration int ipmp_getgroupinfo(ipmp_handle_t handle, \
+ const char *grname, ipmp_groupinfo_t **grinfopp);
+version SUNWprivate_1.1
+end
+
+function ipmp_freegroupinfo
+include <ipmp_query.h>
+declaration void ipmp_freegroupinfo(ipmp_groupinfo_t *grinfop);
+version SUNWprivate_1.1
+end
+
+function ipmp_getifinfo
+include <ipmp_query.h>
+declaration int ipmp_getifinfo(ipmp_handle_t handle, const char *ifname, \
+ ipmp_ifinfo_t **ifinfopp);
+version SUNWprivate_1.1
+end
+
+function ipmp_freeifinfo
+include <ipmp_query.h>
+declaration void ipmp_freeifinfo(ipmp_ifinfo_t *ifinfop);
+version SUNWprivate_1.1
+end
+
+function ipmp_ifinfo_create
+include <ipmp_query_impl.h>
+declaration ipmp_ifinfo_t *ipmp_ifinfo_create(const char *name, \
+ const char *group, ipmp_if_state_t state, \
+ ipmp_if_type_t type)
+version SUNWprivate_1.1
+end
+
+function ipmp_groupinfo_create
+include <ipmp_query_impl.h>
+declaration ipmp_groupinfo_t *ipmp_groupinfo_create(const char *name, \
+ uint64_t sig, ipmp_group_state_t state, unsigned int nif, \
+ char (*ifs)[LIFNAMSIZ])
+version SUNWprivate_1.1
+end
+
+function ipmp_grouplist_create
+include <ipmp_query_impl.h>
+declaration ipmp_grouplist_t *ipmp_grouplist_create(uint64_t sig, \
+ unsigned int ngroup, char (*groups)[LIFGRNAMSIZ])
+version SUNWprivate_1.1
+end
+
+function ipmp_snap_free
+include <ipmp_query_impl.h>
+declaration void ipmp_snap_free(ipmp_snap_t *)
+version SUNWprivate_1.1
+end
+
+function ipmp_snap_create
+include <ipmp_query_impl.h>
+declaration ipmp_snap_t *ipmp_snap_create(void)
+version SUNWprivate_1.1
+end
+
+function ipmp_snap_addgroupinfo
+include <ipmp_query_impl.h>
+declaration int ipmp_snap_addgroupinfo(ipmp_snap_t *snap, \
+ ipmp_groupinfo_t *grinfop)
+version SUNWprivate_1.1
+end
+
+function ipmp_snap_addifinfo
+include <ipmp_query_impl.h>
+declaration int ipmp_snap_addifinfo(ipmp_snap_t *snap, \
+ ipmp_ifinfo_t *ifinfop)
+version SUNWprivate_1.1
+end
+
+function ipmp_read
+include <ipmp_mpathd.h>
+declaration int ipmp_read(int fd, void *buffer, size_t buflen, \
+ const struct timeval *endtp)
+version SUNWprivate_1.1
+end
+
+function ipmp_write
+include <ipmp_mpathd.h>
+declaration int ipmp_write(int fd, const void *buffer, size_t buflen)
+version SUNWprivate_1.1
+end
+
+function ipmp_writetlv
+include <ipmp_mpathd.h>
+declaration int ipmp_writetlv(int fd, ipmp_infotype_t type, size_t len, \
+ void *value)
+version SUNWprivate_1.1
+end
diff --git a/usr/src/lib/libipmp/spec/sparc/Makefile b/usr/src/lib/libipmp/spec/sparc/Makefile
new file mode 100644
index 0000000000..01df11b35b
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/sparc/Makefile
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB)
diff --git a/usr/src/lib/libipmp/spec/sparcv9/Makefile b/usr/src/lib/libipmp/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..4f53c7c87f
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/sparcv9/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+all clean clobber install lint:
+ @echo "Nothing to $@ on sparcv9"
diff --git a/usr/src/lib/libipmp/spec/versions b/usr/src/lib/libipmp/spec/versions
new file mode 100644
index 0000000000..3fc6f92d2d
--- /dev/null
+++ b/usr/src/lib/libipmp/spec/versions
@@ -0,0 +1,42 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+sparc {
+ SUNWprivate_1.1;
+}
+
+sparcv9 {
+ SUNWprivate_1.1;
+}
+
+i386 {
+ SUNWprivate_1.1;
+}
+
+amd64 {
+ SUNWprivate_1.1;
+}