summaryrefslogtreecommitdiff
path: root/usr/src/cmd/dlmgmtd
diff options
context:
space:
mode:
authorSebastien Roy <Sebastien.Roy@Sun.COM>2009-09-22 22:04:45 -0400
committerSebastien Roy <Sebastien.Roy@Sun.COM>2009-09-22 22:04:45 -0400
commit2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea (patch)
tree72c0d7d4e1c44843a86bab6e3ed6f82cfa7356af /usr/src/cmd/dlmgmtd
parent51fc88a818087605a0e5f11eddb8b66576f72c23 (diff)
downloadillumos-joyent-2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea.tar.gz
PSARC 2009/373 Clearview IP Tunneling
PSARC 2009/410 Datalink Administration from Non-Global Zones 6858533 Clearview IP Tunneling 4861777 *snoop* cannot snoop on tunnel interfaces 5010680 M_IOCTL interface between ip and tun is horribly wrong 5029727 tun prints bogus debug messages when receiving multicast packets on 6to4 tunnels 6835873 dlpi_walk() silently fails in an exclusive zone 4152864 must not allow two tunnels to have the same tsrc/tdst pair 6855902 link and flow kstats are too promiscuous 6218826 need to be able to tunnel into a zone 4505468 network interface names can confuse, lie, and deceive 4524756 tun_wproc() takes up too much stack 6417373 tun_wproc_mdata assertion failures 4627970 scalability problems with IP in IP tunnels 4674797 ifparse_ifspec() will not correctly parse ipv6 tunnels 6509231 dladm should show links in exclusive stack zone 4793233 tun driver should include addr in DL_PHYS_ADDR_ACK for non-zero lengths 6795831 ZONE_*_DATALINK syscalls should take datalink_id_t as argument 6791472 mac module doesn't allow MAC addresses < 6 bytes 6618091 Race condition trips ASSERT() in tun.c's SIOCSLIFNAME path 6837580 bogus mi_active check in mac_set_mtu() 6868083 libinetutil: ofmt_open()'s template argument should be const 6870313 libdladm: needless dladm_init_linkprop() in i_dladm_aggr_up() 6872221 panic in dls_devnet_close() if "mtu" property is being set 4289774 Change to the interface-id does not change IPv6 link-local address 6873561 unable to create links with 31 character link names 6874666 changing a link property can accidentally destroy it 6874682 removing a link attribute corrupts the attribute list 6875167 IPCL_ISV6 conn flag is set but never used 6881764 itp reference leak in ipsec_construct_inverse_acquire() 6881951 dladm delete-vlan can no longer delete persistent-only VLANs --HG-- rename : usr/src/uts/common/inet/tun.h => usr/src/uts/common/inet/iptun.h rename : usr/src/uts/common/inet/ip/tun.c => usr/src/uts/common/inet/iptun/iptun.c rename : usr/src/uts/intel/tun/Makefile => usr/src/uts/intel/iptun/Makefile rename : usr/src/uts/sparc/tun/Makefile => usr/src/uts/sparc/iptun/Makefile
Diffstat (limited to 'usr/src/cmd/dlmgmtd')
-rw-r--r--usr/src/cmd/dlmgmtd/Makefile12
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_db.c991
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_door.c641
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_impl.h43
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_main.c359
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_util.c387
6 files changed, 1659 insertions, 774 deletions
diff --git a/usr/src/cmd/dlmgmtd/Makefile b/usr/src/cmd/dlmgmtd/Makefile
index 2df2508f80..1eb82565c9 100644
--- a/usr/src/cmd/dlmgmtd/Makefile
+++ b/usr/src/cmd/dlmgmtd/Makefile
@@ -38,14 +38,22 @@ ROOTCFGFILES= $(CFGFILES:%=$(ROOTCFGDIR)/%)
$(ROOTCFGDIR)/datalink.conf := FILEMODE= 644
-LDLIBS += -ldladm -ldlpi -lavl -lnvpair -lsysevent
+LDLIBS += -ldladm -ldlpi -lavl -lnvpair -lsysevent -lcontract
+
+#
+# Instrument dlmgmtd with CTF data to ease debugging.
+#
+CTFCONVERT_HOOK = && $(CTFCONVERT_O)
+CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS)
+$(OBJS) := CFLAGS += $(CTF_FLAGS)
+
.KEEP_STATE:
all: $(PROG)
$(PROG): $(OBJS)
- $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK)
$(POST_PROCESS)
install: all $(ROOTSBINPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTCFGDIR) \
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_db.c b/usr/src/cmd/dlmgmtd/dlmgmt_db.c
index e65722613b..807b912d1e 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_db.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_db.c
@@ -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.
*/
@@ -30,11 +30,19 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <strings.h>
#include <syslog.h>
+#include <zone.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <stropts.h>
+#include <sys/conf.h>
#include <pthread.h>
#include <unistd.h>
+#include <wait.h>
+#include <libcontract.h>
+#include <sys/contract/process.h>
#include "dlmgmt_impl.h"
typedef enum dlmgmt_db_op {
@@ -46,7 +54,9 @@ typedef enum dlmgmt_db_op {
typedef struct dlmgmt_db_req_s {
struct dlmgmt_db_req_s *ls_next;
dlmgmt_db_op_t ls_op;
+ char ls_link[MAXLINKNAMELEN];
datalink_id_t ls_linkid;
+ zoneid_t ls_zoneid;
uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */
/* DLMGMT_PERSIST, not both. */
} dlmgmt_db_req_t;
@@ -57,19 +67,28 @@ typedef struct dlmgmt_db_req_s {
static dlmgmt_db_req_t *dlmgmt_db_req_head = NULL;
static dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL;
-static int dlmgmt_db_update(dlmgmt_db_op_t, datalink_id_t,
- uint32_t);
+/*
+ * rewrite_needed is set to B_TRUE by process_link_line() if it encounters a
+ * line with an old format. This will cause the file being read to be
+ * re-written with the current format.
+ */
+static boolean_t rewrite_needed;
+
+static int dlmgmt_db_update(dlmgmt_db_op_t, const char *,
+ dlmgmt_link_t *, uint32_t);
static int dlmgmt_process_db_req(dlmgmt_db_req_t *);
static int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t);
static void *dlmgmt_db_update_thread(void *);
-static boolean_t process_link_line(char *, dlmgmt_link_t **);
+static boolean_t process_link_line(char *, dlmgmt_link_t *);
static int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *);
-static int process_db_read(dlmgmt_db_req_t *, FILE *, FILE *);
+static int process_db_read(dlmgmt_db_req_t *, FILE *);
static void generate_link_line(dlmgmt_link_t *, boolean_t, char *);
#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
#define MAXLINELEN 1024
+typedef void db_walk_func_t(dlmgmt_link_t *);
+
/*
* Translator functions to go from dladm_datatype_t to character strings.
* Each function takes a pointer to a buffer, the size of the buffer,
@@ -127,13 +146,262 @@ static size_t ntranslators = sizeof (translators) / sizeof (translator_t);
/*
* Name of the cache file to keep the active <link name, linkid> mapping
*/
-static char cachefile[MAXPATHLEN];
+char cachefile[MAXPATHLEN];
#define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf"
#define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \
(void) snprintf((buffer), MAXPATHLEN, "%s", \
(persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile);
+typedef struct zopen_arg {
+ const char *zopen_modestr;
+ int *zopen_pipe;
+ int zopen_fd;
+} zopen_arg_t;
+
+typedef struct zrename_arg {
+ const char *zrename_newname;
+} zrename_arg_t;
+
+typedef union zfoparg {
+ zopen_arg_t zfop_openarg;
+ zrename_arg_t zfop_renamearg;
+} zfoparg_t;
+
+typedef struct zfcbarg {
+ boolean_t zfarg_inglobalzone; /* is callback in global zone? */
+ zoneid_t zfarg_finglobalzone; /* is file in global zone? */
+ const char *zfarg_filename;
+ zfoparg_t *zfarg_oparg;
+} zfarg_t;
+#define zfarg_openarg zfarg_oparg->zfop_openarg
+#define zfarg_renamearg zfarg_oparg->zfop_renamearg
+
+/* zone file callback */
+typedef int zfcb_t(zfarg_t *);
+
+/*
+ * Execute an operation on filename relative to zoneid's zone root. If the
+ * file is in the global zone, then the zfcb() callback will simply be called
+ * directly. If the file is in a non-global zone, then zfcb() will be called
+ * both from the global zone's context, and from the non-global zone's context
+ * (from a fork()'ed child that has entered the non-global zone). This is
+ * done to allow the callback to communicate with itself if needed (e.g. to
+ * pass back the file descriptor of an opened file).
+ */
+static int
+dlmgmt_zfop(const char *filename, zoneid_t zoneid, zfcb_t *zfcb,
+ zfoparg_t *zfoparg)
+{
+ int ctfd;
+ int err;
+ pid_t childpid;
+ siginfo_t info;
+ zfarg_t zfarg;
+
+ if (zoneid != GLOBAL_ZONEID) {
+ /*
+ * We need to access a file that isn't in the global zone.
+ * Accessing non-global zone files from the global zone is
+ * unsafe (due to symlink attacks), we'll need to fork a child
+ * that enters the zone in question and executes the callback
+ * that will operate on the file.
+ *
+ * Before we proceed with this zone tango, we need to create a
+ * new process contract for the child, as required by
+ * zone_enter().
+ */
+ errno = 0;
+ ctfd = open64("/system/contract/process/template", O_RDWR);
+ if (ctfd == -1)
+ return (errno);
+ if ((err = ct_tmpl_set_critical(ctfd, 0)) != 0 ||
+ (err = ct_tmpl_set_informative(ctfd, 0)) != 0 ||
+ (err = ct_pr_tmpl_set_fatal(ctfd, CT_PR_EV_HWERR)) != 0 ||
+ (err = ct_pr_tmpl_set_param(ctfd, CT_PR_PGRPONLY)) != 0 ||
+ (err = ct_tmpl_activate(ctfd)) != 0) {
+ return (err);
+ }
+ childpid = fork();
+ (void) ct_tmpl_clear(ctfd);
+ (void) close(ctfd);
+ switch (childpid) {
+ case -1:
+ return (err);
+ case 0:
+ /*
+ * Elevate our privileges as zone_enter() requires all
+ * privileges.
+ */
+ if ((err = dlmgmt_elevate_privileges()) != 0)
+ _exit(err);
+ if (zone_enter(zoneid) == -1)
+ _exit(errno);
+ if ((err = dlmgmt_drop_privileges()) != 0)
+ _exit(err);
+ break;
+ default:
+ if (waitid(P_PID, childpid, &info, WEXITED) == -1)
+ return (errno);
+ if (info.si_status != 0)
+ return (info.si_status);
+ }
+ }
+
+ zfarg.zfarg_inglobalzone = (zoneid == GLOBAL_ZONEID || childpid != 0);
+ zfarg.zfarg_finglobalzone = (zoneid == GLOBAL_ZONEID);
+ zfarg.zfarg_filename = filename;
+ zfarg.zfarg_oparg = zfoparg;
+ err = zfcb(&zfarg);
+ if (!zfarg.zfarg_inglobalzone)
+ _exit(err);
+ return (err);
+}
+
+static int
+dlmgmt_zopen_cb(zfarg_t *zfarg)
+{
+ struct strrecvfd recvfd;
+ boolean_t newfile = B_FALSE;
+ boolean_t inglobalzone = zfarg->zfarg_inglobalzone;
+ zoneid_t finglobalzone = zfarg->zfarg_finglobalzone;
+ const char *filename = zfarg->zfarg_filename;
+ const char *modestr = zfarg->zfarg_openarg.zopen_modestr;
+ int *p = zfarg->zfarg_openarg.zopen_pipe;
+ struct stat statbuf;
+ int oflags;
+ mode_t mode;
+ int fd = -1;
+ int err;
+
+ /* We only ever open a file for reading or writing, not both. */
+ oflags = (modestr[0] == 'r') ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC;
+ mode = (modestr[0] == 'r') ? 0 : S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+ /* Open the file if we're in the same zone as the file. */
+ if (inglobalzone == finglobalzone) {
+ /*
+ * First determine if we will be creating the file as part of
+ * opening it. If so, then we'll need to ensure that it has
+ * the proper ownership after having opened it.
+ */
+ if (oflags & O_CREAT) {
+ if (stat(filename, &statbuf) == -1) {
+ if (errno == ENOENT)
+ newfile = B_TRUE;
+ else
+ return (errno);
+ }
+ }
+ if ((fd = open(filename, oflags, mode)) == -1)
+ return (errno);
+ if (newfile) {
+ if (chown(filename, UID_DLADM, GID_SYS) == -1) {
+ err = errno;
+ (void) close(fd);
+ return (err);
+ }
+ }
+ }
+
+ /*
+ * If we're not in the global zone, send the file-descriptor back to
+ * our parent in the global zone.
+ */
+ if (!inglobalzone) {
+ assert(!finglobalzone);
+ assert(fd != -1);
+ return (ioctl(p[1], I_SENDFD, fd) == -1 ? errno : 0);
+ }
+
+ /*
+ * At this point, we know we're in the global zone. If the file was
+ * in a non-global zone, receive the file-descriptor from our child in
+ * the non-global zone.
+ */
+ if (!finglobalzone) {
+ if (ioctl(p[0], I_RECVFD, &recvfd) == -1)
+ return (errno);
+ fd = recvfd.fd;
+ }
+
+ zfarg->zfarg_openarg.zopen_fd = fd;
+ return (0);
+}
+
+static int
+dlmgmt_zunlink_cb(zfarg_t *zfarg)
+{
+ if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone)
+ return (0);
+ return (unlink(zfarg->zfarg_filename) == 0 ? 0 : errno);
+}
+
+static int
+dlmgmt_zrename_cb(zfarg_t *zfarg)
+{
+ if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone)
+ return (0);
+ return (rename(zfarg->zfarg_filename,
+ zfarg->zfarg_renamearg.zrename_newname) == 0 ? 0 : errno);
+}
+
+/*
+ * Same as fopen(3C), except that it opens the file relative to zoneid's zone
+ * root.
+ */
+static FILE *
+dlmgmt_zfopen(const char *filename, const char *modestr, zoneid_t zoneid,
+ int *err)
+{
+ int p[2];
+ zfoparg_t zfoparg;
+ FILE *fp = NULL;
+
+ if (zoneid != GLOBAL_ZONEID && pipe(p) == -1) {
+ *err = errno;
+ return (NULL);
+ }
+
+ zfoparg.zfop_openarg.zopen_modestr = modestr;
+ zfoparg.zfop_openarg.zopen_pipe = p;
+ *err = dlmgmt_zfop(filename, zoneid, dlmgmt_zopen_cb, &zfoparg);
+ if (zoneid != GLOBAL_ZONEID) {
+ (void) close(p[0]);
+ (void) close(p[1]);
+ }
+ if (*err == 0) {
+ fp = fdopen(zfoparg.zfop_openarg.zopen_fd, modestr);
+ if (fp == NULL) {
+ *err = errno;
+ (void) close(zfoparg.zfop_openarg.zopen_fd);
+ }
+ }
+ return (fp);
+}
+
+/*
+ * Same as rename(2), except that old and new are relative to zoneid's zone
+ * root.
+ */
+static int
+dlmgmt_zrename(const char *old, const char *new, zoneid_t zoneid)
+{
+ zfoparg_t zfoparg;
+
+ zfoparg.zfop_renamearg.zrename_newname = new;
+ return (dlmgmt_zfop(old, zoneid, dlmgmt_zrename_cb, &zfoparg));
+}
+
+/*
+ * Same as unlink(2), except that filename is relative to zoneid's zone root.
+ */
+static int
+dlmgmt_zunlink(const char *filename, zoneid_t zoneid)
+{
+ return (dlmgmt_zfop(filename, zoneid, dlmgmt_zunlink_cb, NULL));
+}
+
static size_t
write_str(char *buffer, size_t buffer_length, char *name, void *value)
{
@@ -237,24 +505,41 @@ read_int64(char *buffer, void **value)
return (sizeof (int64_t));
}
+static dlmgmt_db_req_t *
+dlmgmt_db_req_alloc(dlmgmt_db_op_t op, const char *linkname,
+ datalink_id_t linkid, zoneid_t zoneid, uint32_t flags, int *err)
+{
+ dlmgmt_db_req_t *req;
+
+ if ((req = calloc(1, sizeof (dlmgmt_db_req_t))) == NULL) {
+ *err = errno;
+ } else {
+ req->ls_op = op;
+ if (linkname != NULL)
+ (void) strlcpy(req->ls_link, linkname, MAXLINKNAMELEN);
+ req->ls_linkid = linkid;
+ req->ls_zoneid = zoneid;
+ req->ls_flags = flags;
+ }
+ return (req);
+}
+
+/*
+ * Update the db entry with name "entryname" using information from "linkp".
+ */
static int
-dlmgmt_db_update(dlmgmt_db_op_t op, datalink_id_t linkid, uint32_t flags)
+dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp,
+ uint32_t flags)
{
dlmgmt_db_req_t *req;
int err;
- /*
- * It is either a persistent request or an active request, not both.
- */
+ /* It is either a persistent request or an active request, not both. */
assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
- if ((req = malloc(sizeof (dlmgmt_db_req_t))) == NULL)
- return (ENOMEM);
-
- req->ls_next = NULL;
- req->ls_op = op;
- req->ls_linkid = linkid;
- req->ls_flags = flags;
+ if ((req = dlmgmt_db_req_alloc(op, entryname, linkp->ll_linkid,
+ linkp->ll_zoneid, flags, &err)) == NULL)
+ return (err);
/*
* If the return error is EINPROGRESS, this request is handled
@@ -297,15 +582,11 @@ dlmgmt_process_db_req(dlmgmt_db_req_t *req)
}
err = dlmgmt_process_db_onereq(req, writeop);
- if (err != EINPROGRESS && err != 0 &&
- (req->ls_flags != DLMGMT_ACTIVE || errno != ENOENT)) {
-
+ if (err != EINPROGRESS && err != 0 && err != ENOENT) {
/*
- * Log the error unless the request processing:
- * - is successful;
- * - is still in progress;
- * - has failed with ENOENT because the active configuration
- * file is not created yet;
+ * Log the error unless the request processing is still in
+ * progress or if the configuration file hasn't been created
+ * yet (ENOENT).
*/
dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s "
"operation on %s configuration failed: %s",
@@ -331,79 +612,44 @@ dlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop)
FILE *fp, *nfp = NULL;
char file[MAXPATHLEN];
char newfile[MAXPATHLEN];
- int nfd;
DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST));
- if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
- if (writeop && errno == EROFS) {
- /*
- * This can happen at boot when the file system is
- * read-only. So add this request to the pending
- * request list and start a retry thread.
- */
- return (EINPROGRESS);
- } else if (req->ls_flags == DLMGMT_ACTIVE && errno == ENOENT) {
- /*
- * It is fine if the file keeping active configuration
- * does not exist. This happens during a new reboot.
- */
- if (!writeop)
- return (ENOENT);
- /*
- * If this is an update request for the active
- * configuration, create the file.
- */
- if ((fp = fopen(file, "w")) == NULL)
- return (errno == EROFS ? EINPROGRESS : errno);
- } else {
- return (errno);
- }
- }
+ fp = dlmgmt_zfopen(file, "r", req->ls_zoneid, &err);
+ /*
+ * Note that it is not an error if the file doesn't exist. If we're
+ * reading, we treat this case the same way as an empty file. If
+ * we're writing, the file will be created when we open the file for
+ * writing below.
+ */
+ if (fp == NULL && !writeop)
+ return (err);
if (writeop) {
(void) snprintf(newfile, MAXPATHLEN, "%s.new", file);
- if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
- err = errno;
- (void) fclose(fp);
- return (err);
- }
-
- if ((nfp = fdopen(nfd, "w")) == NULL) {
- err = errno;
- (void) close(nfd);
- (void) fclose(fp);
- (void) unlink(newfile);
- return (err);
+ nfp = dlmgmt_zfopen(newfile, "w", req->ls_zoneid, &err);
+ if (nfp == NULL) {
+ /*
+ * EROFS can happen at boot when the file system is
+ * read-only. Return EINPROGRESS so that the caller
+ * can add this request to the pending request list
+ * and start a retry thread.
+ */
+ err = (errno == EROFS ? EINPROGRESS : errno);
+ goto done;
}
}
- if (writeop)
- err = process_db_write(req, fp, nfp);
- else
- err = process_db_read(req, fp, nfp);
- if (!writeop || err != 0)
- goto done;
-
- if (fflush(nfp) == EOF) {
- err = errno;
- goto done;
- }
- (void) fclose(fp);
- (void) fclose(nfp);
-
- if (rename(newfile, file) < 0) {
- err = errno;
- (void) unlink(newfile);
- return (err);
+ if (writeop) {
+ if ((err = process_db_write(req, fp, nfp)) == 0)
+ err = dlmgmt_zrename(newfile, file, req->ls_zoneid);
+ } else {
+ err = process_db_read(req, fp);
}
- return (0);
-
done:
if (nfp != NULL) {
(void) fclose(nfp);
if (err != 0)
- (void) unlink(newfile);
+ (void) dlmgmt_zunlink(newfile, req->ls_zoneid);
}
(void) fclose(fp);
return (err);
@@ -414,15 +660,13 @@ static void *
dlmgmt_db_update_thread(void *arg)
{
dlmgmt_db_req_t *req;
- int err = 0;
dlmgmt_table_lock(B_TRUE);
assert(dlmgmt_db_req_head != NULL);
while ((req = dlmgmt_db_req_head) != NULL) {
assert(req->ls_flags == DLMGMT_PERSIST);
- err = dlmgmt_process_db_onereq(req, B_TRUE);
- if (err == EINPROGRESS) {
+ if (dlmgmt_process_db_onereq(req, B_TRUE) == EINPROGRESS) {
/*
* The filesystem is still read only. Go to sleep and
* try again.
@@ -494,7 +738,11 @@ parse_linkprops(char *buf, dlmgmt_link_t *linkp)
if (c == '=')
goto parse_fail;
- if (strcmp(attr_name, "name") == 0) {
+ if (strcmp(attr_name, "linkid") == 0) {
+ (void) read_int64(curr, &attr_buf);
+ linkp->ll_linkid =
+ (datalink_class_t)*(int64_t *)attr_buf;
+ } else if (strcmp(attr_name, "name") == 0) {
(void) read_str(curr, &attr_buf);
(void) snprintf(linkp->ll_link,
MAXLINKNAMELEN, "%s", attr_buf);
@@ -553,12 +801,14 @@ parse_fail:
}
static boolean_t
-process_link_line(char *buf, dlmgmt_link_t **linkpp)
+process_link_line(char *buf, dlmgmt_link_t *linkp)
{
- dlmgmt_link_t *linkp;
- int i, len, llen;
- char *str, *lasts;
- char tmpbuf[MAXLINELEN];
+ int i, len, llen;
+ char *str, *lasts;
+ char tmpbuf[MAXLINELEN];
+
+ bzero(linkp, sizeof (*linkp));
+ linkp->ll_linkid = DATALINK_INVALID_LINKID;
/*
* Use a copy of buf for parsing so that we can do whatever we want.
@@ -573,24 +823,33 @@ process_link_line(char *buf, dlmgmt_link_t **linkpp)
if (!isspace(tmpbuf[i]))
break;
}
- if (i == len || tmpbuf[i] == '#') {
- *linkpp = NULL;
+ if (i == len || tmpbuf[i] == '#')
return (B_TRUE);
- }
-
- linkp = calloc(1, sizeof (dlmgmt_link_t));
- if (linkp == NULL)
- goto fail;
str = tmpbuf + i;
/*
- * Find the link id and assign it to the link structure.
+ * Find the link name and assign it to the link structure.
*/
if (strtok_r(str, " \n\t", &lasts) == NULL)
goto fail;
llen = strlen(str);
- linkp->ll_linkid = atoi(str);
+ /*
+ * Note that a previous version of the persistent datalink.conf file
+ * stored the linkid as the first field. In that case, the name will
+ * be obtained through parse_linkprops from a property with the format
+ * "name=<linkname>". If we encounter such a format, we set
+ * rewrite_needed so that dlmgmt_db_init() can rewrite the file with
+ * the new format after it's done reading in the data.
+ */
+ if (isdigit(str[0])) {
+ linkp->ll_linkid = atoi(str);
+ rewrite_needed = B_TRUE;
+ } else {
+ if (strlcpy(linkp->ll_link, str, sizeof (linkp->ll_link)) >=
+ sizeof (linkp->ll_link))
+ goto fail;
+ }
str += llen + 1;
if (str >= tmpbuf + len)
@@ -605,12 +864,9 @@ process_link_line(char *buf, dlmgmt_link_t **linkpp)
if (parse_linkprops(str, linkp) < 0)
goto fail;
- *linkpp = linkp;
return (B_TRUE);
fail:
- link_destroy(linkp);
-
/*
* Delete corrupted line.
*/
@@ -618,20 +874,82 @@ fail:
return (B_FALSE);
}
+/*
+ * Find any properties in linkp that refer to "old", and rename to "new".
+ * Return B_TRUE if any renaming occurred.
+ */
+static int
+dlmgmt_attr_rename(dlmgmt_link_t *linkp, const char *old, const char *new,
+ boolean_t *renamed)
+{
+ dlmgmt_linkattr_t *attrp;
+ char *newval = NULL, *pname;
+ char valcp[MAXLINKATTRVALLEN];
+ size_t newsize;
+
+ *renamed = B_FALSE;
+
+ if ((attrp = linkattr_find(linkp->ll_head, "linkover")) != NULL ||
+ (attrp = linkattr_find(linkp->ll_head, "simnetpeer")) != NULL) {
+ if (strcmp(old, (char *)attrp->lp_val) == 0) {
+ newsize = strlen(new) + 1;
+ if ((newval = malloc(newsize)) == NULL)
+ return (errno);
+ (void) strcpy(newval, new);
+ free(attrp->lp_val);
+ attrp->lp_val = newval;
+ attrp->lp_sz = newsize;
+ *renamed = B_TRUE;
+ }
+ return (0);
+ }
+
+ if ((attrp = linkattr_find(linkp->ll_head, "portnames")) == NULL)
+ return (0);
+
+ /* <linkname>:[<linkname>:]... */
+ if ((newval = calloc(MAXLINKATTRVALLEN, sizeof (char))) == NULL)
+ return (errno);
+
+ bcopy(attrp->lp_val, valcp, sizeof (valcp));
+ pname = strtok(valcp, ":");
+ while (pname != NULL) {
+ if (strcmp(pname, old) == 0) {
+ (void) strcat(newval, new);
+ *renamed = B_TRUE;
+ } else {
+ (void) strcat(newval, pname);
+ }
+ (void) strcat(newval, ":");
+ pname = strtok(NULL, ":");
+ }
+ if (*renamed) {
+ free(attrp->lp_val);
+ attrp->lp_val = newval;
+ attrp->lp_sz = strlen(newval) + 1;
+ } else {
+ free(newval);
+ }
+ return (0);
+}
+
static int
process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
{
boolean_t done = B_FALSE;
int err = 0;
- dlmgmt_link_t *linkp, *link_in_file, link;
+ dlmgmt_link_t link_in_file, *linkp = NULL, *dblinkp;
+ boolean_t persist = (req->ls_flags == DLMGMT_PERSIST);
+ boolean_t writeall, rename, attr_renamed;
char buf[MAXLINELEN];
- if (req->ls_op == DLMGMT_DB_OP_WRITE) {
+ writeall = (req->ls_linkid == DATALINK_ALL_LINKID);
+
+ if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall) {
/*
* find the link in the avl tree with the given linkid.
*/
- link.ll_linkid = req->ls_linkid;
- linkp = avl_find(&dlmgmt_id_avl, &link, NULL);
+ linkp = link_by_id(req->ls_linkid, req->ls_zoneid);
if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) {
/*
* This link has already been changed. This could
@@ -640,50 +958,77 @@ process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
*/
return (0);
}
+ /*
+ * In the case of a rename, linkp's name has been updated to
+ * the new name, and req->ls_link is the old link name.
+ */
+ rename = (strcmp(req->ls_link, linkp->ll_link) != 0);
}
+ /*
+ * fp can be NULL if the file didn't initially exist and we're
+ * creating it as part of this write operation.
+ */
+ if (fp == NULL)
+ goto write;
+
while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL &&
process_link_line(buf, &link_in_file)) {
- if (link_in_file == NULL || done) {
+ if (link_in_file.ll_link[0] == '\0' || done) {
/*
* this is a comment line or we are done updating the
- * link of the given link, write the rest of lines out.
+ * line for the specified link, write the rest of
+ * lines out.
*/
if (fputs(buf, nfp) == EOF)
err = errno;
- if (link_in_file != NULL)
- link_destroy(link_in_file);
continue;
}
switch (req->ls_op) {
case DLMGMT_DB_OP_WRITE:
/*
- * For write operations, if the linkid of the link
- * read from the file does not match the id of what
- * req->ll_linkid points to, write out the buffer.
- * Otherwise, generate a new line. If we get to the
- * end and have not seen what req->ll_linkid points
- * to, write it out then.
+ * For write operations, we generate a new output line
+ * if we're either writing all links (writeall) or if
+ * the name of the link in the file matches the one
+ * we're looking for. Otherwise, we write out the
+ * buffer as-is.
+ *
+ * If we're doing a rename operation, ensure that any
+ * references to the link being renamed in link
+ * properties are also updated before we write
+ * anything.
*/
- if (linkp == NULL ||
- linkp->ll_linkid != link_in_file->ll_linkid) {
- if (fputs(buf, nfp) == EOF)
- err = errno;
- } else {
- generate_link_line(linkp,
- req->ls_flags == DLMGMT_PERSIST, buf);
- if (fputs(buf, nfp) == EOF)
- err = errno;
- done = B_TRUE;
+ if (writeall) {
+ linkp = link_by_name(link_in_file.ll_link,
+ req->ls_zoneid);
}
+ if (writeall || strcmp(req->ls_link,
+ link_in_file.ll_link) == 0) {
+ generate_link_line(linkp, persist, buf);
+ if (!writeall && !rename)
+ done = B_TRUE;
+ } else if (rename && persist) {
+ dblinkp = link_by_name(link_in_file.ll_link,
+ req->ls_zoneid);
+ err = dlmgmt_attr_rename(dblinkp, req->ls_link,
+ linkp->ll_link, &attr_renamed);
+ if (err != 0)
+ break;
+ if (attr_renamed) {
+ generate_link_line(dblinkp, persist,
+ buf);
+ }
+ }
+ if (fputs(buf, nfp) == EOF)
+ err = errno;
break;
case DLMGMT_DB_OP_DELETE:
/*
* Delete is simple. If buf does not represent the
* link we're deleting, write it out.
*/
- if (req->ls_linkid != link_in_file->ll_linkid) {
+ if (strcmp(req->ls_link, link_in_file.ll_link) != 0) {
if (fputs(buf, nfp) == EOF)
err = errno;
} else {
@@ -695,33 +1040,28 @@ process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
err = EINVAL;
break;
}
- link_destroy(link_in_file);
}
+write:
/*
- * If we get to the end of the file and have not seen what
- * req->ll_linkid points to, write it out then.
+ * If we get to the end of the file and have not seen what linkid
+ * points to, write it out then.
*/
- if (req->ls_op == DLMGMT_DB_OP_WRITE && !done) {
- generate_link_line(linkp, req->ls_flags == DLMGMT_PERSIST, buf);
+ if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall && !rename && !done) {
+ generate_link_line(linkp, persist, buf);
done = B_TRUE;
if (fputs(buf, nfp) == EOF)
err = errno;
}
- if (!done)
- err = ENOENT;
-
return (err);
}
-/* ARGSUSED1 */
static int
-process_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
+process_db_read(dlmgmt_db_req_t *req, FILE *fp)
{
avl_index_t name_where, id_where;
- dlmgmt_link_t *link_in_file;
- dlmgmt_link_t *linkp1, *linkp2;
+ dlmgmt_link_t link_in_file, *newlink, *link_in_db;
char buf[MAXLINELEN];
int err = 0;
@@ -737,40 +1077,71 @@ process_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
/*
* Skip the comment line.
*/
- if (link_in_file == NULL)
+ if (link_in_file.ll_link[0] == '\0')
+ continue;
+
+ if ((req->ls_flags & DLMGMT_ACTIVE) &&
+ link_in_file.ll_linkid == DATALINK_INVALID_LINKID)
continue;
- linkp1 = avl_find(&dlmgmt_name_avl, link_in_file, &name_where);
- linkp2 = avl_find(&dlmgmt_id_avl, link_in_file, &id_where);
- if ((linkp1 != NULL) || (linkp2 != NULL)) {
+ link_in_file.ll_zoneid = req->ls_zoneid;
+ link_in_db = avl_find(&dlmgmt_name_avl, &link_in_file,
+ &name_where);
+ if (link_in_db != NULL) {
/*
- * If any of the following conditions are met, this is
- * a duplicate entry:
- *
- * 1. link2 (with the given name) and link2 (with the
- * given id) are not the same link;
- * 2. This is a persistent req and find the link with
- * the given name and id. Note that persistent db
- * is read before the active one.
- * 3. Found the link with the given name and id but
- * the link is already active.
+ * If the link in the database already has the flag
+ * for this request set, then the entry is a
+ * duplicate. If it's not a duplicate, then simply
+ * turn on the appropriate flag on the existing link.
*/
- if ((linkp1 != linkp2) ||
- (req->ls_flags == DLMGMT_PERSIST) ||
- ((linkp1->ll_flags & DLMGMT_ACTIVE) != 0)) {
- dlmgmt_log(LOG_WARNING, "Duplicate link "
- "entries in repository: link name %s "
- "link id %i", link_in_file->ll_link,
- link_in_file->ll_linkid);
+ if (link_in_db->ll_flags & req->ls_flags) {
+ dlmgmt_log(LOG_WARNING, "Duplicate links "
+ "in the repository: %s",
+ link_in_file.ll_link);
} else {
- linkp1->ll_flags |= DLMGMT_ACTIVE;
+ if (req->ls_flags & DLMGMT_PERSIST) {
+ /*
+ * Save the newly read properties into
+ * the existing link.
+ */
+ assert(link_in_db->ll_head == NULL);
+ link_in_db->ll_head =
+ link_in_file.ll_head;
+ }
+ link_in_db->ll_flags |= req->ls_flags;
}
- link_destroy(link_in_file);
} else {
- avl_insert(&dlmgmt_name_avl, link_in_file, name_where);
- avl_insert(&dlmgmt_id_avl, link_in_file, id_where);
- dlmgmt_advance(link_in_file);
- link_in_file->ll_flags |= req->ls_flags;
+ /*
+ * This is a new link. Allocate a new dlmgmt_link_t
+ * and add it to the trees.
+ */
+ newlink = calloc(1, sizeof (*newlink));
+ if (newlink == NULL) {
+ dlmgmt_log(LOG_WARNING, "Unable to allocate "
+ "memory to create new link %s",
+ link_in_file.ll_link);
+ continue;
+ }
+ bcopy(&link_in_file, newlink, sizeof (*newlink));
+
+ if (newlink->ll_linkid == DATALINK_INVALID_LINKID)
+ newlink->ll_linkid = dlmgmt_nextlinkid;
+ if (avl_find(&dlmgmt_id_avl, newlink, &id_where) !=
+ NULL) {
+ link_destroy(newlink);
+ continue;
+ }
+ if ((req->ls_flags & DLMGMT_ACTIVE) &&
+ link_activate(newlink) != 0) {
+ dlmgmt_log(LOG_WARNING, "Unable to activate %s",
+ newlink->ll_link);
+ link_destroy(newlink);
+ continue;
+ }
+ avl_insert(&dlmgmt_name_avl, newlink, name_where);
+ avl_insert(&dlmgmt_id_avl, newlink, id_where);
+ dlmgmt_advance(newlink);
+ newlink->ll_flags |= req->ls_flags;
}
}
@@ -780,70 +1151,72 @@ process_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
/*
* Generate an entry in the link database.
* Each entry has this format:
- * <link id> <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
+ * <link name> <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
*/
static void
generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
{
char tmpbuf[MAXLINELEN];
- char *ptr;
+ char *ptr = tmpbuf;
char *lim = tmpbuf + MAXLINELEN;
- char *name_to_write = NULL;
- datalink_id_t id_to_write;
dlmgmt_linkattr_t *cur_p = NULL;
uint64_t u64;
- ptr = tmpbuf;
- id_to_write = linkp->ll_linkid;
- ptr += snprintf(ptr, BUFLEN(lim, ptr), "%d\t", id_to_write);
- name_to_write = linkp->ll_link;
- ptr += write_str(ptr, BUFLEN(lim, ptr), "name", name_to_write);
+ ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link);
+ if (!persist) {
+ /*
+ * We store the linkid in the active database so that dlmgmtd
+ * can recover in the event that it is restarted.
+ */
+ u64 = linkp->ll_linkid;
+ ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64);
+ }
u64 = linkp->ll_class;
ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
u64 = linkp->ll_media;
ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
/*
- * The daemon does not keep any active link attribute. If this request
- * is for active configuration, we are done.
+ * The daemon does not keep any active link attribute. Only store the
+ * attributes if this request is for persistent configuration,
*/
- if (!persist)
- goto done;
-
- for (cur_p = linkp->ll_head; cur_p != NULL; cur_p = cur_p->lp_next) {
- ptr += translators[cur_p->lp_type].write_func(ptr,
- BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
+ if (persist) {
+ for (cur_p = linkp->ll_head; cur_p != NULL;
+ cur_p = cur_p->lp_next) {
+ ptr += translators[cur_p->lp_type].write_func(ptr,
+ BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
+ }
}
-done:
- if (ptr > lim)
- return;
- (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
+
+ if (ptr <= lim)
+ (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
}
int
-dlmgmt_delete_db_entry(datalink_id_t linkid, uint32_t flags)
+dlmgmt_delete_db_entry(dlmgmt_link_t *linkp, uint32_t flags)
{
- return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkid, flags));
+ return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkp->ll_link, linkp,
+ flags));
}
int
-dlmgmt_write_db_entry(datalink_id_t linkid, uint32_t flags)
+dlmgmt_write_db_entry(const char *entryname, dlmgmt_link_t *linkp,
+ uint32_t flags)
{
- int err;
+ int err;
if (flags & DLMGMT_PERSIST) {
- if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE,
- linkid, DLMGMT_PERSIST)) != 0) {
+ if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname,
+ linkp, DLMGMT_PERSIST)) != 0) {
return (err);
}
}
if (flags & DLMGMT_ACTIVE) {
- if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE,
- linkid, DLMGMT_ACTIVE)) != 0) &&
- (flags & DLMGMT_PERSIST)) {
- (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE,
- linkid, DLMGMT_PERSIST);
+ if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname,
+ linkp, DLMGMT_ACTIVE)) != 0) && (flags & DLMGMT_PERSIST)) {
+ (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE, entryname,
+ linkp, DLMGMT_PERSIST);
return (err);
}
}
@@ -852,87 +1225,177 @@ dlmgmt_write_db_entry(datalink_id_t linkid, uint32_t flags)
}
/*
+ * Upgrade properties that have link IDs as values to link names. Because '.'
+ * is a valid linkname character, the port separater for link aggregations
+ * must be changed to ':'.4
+ */
+static void
+linkattr_upgrade(dlmgmt_linkattr_t *attrp)
+{
+ datalink_id_t linkid;
+ char *portidstr;
+ char portname[MAXLINKNAMELEN + 1];
+ dlmgmt_link_t *linkp;
+ char *new_attr_val;
+ size_t new_attr_sz;
+ boolean_t upgraded = B_FALSE;
+
+ if (strcmp(attrp->lp_name, "linkover") == 0 ||
+ strcmp(attrp->lp_name, "simnetpeer") == 0) {
+ if (attrp->lp_type == DLADM_TYPE_UINT64) {
+ linkid = *(datalink_id_t *)attrp->lp_val;
+ if ((linkp = link_by_id(linkid, GLOBAL_ZONEID)) == NULL)
+ return;
+ new_attr_sz = strlen(linkp->ll_link) + 1;
+ if ((new_attr_val = malloc(new_attr_sz)) == NULL)
+ return;
+ (void) strcpy(new_attr_val, linkp->ll_link);
+ upgraded = B_TRUE;
+ }
+ } else if (strcmp(attrp->lp_name, "portnames") == 0) {
+ /*
+ * The old format for "portnames" was
+ * "<linkid>.[<linkid>.]...". The new format is
+ * "<linkname>:[<linkname>:]...".
+ */
+ if (!isdigit(((char *)attrp->lp_val)[0]))
+ return;
+ new_attr_val = calloc(MAXLINKATTRVALLEN, sizeof (char));
+ if (new_attr_val == NULL)
+ return;
+ portidstr = (char *)attrp->lp_val;
+ while (*portidstr != '\0') {
+ errno = 0;
+ linkid = strtol(portidstr, &portidstr, 10);
+ if (linkid == 0 || *portidstr != '.' ||
+ (linkp = link_by_id(linkid, GLOBAL_ZONEID)) ==
+ NULL) {
+ free(new_attr_val);
+ return;
+ }
+ (void) snprintf(portname, sizeof (portname), "%s:",
+ linkp->ll_link);
+ if (strlcat(new_attr_val, portname,
+ MAXLINKATTRVALLEN) >= MAXLINKATTRVALLEN) {
+ free(new_attr_val);
+ return;
+ }
+ /* skip the '.' delimiter */
+ portidstr++;
+ }
+ new_attr_sz = strlen(new_attr_val) + 1;
+ upgraded = B_TRUE;
+ }
+
+ if (upgraded) {
+ attrp->lp_type = DLADM_TYPE_STR;
+ attrp->lp_sz = new_attr_sz;
+ free(attrp->lp_val);
+ attrp->lp_val = new_attr_val;
+ }
+}
+
+static void
+dlmgmt_db_upgrade(dlmgmt_link_t *linkp)
+{
+ dlmgmt_linkattr_t *attrp;
+
+ for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next)
+ linkattr_upgrade(attrp);
+}
+
+static void
+dlmgmt_db_phys_activate(dlmgmt_link_t *linkp)
+{
+ linkp->ll_flags |= DLMGMT_ACTIVE;
+ (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE);
+}
+
+static void
+dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func)
+{
+ dlmgmt_link_t *linkp;
+
+ for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
+ linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
+ if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class))
+ func(linkp);
+ }
+}
+
+/*
* Initialize the datalink <link name, linkid> mapping and the link's
* attributes list based on the configuration file /etc/dladm/datalink.conf
* and the active configuration cache file
* /etc/svc/volatile/dladm/datalink-management:default.cache.
- *
- * This function is called when the datalink-management service is started
- * during reboot, and when the dlmgmtd daemon is restarted.
*/
int
-dlmgmt_db_init()
+dlmgmt_db_init(zoneid_t zoneid)
{
- char filename[MAXPATHLEN];
- dlmgmt_db_req_t req;
+ dlmgmt_db_req_t *req;
int err;
- dlmgmt_link_t *linkp;
- char *fmri, *c;
+ boolean_t boot = B_FALSE;
- /*
- * First derive the name of the cache file from the FMRI name. This
- * cache name is used to keep active datalink configuration.
- */
- if (debug) {
- (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
- DLMGMT_TMPFS_DIR, progname, ".debug.cache");
- } else {
- if ((fmri = getenv("SMF_FMRI")) == NULL) {
- dlmgmt_log(LOG_WARNING, "dlmgmtd is an smf(5) managed "
- "service and should not be run from the command "
- "line.");
- return (EINVAL);
- }
+ if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL,
+ DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL)
+ return (err);
+ if ((err = dlmgmt_process_db_req(req)) != 0) {
/*
- * The FMRI name is in the form of
- * svc:/service/service:instance. We need to remove the
- * prefix "svc:/" and replace '/' with '-'. The cache file
- * name is in the form of "service:instance.cache".
+ * If we get back ENOENT, that means that the active
+ * configuration file doesn't exist yet, and is not an error.
+ * We'll create it down below after we've loaded the
+ * persistent configuration.
*/
- if ((c = strchr(fmri, '/')) != NULL)
- c++;
- else
- c = fmri;
- (void) snprintf(filename, MAXPATHLEN, "%s.cache", c);
- for (c = filename; *c != '\0'; c++) {
- if (*c == '/')
- *c = '-';
- }
-
- (void) snprintf(cachefile, MAXPATHLEN, "%s/%s",
- DLMGMT_TMPFS_DIR, filename);
+ if (err != ENOENT)
+ goto done;
+ boot = B_TRUE;
}
- dlmgmt_table_lock(B_TRUE);
-
- req.ls_next = NULL;
- req.ls_op = DLMGMT_DB_OP_READ;
- req.ls_linkid = DATALINK_INVALID_LINKID;
- req.ls_flags = DLMGMT_PERSIST;
-
- if ((err = dlmgmt_process_db_req(&req)) != 0)
+ req->ls_flags = DLMGMT_PERSIST;
+ err = dlmgmt_process_db_req(req);
+ if (err != 0 && err != ENOENT)
goto done;
-
- req.ls_flags = DLMGMT_ACTIVE;
- err = dlmgmt_process_db_req(&req);
- if (err == ENOENT) {
+ err = 0;
+ if (rewrite_needed) {
/*
- * The temporary datalink.conf does not exist. This is
- * the first boot. Mark all the physical links active.
+ * First update links in memory, then dump the entire db to
+ * disk.
*/
- for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
- linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
- if (linkp->ll_class == DATALINK_CLASS_PHYS) {
- linkp->ll_flags |= DLMGMT_ACTIVE;
- (void) dlmgmt_write_db_entry(
- linkp->ll_linkid, DLMGMT_ACTIVE);
- }
- }
- err = 0;
+ dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade);
+ req->ls_op = DLMGMT_DB_OP_WRITE;
+ req->ls_linkid = DATALINK_ALL_LINKID;
+ if ((err = dlmgmt_process_db_req(req)) != 0 &&
+ err != EINPROGRESS)
+ goto done;
+ }
+ if (boot) {
+ dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS,
+ dlmgmt_db_phys_activate);
}
done:
- dlmgmt_table_unlock();
+ if (err == EINPROGRESS)
+ err = 0;
+ else
+ free(req);
return (err);
}
+
+/*
+ * Remove all links in the given zoneid.
+ */
+void
+dlmgmt_db_fini(zoneid_t zoneid)
+{
+ dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp;
+
+ while (linkp != NULL) {
+ next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
+ if (linkp->ll_zoneid == zoneid) {
+ (void) dlmgmt_destroy_common(linkp,
+ DLMGMT_ACTIVE | DLMGMT_PERSIST);
+ }
+ linkp = next_linkp;
+ }
+}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_door.c b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
index e73f4841b6..ad59cfe190 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_door.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
@@ -28,6 +28,23 @@
* Main door handler functions used by dlmgmtd to process the different door
* call requests. Door call requests can come from the user-land applications,
* or from the kernel.
+ *
+ * Note on zones handling:
+ *
+ * There are two zoneid's associated with a link. One is the zoneid of the
+ * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
+ * the other is the zoneid of the zone where the link is currently assigned
+ * (the "zone" link property). The two can be different if a datalink is
+ * created in the global zone and subsequently assigned to a non-global zone
+ * via zonecfg or via explicitly setting the "zone" link property.
+ *
+ * Door clients can see links that were created in their zone, and links that
+ * are currently assigned to their zone. Door clients in a zone can only
+ * modify links that were created in their zone.
+ *
+ * The datalink ID space is global, while each zone has its own datalink name
+ * space. This allows each zone to have complete freedom over the names that
+ * they assign to links created within the zone.
*/
#include <assert.h>
@@ -38,29 +55,47 @@
#include <strings.h>
#include <syslog.h>
#include <sys/sysevent/eventdefs.h>
+#include <zone.h>
#include <libsysevent.h>
#include <libdlmgmt.h>
#include <librcm.h>
#include "dlmgmt_impl.h"
-typedef void dlmgmt_door_handler_t(void *, void *);
+typedef void dlmgmt_door_handler_t(void *, void *, zoneid_t, ucred_t *);
typedef struct dlmgmt_door_info_s {
uint_t di_cmd;
- boolean_t di_set;
size_t di_reqsz;
size_t di_acksz;
dlmgmt_door_handler_t *di_handler;
} dlmgmt_door_info_t;
+/*
+ * Check if the caller has the required privileges to operate on a link of the
+ * given class.
+ */
+static int
+dlmgmt_checkprivs(datalink_class_t class, ucred_t *cred)
+{
+ const priv_set_t *eset;
+
+ eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
+ if (eset != NULL && ((class == DATALINK_CLASS_IPTUN &&
+ priv_ismember(eset, PRIV_SYS_IPTUN_CONFIG)) ||
+ priv_ismember(eset, PRIV_SYS_DL_CONFIG) ||
+ priv_ismember(eset, PRIV_SYS_NET_CONFIG)))
+ return (0);
+ return (EACCES);
+}
static dlmgmt_link_t *
-dlmgmt_getlink_by_dev(char *devname)
+dlmgmt_getlink_by_dev(char *devname, zoneid_t zoneid)
{
dlmgmt_link_t *linkp = avl_first(&dlmgmt_id_avl);
for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
- if ((linkp->ll_class == DATALINK_CLASS_PHYS) &&
+ if (link_is_visible(linkp, zoneid) &&
+ (linkp->ll_class == DATALINK_CLASS_PHYS) &&
linkattr_equal(&(linkp->ll_head), FDEVNAME, devname,
strlen(devname) + 1)) {
return (linkp);
@@ -102,7 +137,7 @@ done:
}
static void
-dlmgmt_upcall_create(void *argp, void *retp)
+dlmgmt_upcall_create(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_upcall_arg_create_t *create = argp;
dlmgmt_create_retval_t *retvalp = retp;
@@ -129,13 +164,15 @@ dlmgmt_upcall_create(void *argp, void *retp)
*/
dlmgmt_table_lock(B_TRUE);
+ if ((err = dlmgmt_checkprivs(class, cred)) != 0)
+ goto done;
+
/*
* Check to see whether this is the reattachment of an existing
* physical link. If so, return its linkid.
*/
- if ((class == DATALINK_CLASS_PHYS) &&
- (linkp = dlmgmt_getlink_by_dev(create->ld_devname)) != NULL) {
-
+ if ((class == DATALINK_CLASS_PHYS) && (linkp =
+ dlmgmt_getlink_by_dev(create->ld_devname, zoneid)) != NULL) {
if (linkattr_equal(&(linkp->ll_head), FPHYMAJ,
&create->ld_phymaj, sizeof (uint64_t)) &&
linkattr_equal(&(linkp->ll_head), FPHYINST,
@@ -163,6 +200,8 @@ dlmgmt_upcall_create(void *argp, void *retp)
if ((linkp->ll_flags & DLMGMT_ACTIVE) == 0)
reconfigured = B_TRUE;
+ if ((err = link_activate(linkp)) != 0)
+ goto done;
linkp->ll_flags |= flags;
linkp->ll_gen++;
@@ -170,7 +209,7 @@ dlmgmt_upcall_create(void *argp, void *retp)
}
if ((err = dlmgmt_create_common(create->ld_devname, class, media,
- flags, &linkp)) == EEXIST) {
+ zoneid, flags, &linkp)) == EEXIST) {
/*
* The link name already exists. Return error if this is a
* non-physical link (in that case, the link name must be
@@ -183,11 +222,12 @@ dlmgmt_upcall_create(void *argp, void *retp)
* The physical link's name already exists, request
* a suggested link name: net<nextppa>
*/
- err = dlmgmt_generate_name("net", link, MAXLINKNAMELEN);
+ err = dlmgmt_generate_name("net", link, MAXLINKNAMELEN, zoneid);
if (err != 0)
goto done;
- err = dlmgmt_create_common(link, class, media, flags, &linkp);
+ err = dlmgmt_create_common(link, class, media, zoneid, flags,
+ &linkp);
}
if (err != 0)
@@ -210,7 +250,7 @@ dlmgmt_upcall_create(void *argp, void *retp)
}
done:
- if ((err == 0) && ((err = dlmgmt_write_db_entry(linkp->ll_linkid,
+ if ((err == 0) && ((err = dlmgmt_write_db_entry(linkp->ll_link, linkp,
linkp->ll_flags)) != 0) && created) {
(void) dlmgmt_destroy_common(linkp, flags);
}
@@ -235,7 +275,7 @@ noupdate:
}
static void
-dlmgmt_upcall_update(void *argp, void *retp)
+dlmgmt_upcall_update(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_upcall_arg_update_t *update = argp;
dlmgmt_update_retval_t *retvalp = retp;
@@ -252,11 +292,15 @@ dlmgmt_upcall_update(void *argp, void *retp)
* Check to see whether this is the reattachment of an existing
* physical link. If so, return its linkid.
*/
- if ((linkp = dlmgmt_getlink_by_dev(update->ld_devname)) == NULL) {
+ if ((linkp = dlmgmt_getlink_by_dev(update->ld_devname, zoneid)) ==
+ NULL) {
err = ENOENT;
goto done;
}
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
+ goto done;
+
retvalp->lr_linkid = linkp->ll_linkid;
retvalp->lr_media = media;
if (linkp->ll_media != media && linkp->ll_media != DL_OTHER) {
@@ -295,7 +339,8 @@ dlmgmt_upcall_update(void *argp, void *retp)
if (linkp->ll_media != media) {
linkp->ll_media = media;
linkp->ll_gen++;
- (void) dlmgmt_write_db_entry(linkp->ll_linkid, linkp->ll_flags);
+ (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
+ linkp->ll_flags);
}
done:
@@ -304,7 +349,7 @@ done:
}
static void
-dlmgmt_upcall_destroy(void *argp, void *retp)
+dlmgmt_upcall_destroy(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_upcall_arg_destroy_t *destroy = argp;
dlmgmt_destroy_retval_t *retvalp = retp;
@@ -320,21 +365,22 @@ dlmgmt_upcall_destroy(void *argp, void *retp)
*/
dlmgmt_table_lock(B_TRUE);
- if ((linkp = link_by_id(linkid)) == NULL) {
+ if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
err = ENOENT;
goto done;
}
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
+ goto done;
+
if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) != 0) {
- err = dlmgmt_delete_db_entry(linkid, DLMGMT_ACTIVE);
- if (err != 0)
+ if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE)) != 0)
goto done;
dflags |= DLMGMT_ACTIVE;
}
if (((linkp->ll_flags & flags) & DLMGMT_PERSIST) != 0) {
- err = dlmgmt_delete_db_entry(linkid, DLMGMT_PERSIST);
- if (err != 0)
+ if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST)) != 0)
goto done;
dflags |= DLMGMT_PERSIST;
}
@@ -342,14 +388,15 @@ dlmgmt_upcall_destroy(void *argp, void *retp)
err = dlmgmt_destroy_common(linkp, flags);
done:
if (err != 0 && dflags != 0)
- (void) dlmgmt_write_db_entry(linkp->ll_linkid, dflags);
+ (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, dflags);
dlmgmt_table_unlock();
retvalp->lr_err = err;
}
+/* ARGSUSED */
static void
-dlmgmt_getname(void *argp, void *retp)
+dlmgmt_getname(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_getname_t *getname = argp;
dlmgmt_getname_retval_t *retvalp = retp;
@@ -360,30 +407,24 @@ dlmgmt_getname(void *argp, void *retp)
* Hold the reader lock to access the link
*/
dlmgmt_table_lock(B_FALSE);
- if ((linkp = link_by_id(getname->ld_linkid)) == NULL) {
- /*
- * The link does not exists.
- */
+ if ((linkp = link_by_id(getname->ld_linkid, zoneid)) == NULL) {
err = ENOENT;
- goto done;
- }
-
- if (strlcpy(retvalp->lr_link, linkp->ll_link, MAXLINKNAMELEN) >=
+ } else if (strlcpy(retvalp->lr_link, linkp->ll_link, MAXLINKNAMELEN) >=
MAXLINKNAMELEN) {
err = ENOSPC;
- goto done;
+ } else {
+ retvalp->lr_flags = linkp->ll_flags;
+ retvalp->lr_class = linkp->ll_class;
+ retvalp->lr_media = linkp->ll_media;
}
- retvalp->lr_flags = linkp->ll_flags;
- retvalp->lr_class = linkp->ll_class;
- retvalp->lr_media = linkp->ll_media;
-done:
dlmgmt_table_unlock();
retvalp->lr_err = err;
}
+/* ARGSUSED */
static void
-dlmgmt_getlinkid(void *argp, void *retp)
+dlmgmt_getlinkid(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_getlinkid_t *getlinkid = argp;
dlmgmt_getlinkid_retval_t *retvalp = retp;
@@ -394,9 +435,10 @@ dlmgmt_getlinkid(void *argp, void *retp)
* Hold the reader lock to access the link
*/
dlmgmt_table_lock(B_FALSE);
- if ((linkp = link_by_name(getlinkid->ld_link)) == NULL) {
+
+ if ((linkp = link_by_name(getlinkid->ld_link, zoneid)) == NULL) {
/*
- * The link does not exists.
+ * The link does not exist in this zone.
*/
err = ENOENT;
goto done;
@@ -412,13 +454,13 @@ done:
retvalp->lr_err = err;
}
+/* ARGSUSED */
static void
-dlmgmt_getnext(void *argp, void *retp)
+dlmgmt_getnext(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_getnext_t *getnext = argp;
dlmgmt_getnext_retval_t *retvalp = retp;
dlmgmt_link_t link, *linkp;
- datalink_id_t linkid = getnext->ld_linkid;
avl_index_t where;
int err = 0;
@@ -427,12 +469,13 @@ dlmgmt_getnext(void *argp, void *retp)
*/
dlmgmt_table_lock(B_FALSE);
- link.ll_linkid = (linkid + 1);
- linkp = avl_find(&dlmgmt_id_avl, &link, &where);
- if (linkp == NULL)
+ link.ll_linkid = (getnext->ld_linkid + 1);
+ if ((linkp = avl_find(&dlmgmt_id_avl, &link, &where)) == NULL)
linkp = avl_nearest(&dlmgmt_id_avl, where, AVL_AFTER);
for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
+ if (!link_is_visible(linkp, zoneid))
+ continue;
if ((linkp->ll_class & getnext->ld_class) &&
(linkp->ll_flags & getnext->ld_flags) &&
DATALINK_MEDIA_ACCEPTED(getnext->ld_dmedia,
@@ -453,8 +496,9 @@ dlmgmt_getnext(void *argp, void *retp)
retvalp->lr_err = err;
}
+/* ARGSUSED */
static void
-dlmgmt_upcall_getattr(void *argp, void *retp)
+dlmgmt_upcall_getattr(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_upcall_arg_getattr_t *getattr = argp;
dlmgmt_getattr_retval_t *retvalp = retp;
@@ -464,22 +508,17 @@ dlmgmt_upcall_getattr(void *argp, void *retp)
* Hold the reader lock to access the link
*/
dlmgmt_table_lock(B_FALSE);
- if ((linkp = link_by_id(getattr->ld_linkid)) == NULL) {
- /*
- * The link does not exist.
- */
+ if ((linkp = link_by_id(getattr->ld_linkid, zoneid)) == NULL) {
retvalp->lr_err = ENOENT;
- goto done;
+ } else {
+ retvalp->lr_err = dlmgmt_getattr_common(&linkp->ll_head,
+ getattr->ld_attr, retvalp);
}
-
- dlmgmt_getattr_common(&linkp->ll_head, getattr->ld_attr, retvalp);
-
-done:
dlmgmt_table_unlock();
}
static void
-dlmgmt_createid(void *argp, void *retp)
+dlmgmt_createid(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_createid_t *createid = argp;
dlmgmt_createid_retval_t *retvalp = retp;
@@ -493,18 +532,21 @@ dlmgmt_createid(void *argp, void *retp)
*/
dlmgmt_table_lock(B_TRUE);
+ if ((err = dlmgmt_checkprivs(createid->ld_class, cred)) != 0)
+ goto done;
+
if (createid->ld_prefix) {
err = dlmgmt_generate_name(createid->ld_link, link,
- MAXLINKNAMELEN);
+ MAXLINKNAMELEN, zoneid);
if (err != 0)
goto done;
err = dlmgmt_create_common(link, createid->ld_class,
- createid->ld_media, createid->ld_flags, &linkp);
+ createid->ld_media, zoneid, createid->ld_flags, &linkp);
} else {
err = dlmgmt_create_common(createid->ld_link,
- createid->ld_class, createid->ld_media, createid->ld_flags,
- &linkp);
+ createid->ld_class, createid->ld_media, zoneid,
+ createid->ld_flags, &linkp);
}
if (err == 0) {
@@ -512,8 +554,10 @@ dlmgmt_createid(void *argp, void *retp)
* Keep the active mapping.
*/
linkid = linkp->ll_linkid;
- if (createid->ld_flags & DLMGMT_ACTIVE)
- (void) dlmgmt_write_db_entry(linkid, DLMGMT_ACTIVE);
+ if (createid->ld_flags & DLMGMT_ACTIVE) {
+ (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
+ DLMGMT_ACTIVE);
+ }
}
done:
@@ -523,7 +567,7 @@ done:
}
static void
-dlmgmt_destroyid(void *argp, void *retp)
+dlmgmt_destroyid(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_destroyid_t *destroyid = argp;
dlmgmt_destroyid_retval_t *retvalp = retp;
@@ -536,20 +580,21 @@ dlmgmt_destroyid(void *argp, void *retp)
* Hold the writer lock to update the link table.
*/
dlmgmt_table_lock(B_TRUE);
- if ((linkp = link_by_id(linkid)) == NULL) {
+ if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
err = ENOENT;
goto done;
}
- if ((err = dlmgmt_destroy_common(linkp, flags)) != 0)
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
goto done;
/*
* Delete the active mapping.
*/
if (flags & DLMGMT_ACTIVE)
- (void) dlmgmt_delete_db_entry(linkid, DLMGMT_ACTIVE);
-
+ err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE);
+ if (err == 0)
+ err = dlmgmt_destroy_common(linkp, flags);
done:
dlmgmt_table_unlock();
retvalp->lr_err = err;
@@ -561,13 +606,13 @@ done:
* the given link name.
*/
static void
-dlmgmt_remapid(void *argp, void *retp)
+dlmgmt_remapid(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_remapid_t *remapid = argp;
dlmgmt_remapid_retval_t *retvalp = retp;
- datalink_id_t linkid1 = remapid->ld_linkid;
- dlmgmt_link_t link, *linkp1, *tmp;
- avl_index_t where;
+ dlmgmt_link_t *linkp;
+ char oldname[MAXLINKNAMELEN];
+ boolean_t renamed = B_FALSE;
int err = 0;
if (!dladm_valid_linkname(remapid->ld_link)) {
@@ -579,36 +624,55 @@ dlmgmt_remapid(void *argp, void *retp)
* Hold the writer lock to update the link table.
*/
dlmgmt_table_lock(B_TRUE);
- if ((linkp1 = link_by_id(linkid1)) == NULL) {
+ if ((linkp = link_by_id(remapid->ld_linkid, zoneid)) == NULL) {
err = ENOENT;
goto done;
}
- if (link_by_name(remapid->ld_link) != NULL) {
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
+ goto done;
+
+ if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
err = EEXIST;
goto done;
}
- avl_remove(&dlmgmt_name_avl, linkp1);
- (void) strlcpy(link.ll_link, remapid->ld_link, MAXLINKNAMELEN);
- tmp = avl_find(&dlmgmt_name_avl, &link, &where);
- assert(tmp == NULL);
- (void) strlcpy(linkp1->ll_link, remapid->ld_link, MAXLINKNAMELEN);
- avl_insert(&dlmgmt_name_avl, linkp1, where);
- dlmgmt_advance(linkp1);
+ (void) strlcpy(oldname, linkp->ll_link, MAXLINKNAMELEN);
+ avl_remove(&dlmgmt_name_avl, linkp);
+ (void) strlcpy(linkp->ll_link, remapid->ld_link, MAXLINKNAMELEN);
+ avl_add(&dlmgmt_name_avl, linkp);
+ renamed = B_TRUE;
- /*
- * If we renamed a temporary link, update the temporary repository.
- */
- if (linkp1->ll_flags & DLMGMT_ACTIVE)
- (void) dlmgmt_write_db_entry(linkid1, DLMGMT_ACTIVE);
+ if (linkp->ll_flags & DLMGMT_ACTIVE) {
+ err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_ACTIVE);
+ if (err != 0)
+ goto done;
+ }
+ if (linkp->ll_flags & DLMGMT_PERSIST) {
+ err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_PERSIST);
+ if (err != 0) {
+ if (linkp->ll_flags & DLMGMT_ACTIVE) {
+ (void) dlmgmt_write_db_entry(remapid->ld_link,
+ linkp, DLMGMT_ACTIVE);
+ }
+ goto done;
+ }
+ }
+
+ dlmgmt_advance(linkp);
+ linkp->ll_gen++;
done:
+ if (err != 0 && renamed) {
+ avl_remove(&dlmgmt_name_avl, linkp);
+ (void) strlcpy(linkp->ll_link, oldname, MAXLINKNAMELEN);
+ avl_add(&dlmgmt_name_avl, linkp);
+ }
dlmgmt_table_unlock();
retvalp->lr_err = err;
}
static void
-dlmgmt_upid(void *argp, void *retp)
+dlmgmt_upid(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_upid_t *upid = argp;
dlmgmt_upid_retval_t *retvalp = retp;
@@ -619,30 +683,34 @@ dlmgmt_upid(void *argp, void *retp)
* Hold the writer lock to update the link table.
*/
dlmgmt_table_lock(B_TRUE);
- if ((linkp = link_by_id(upid->ld_linkid)) == NULL) {
+ if ((linkp = link_by_id(upid->ld_linkid, zoneid)) == NULL) {
err = ENOENT;
goto done;
}
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
+ goto done;
+
if (linkp->ll_flags & DLMGMT_ACTIVE) {
err = EINVAL;
goto done;
}
- linkp->ll_flags |= DLMGMT_ACTIVE;
- (void) dlmgmt_write_db_entry(linkp->ll_linkid, DLMGMT_ACTIVE);
+ if ((err = link_activate(linkp)) == 0) {
+ (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
+ DLMGMT_ACTIVE);
+ }
done:
dlmgmt_table_unlock();
retvalp->lr_err = err;
}
static void
-dlmgmt_createconf(void *argp, void *retp)
+dlmgmt_createconf(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_createconf_t *createconf = argp;
dlmgmt_createconf_retval_t *retvalp = retp;
- dlmgmt_dlconf_t dlconf, *dlconfp, *tmp;
- avl_index_t where;
+ dlmgmt_dlconf_t *dlconfp;
int err;
/*
@@ -650,25 +718,23 @@ dlmgmt_createconf(void *argp, void *retp)
*/
dlmgmt_dlconf_table_lock(B_TRUE);
- if ((err = dlconf_create(createconf->ld_link, createconf->ld_linkid,
- createconf->ld_class, createconf->ld_media, &dlconfp)) != 0) {
+ if ((err = dlmgmt_checkprivs(createconf->ld_class, cred)) != 0)
goto done;
- }
-
- dlconf.ld_id = dlconfp->ld_id;
- tmp = avl_find(&dlmgmt_dlconf_avl, &dlconf, &where);
- assert(tmp == NULL);
- avl_insert(&dlmgmt_dlconf_avl, dlconfp, where);
- dlmgmt_advance_dlconfid(dlconfp);
- retvalp->lr_conf = (dladm_conf_t)dlconfp->ld_id;
+ err = dlconf_create(createconf->ld_link, createconf->ld_linkid,
+ createconf->ld_class, createconf->ld_media, zoneid, &dlconfp);
+ if (err == 0) {
+ avl_add(&dlmgmt_dlconf_avl, dlconfp);
+ dlmgmt_advance_dlconfid(dlconfp);
+ retvalp->lr_conf = (dladm_conf_t)dlconfp->ld_id;
+ }
done:
dlmgmt_dlconf_table_unlock();
retvalp->lr_err = err;
}
static void
-dlmgmt_setattr(void *argp, void *retp)
+dlmgmt_setattr(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_setattr_t *setattr = argp;
dlmgmt_setattr_retval_t *retvalp = retp;
@@ -682,11 +748,14 @@ dlmgmt_setattr(void *argp, void *retp)
dlconf.ld_id = (int)setattr->ld_conf;
dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
- if (dlconfp == NULL) {
+ if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
err = ENOENT;
goto done;
}
+ if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
+ goto done;
+
err = linkattr_set(&(dlconfp->ld_head), setattr->ld_attr,
&setattr->ld_attrval, setattr->ld_attrsz, setattr->ld_type);
@@ -696,7 +765,7 @@ done:
}
static void
-dlmgmt_unsetconfattr(void *argp, void *retp)
+dlmgmt_unsetconfattr(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_unsetattr_t *unsetattr = argp;
dlmgmt_unsetattr_retval_t *retvalp = retp;
@@ -710,12 +779,15 @@ dlmgmt_unsetconfattr(void *argp, void *retp)
dlconf.ld_id = (int)unsetattr->ld_conf;
dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
- if (dlconfp == NULL) {
+ if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
err = ENOENT;
goto done;
}
- err = linkattr_unset(&(dlconfp->ld_head), unsetattr->ld_attr);
+ if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
+ goto done;
+
+ linkattr_unset(&(dlconfp->ld_head), unsetattr->ld_attr);
done:
dlmgmt_dlconf_table_unlock();
@@ -735,7 +807,7 @@ done:
* across the pair of dladm_read_conf() and dladm_write_conf() calls.
*/
static void
-dlmgmt_writeconf(void *argp, void *retp)
+dlmgmt_writeconf(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_writeconf_t *writeconf = argp;
dlmgmt_writeconf_retval_t *retvalp = retp;
@@ -751,16 +823,19 @@ dlmgmt_writeconf(void *argp, void *retp)
dlconf.ld_id = (int)writeconf->ld_conf;
dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
- if (dlconfp == NULL) {
+ if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
err = ENOENT;
goto done;
}
+ if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
+ goto done;
+
/*
* Hold the writer lock to update the link table.
*/
dlmgmt_table_lock(B_TRUE);
- linkp = link_by_id(dlconfp->ld_linkid);
+ linkp = link_by_id(dlconfp->ld_linkid, zoneid);
if ((linkp == NULL) || (linkp->ll_class != dlconfp->ld_class) ||
(linkp->ll_media != dlconfp->ld_media) ||
(strcmp(linkp->ll_link, dlconfp->ld_link) != 0)) {
@@ -803,7 +878,7 @@ dlmgmt_writeconf(void *argp, void *retp)
}
linkp->ll_gen++;
- err = dlmgmt_write_db_entry(linkp->ll_linkid, DLMGMT_PERSIST);
+ err = dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_PERSIST);
dlmgmt_table_unlock();
done:
dlmgmt_dlconf_table_unlock();
@@ -811,20 +886,38 @@ done:
}
static void
-dlmgmt_removeconf(void *argp, void *retp)
+dlmgmt_removeconf(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_removeconf_t *removeconf = argp;
dlmgmt_removeconf_retval_t *retvalp = retp;
+ dlmgmt_link_t *linkp;
int err;
dlmgmt_table_lock(B_TRUE);
- err = dlmgmt_delete_db_entry(removeconf->ld_linkid, DLMGMT_PERSIST);
+ if ((linkp = link_by_id(removeconf->ld_linkid, zoneid)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+ if (zoneid != GLOBAL_ZONEID && linkp->ll_onloan) {
+ /*
+ * A non-global zone cannot remove the persistent
+ * configuration of a link that is on loan from the global
+ * zone.
+ */
+ err = EACCES;
+ goto done;
+ }
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
+ goto done;
+
+ err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST);
+done:
dlmgmt_table_unlock();
retvalp->lr_err = err;
}
static void
-dlmgmt_destroyconf(void *argp, void *retp)
+dlmgmt_destroyconf(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_destroyconf_t *destroyconf = argp;
dlmgmt_destroyconf_retval_t *retvalp = retp;
@@ -838,11 +931,14 @@ dlmgmt_destroyconf(void *argp, void *retp)
dlconf.ld_id = (int)destroyconf->ld_conf;
dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
- if (dlconfp == NULL) {
+ if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
err = ENOENT;
goto done;
}
+ if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
+ goto done;
+
avl_remove(&dlmgmt_dlconf_avl, dlconfp);
dlconf_destroy(dlconfp);
@@ -855,16 +951,16 @@ done:
* See the comments above dladm_write_conf() to see how ld_gen is used to
* ensure atomicity across the {dlmgmt_readconf(), dlmgmt_writeconf()} pair.
*/
+/* ARGSUSED */
static void
-dlmgmt_readconf(void *argp, void *retp)
+dlmgmt_readconf(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_readconf_t *readconf = argp;
dlmgmt_readconf_retval_t *retvalp = retp;
dlmgmt_link_t *linkp;
datalink_id_t linkid = readconf->ld_linkid;
- dlmgmt_dlconf_t *dlconfp, *tmp, dlconf;
+ dlmgmt_dlconf_t *dlconfp;
dlmgmt_linkattr_t *attrp;
- avl_index_t where;
int err = 0;
/*
@@ -876,19 +972,24 @@ dlmgmt_readconf(void *argp, void *retp)
* Hold the reader lock to access the link
*/
dlmgmt_table_lock(B_FALSE);
- linkp = link_by_id(linkid);
+ linkp = link_by_id(linkid, zoneid);
if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) {
+ /* The persistent link configuration does not exist. */
+ err = ENOENT;
+ goto done;
+ }
+ if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) {
/*
- * The persistent link configuration does not exists.
+ * The caller is in a non-global zone and the persistent
+ * configuration belongs to the global zone.
*/
- err = ENOENT;
+ err = EACCES;
goto done;
}
if ((err = dlconf_create(linkp->ll_link, linkp->ll_linkid,
- linkp->ll_class, linkp->ll_media, &dlconfp)) != 0) {
+ linkp->ll_class, linkp->ll_media, zoneid, &dlconfp)) != 0)
goto done;
- }
for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) {
if ((err = linkattr_set(&(dlconfp->ld_head), attrp->lp_name,
@@ -898,11 +999,7 @@ dlmgmt_readconf(void *argp, void *retp)
}
}
dlconfp->ld_gen = linkp->ll_gen;
-
- dlconf.ld_id = dlconfp->ld_id;
- tmp = avl_find(&dlmgmt_dlconf_avl, &dlconf, &where);
- assert(tmp == NULL);
- avl_insert(&dlmgmt_dlconf_avl, dlconfp, where);
+ avl_add(&dlmgmt_dlconf_avl, dlconfp);
dlmgmt_advance_dlconfid(dlconfp);
retvalp->lr_conf = (dladm_conf_t)dlconfp->ld_id;
@@ -915,8 +1012,9 @@ done:
/*
* Note: the caller must free *retvalpp in case of success.
*/
+/* ARGSUSED */
static void
-dlmgmt_getattr(void *argp, void *retp)
+dlmgmt_getattr(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_getattr_t *getattr = argp;
dlmgmt_getattr_retval_t *retvalp = retp;
@@ -928,49 +1026,45 @@ dlmgmt_getattr(void *argp, void *retp)
dlmgmt_dlconf_table_lock(B_FALSE);
dlconf.ld_id = (int)getattr->ld_conf;
- dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
- if (dlconfp == NULL) {
+ if ((dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL)) == NULL ||
+ zoneid != dlconfp->ld_zoneid) {
retvalp->lr_err = ENOENT;
- goto done;
+ } else {
+ retvalp->lr_err = dlmgmt_getattr_common(&dlconfp->ld_head,
+ getattr->ld_attr, retvalp);
}
- dlmgmt_getattr_common(&dlconfp->ld_head, getattr->ld_attr, retvalp);
-
-done:
dlmgmt_dlconf_table_unlock();
}
static void
-dlmgmt_upcall_linkprop_init(void *argp, void *retp)
+dlmgmt_upcall_linkprop_init(void *argp, void *retp, zoneid_t zoneid,
+ ucred_t *cred)
{
dlmgmt_door_linkprop_init_t *lip = argp;
dlmgmt_linkprop_init_retval_t *retvalp = retp;
- boolean_t do_linkprop = B_FALSE;
+ dlmgmt_link_t *linkp;
+ int err;
- /*
- * Ignore wifi links until wifi property ioctls are converted
- * to generic property ioctls. This avoids deadlocks due to
- * wifi property ioctls using their own /dev/net device,
- * not the DLD control device.
- */
dlmgmt_table_lock(B_FALSE);
- if (link_by_id(lip->ld_linkid) == NULL)
- retvalp->lr_err = ENOENT;
+ if ((linkp = link_by_id(lip->ld_linkid, zoneid)) == NULL)
+ err = ENOENT;
else
- do_linkprop = B_TRUE;
+ err = dlmgmt_checkprivs(linkp->ll_class, cred);
dlmgmt_table_unlock();
- if (do_linkprop)
- retvalp->lr_err = dladm_init_linkprop(dld_handle,
- lip->ld_linkid, B_TRUE);
+ if (err == 0)
+ err = dladm_init_linkprop(dld_handle, lip->ld_linkid, B_TRUE);
+ retvalp->lr_err = err;
}
/*
* Get the link property that follows ld_last_attr.
* If ld_last_attr is empty, return the first property.
*/
+/* ARGSUSED */
static void
-dlmgmt_linkprop_getnext(void *argp, void *retp)
+dlmgmt_linkprop_getnext(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
{
dlmgmt_door_linkprop_getnext_t *getnext = argp;
dlmgmt_linkprop_getnext_retval_t *retvalp = retp;
@@ -1013,100 +1107,225 @@ done:
retvalp->lr_err = err;
}
+static void
+dlmgmt_setzoneid(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
+{
+ dlmgmt_door_setzoneid_t *setzoneid = argp;
+ dlmgmt_setzoneid_retval_t *retvalp = retp;
+ dlmgmt_link_t *linkp;
+ datalink_id_t linkid = setzoneid->ld_linkid;
+ zoneid_t oldzoneid, newzoneid;
+ int err = 0;
+
+ dlmgmt_table_lock(B_TRUE);
+
+ /* We currently only allow changing zoneid's from the global zone. */
+ if (zoneid != GLOBAL_ZONEID) {
+ err = EACCES;
+ goto done;
+ }
+
+ if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
+ goto done;
+
+ /* We can only assign an active link to a zone. */
+ if (!(linkp->ll_flags & DLMGMT_ACTIVE)) {
+ err = EINVAL;
+ goto done;
+ }
+
+ oldzoneid = linkp->ll_zoneid;
+ newzoneid = setzoneid->ld_zoneid;
+
+ if (oldzoneid == newzoneid)
+ goto done;
+
+ /*
+ * Before we remove the link from its current zone, make sure that
+ * there isn't a link with the same name in the destination zone.
+ */
+ if (zoneid != GLOBAL_ZONEID &&
+ link_by_name(linkp->ll_link, newzoneid) != NULL) {
+ err = EEXIST;
+ goto done;
+ }
+
+ if (oldzoneid != GLOBAL_ZONEID) {
+ if (zone_remove_datalink(oldzoneid, linkid) != 0) {
+ err = errno;
+ dlmgmt_log(LOG_WARNING, "unable to remove link %d from "
+ "zone %d: %s", linkid, oldzoneid, strerror(err));
+ goto done;
+ }
+ avl_remove(&dlmgmt_loan_avl, linkp);
+ linkp->ll_onloan = B_FALSE;
+ }
+ if (newzoneid != GLOBAL_ZONEID) {
+ if (zone_add_datalink(newzoneid, linkid) != 0) {
+ err = errno;
+ dlmgmt_log(LOG_WARNING, "unable to add link %d to zone "
+ "%d: %s", linkid, newzoneid, strerror(err));
+ (void) zone_add_datalink(oldzoneid, linkid);
+ goto done;
+ }
+ avl_add(&dlmgmt_loan_avl, linkp);
+ linkp->ll_onloan = B_TRUE;
+ }
+
+ avl_remove(&dlmgmt_name_avl, linkp);
+ linkp->ll_zoneid = newzoneid;
+ avl_add(&dlmgmt_name_avl, linkp);
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_zoneboot(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
+{
+ int err;
+ dlmgmt_door_zoneboot_t *zoneboot = argp;
+ dlmgmt_zoneboot_retval_t *retvalp = retp;
+
+ dlmgmt_table_lock(B_TRUE);
+
+ if ((err = dlmgmt_checkprivs(0, cred)) != 0)
+ goto done;
+
+ if (zoneid != GLOBAL_ZONEID) {
+ err = EACCES;
+ goto done;
+ }
+ if (zoneboot->ld_zoneid == GLOBAL_ZONEID) {
+ err = EINVAL;
+ goto done;
+ }
+
+ if ((err = dlmgmt_elevate_privileges()) == 0) {
+ err = dlmgmt_zone_init(zoneboot->ld_zoneid);
+ (void) dlmgmt_drop_privileges();
+ }
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_zonehalt(void *argp, void *retp, zoneid_t zoneid, ucred_t *cred)
+{
+ int err = 0;
+ dlmgmt_door_zonehalt_t *zonehalt = argp;
+ dlmgmt_zonehalt_retval_t *retvalp = retp;
+
+ if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
+ if (zoneid != GLOBAL_ZONEID) {
+ err = EACCES;
+ } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
+ err = EINVAL;
+ } else {
+ dlmgmt_table_lock(B_TRUE);
+ dlmgmt_db_fini(zonehalt->ld_zoneid);
+ dlmgmt_table_unlock();
+ }
+ }
+ retvalp->lr_err = err;
+}
+
static dlmgmt_door_info_t i_dlmgmt_door_info_tbl[] = {
- { DLMGMT_CMD_DLS_CREATE, B_TRUE, sizeof (dlmgmt_upcall_arg_create_t),
+ { DLMGMT_CMD_DLS_CREATE, sizeof (dlmgmt_upcall_arg_create_t),
sizeof (dlmgmt_create_retval_t), dlmgmt_upcall_create },
- { DLMGMT_CMD_DLS_GETATTR, B_FALSE, sizeof (dlmgmt_upcall_arg_getattr_t),
+ { DLMGMT_CMD_DLS_GETATTR, sizeof (dlmgmt_upcall_arg_getattr_t),
sizeof (dlmgmt_getattr_retval_t), dlmgmt_upcall_getattr },
- { DLMGMT_CMD_DLS_DESTROY, B_TRUE, sizeof (dlmgmt_upcall_arg_destroy_t),
+ { DLMGMT_CMD_DLS_DESTROY, sizeof (dlmgmt_upcall_arg_destroy_t),
sizeof (dlmgmt_destroy_retval_t), dlmgmt_upcall_destroy },
- { DLMGMT_CMD_GETNAME, B_FALSE, sizeof (dlmgmt_door_getname_t),
+ { DLMGMT_CMD_GETNAME, sizeof (dlmgmt_door_getname_t),
sizeof (dlmgmt_getname_retval_t), dlmgmt_getname },
- { DLMGMT_CMD_GETLINKID, B_FALSE, sizeof (dlmgmt_door_getlinkid_t),
+ { DLMGMT_CMD_GETLINKID, sizeof (dlmgmt_door_getlinkid_t),
sizeof (dlmgmt_getlinkid_retval_t), dlmgmt_getlinkid },
- { DLMGMT_CMD_GETNEXT, B_FALSE, sizeof (dlmgmt_door_getnext_t),
+ { DLMGMT_CMD_GETNEXT, sizeof (dlmgmt_door_getnext_t),
sizeof (dlmgmt_getnext_retval_t), dlmgmt_getnext },
- { DLMGMT_CMD_DLS_UPDATE, B_TRUE, sizeof (dlmgmt_upcall_arg_update_t),
+ { DLMGMT_CMD_DLS_UPDATE, sizeof (dlmgmt_upcall_arg_update_t),
sizeof (dlmgmt_update_retval_t), dlmgmt_upcall_update },
- { DLMGMT_CMD_CREATE_LINKID, B_TRUE, sizeof (dlmgmt_door_createid_t),
+ { DLMGMT_CMD_CREATE_LINKID, sizeof (dlmgmt_door_createid_t),
sizeof (dlmgmt_createid_retval_t), dlmgmt_createid },
- { DLMGMT_CMD_DESTROY_LINKID, B_TRUE, sizeof (dlmgmt_door_destroyid_t),
+ { DLMGMT_CMD_DESTROY_LINKID, sizeof (dlmgmt_door_destroyid_t),
sizeof (dlmgmt_destroyid_retval_t), dlmgmt_destroyid },
- { DLMGMT_CMD_REMAP_LINKID, B_TRUE, sizeof (dlmgmt_door_remapid_t),
+ { DLMGMT_CMD_REMAP_LINKID, sizeof (dlmgmt_door_remapid_t),
sizeof (dlmgmt_remapid_retval_t), dlmgmt_remapid },
- { DLMGMT_CMD_CREATECONF, B_TRUE, sizeof (dlmgmt_door_createconf_t),
+ { DLMGMT_CMD_CREATECONF, sizeof (dlmgmt_door_createconf_t),
sizeof (dlmgmt_createconf_retval_t), dlmgmt_createconf },
- { DLMGMT_CMD_READCONF, B_FALSE, sizeof (dlmgmt_door_readconf_t),
+ { DLMGMT_CMD_READCONF, sizeof (dlmgmt_door_readconf_t),
sizeof (dlmgmt_readconf_retval_t), dlmgmt_readconf },
- { DLMGMT_CMD_WRITECONF, B_TRUE, sizeof (dlmgmt_door_writeconf_t),
+ { DLMGMT_CMD_WRITECONF, sizeof (dlmgmt_door_writeconf_t),
sizeof (dlmgmt_writeconf_retval_t), dlmgmt_writeconf },
- { DLMGMT_CMD_UP_LINKID, B_TRUE, sizeof (dlmgmt_door_upid_t),
+ { DLMGMT_CMD_UP_LINKID, sizeof (dlmgmt_door_upid_t),
sizeof (dlmgmt_upid_retval_t), dlmgmt_upid },
- { DLMGMT_CMD_SETATTR, B_TRUE, sizeof (dlmgmt_door_setattr_t),
+ { DLMGMT_CMD_SETATTR, sizeof (dlmgmt_door_setattr_t),
sizeof (dlmgmt_setattr_retval_t), dlmgmt_setattr },
- { DLMGMT_CMD_UNSETATTR, B_TRUE, sizeof (dlmgmt_door_unsetattr_t),
+ { DLMGMT_CMD_UNSETATTR, sizeof (dlmgmt_door_unsetattr_t),
sizeof (dlmgmt_unsetattr_retval_t), dlmgmt_unsetconfattr },
- { DLMGMT_CMD_REMOVECONF, B_TRUE, sizeof (dlmgmt_door_removeconf_t),
+ { DLMGMT_CMD_REMOVECONF, sizeof (dlmgmt_door_removeconf_t),
sizeof (dlmgmt_removeconf_retval_t), dlmgmt_removeconf },
- { DLMGMT_CMD_DESTROYCONF, B_TRUE, sizeof (dlmgmt_door_destroyconf_t),
+ { DLMGMT_CMD_DESTROYCONF, sizeof (dlmgmt_door_destroyconf_t),
sizeof (dlmgmt_destroyconf_retval_t), dlmgmt_destroyconf },
- { DLMGMT_CMD_GETATTR, B_FALSE, sizeof (dlmgmt_door_getattr_t),
+ { DLMGMT_CMD_GETATTR, sizeof (dlmgmt_door_getattr_t),
sizeof (dlmgmt_getattr_retval_t), dlmgmt_getattr },
- { DLMGMT_CMD_LINKPROP_INIT, B_TRUE,
- sizeof (dlmgmt_door_linkprop_init_t),
+ { DLMGMT_CMD_LINKPROP_INIT, sizeof (dlmgmt_door_linkprop_init_t),
sizeof (dlmgmt_linkprop_init_retval_t),
dlmgmt_upcall_linkprop_init },
- { DLMGMT_CMD_LINKPROP_GETNEXT, B_FALSE,
- sizeof (dlmgmt_door_linkprop_getnext_t),
+ { DLMGMT_CMD_LINKPROP_GETNEXT, sizeof (dlmgmt_door_linkprop_getnext_t),
sizeof (dlmgmt_linkprop_getnext_retval_t),
- dlmgmt_linkprop_getnext }
+ dlmgmt_linkprop_getnext },
+ { DLMGMT_CMD_SETZONEID, sizeof (dlmgmt_door_setzoneid_t),
+ sizeof (dlmgmt_setzoneid_retval_t), dlmgmt_setzoneid },
+ { DLMGMT_CMD_ZONEBOOT, sizeof (dlmgmt_door_zoneboot_t),
+ sizeof (dlmgmt_zoneboot_retval_t), dlmgmt_zoneboot },
+ { DLMGMT_CMD_ZONEHALT, sizeof (dlmgmt_door_zonehalt_t),
+ sizeof (dlmgmt_zonehalt_retval_t), dlmgmt_zonehalt },
+ { 0, 0, 0, NULL }
};
-#define DLMGMT_INFO_TABLE_SIZE (sizeof (i_dlmgmt_door_info_tbl) / \
- sizeof (i_dlmgmt_door_info_tbl[0]))
+static dlmgmt_door_info_t *
+dlmgmt_getcmdinfo(int cmd)
+{
+ dlmgmt_door_info_t *infop = i_dlmgmt_door_info_tbl;
+
+ while (infop->di_handler != NULL) {
+ if (infop->di_cmd == cmd)
+ break;
+ infop++;
+ }
+ return (infop);
+}
/* ARGSUSED */
void
dlmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
uint_t n_desc)
{
+ dlmgmt_door_arg_t *door_arg = (dlmgmt_door_arg_t *)(void *)argp;
dlmgmt_door_info_t *infop = NULL;
dlmgmt_retval_t retval;
+ ucred_t *cred = NULL;
+ zoneid_t zoneid;
void *retvalp;
int err = 0;
- int i;
-
- for (i = 0; i < DLMGMT_INFO_TABLE_SIZE; i++) {
- if (i_dlmgmt_door_info_tbl[i].di_cmd ==
- ((dlmgmt_door_arg_t *)(void *)argp)->ld_cmd) {
- infop = i_dlmgmt_door_info_tbl + i;
- break;
- }
- }
+ infop = dlmgmt_getcmdinfo(door_arg->ld_cmd);
if (infop == NULL || argsz != infop->di_reqsz) {
err = EINVAL;
- goto fail;
+ goto done;
}
- if (infop->di_set) {
- ucred_t *cred = NULL;
- const priv_set_t *eset;
-
- if (door_ucred(&cred) != 0) {
- err = errno;
- goto fail;
- }
-
- eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
- if ((eset == NULL) ||
- (!priv_ismember(eset, PRIV_SYS_DL_CONFIG) &&
- !priv_ismember(eset, PRIV_SYS_NET_CONFIG))) {
- err = EACCES;
- }
- ucred_free(cred);
- if (err != 0)
- goto fail;
+ if (door_ucred(&cred) != 0 || (zoneid = ucred_getzoneid(cred)) == -1) {
+ err = errno;
+ goto done;
}
/*
@@ -1114,11 +1333,15 @@ dlmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
* memory allocated by malloc() would get leaked. Use alloca() instead.
*/
retvalp = alloca(infop->di_acksz);
- infop->di_handler(argp, retvalp);
- (void) door_return(retvalp, infop->di_acksz, NULL, 0);
- return;
+ infop->di_handler(argp, retvalp, zoneid, cred);
-fail:
- retval.lr_err = err;
- (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+done:
+ if (cred != NULL)
+ ucred_free(cred);
+ if (err == 0) {
+ (void) door_return(retvalp, infop->di_acksz, NULL, 0);
+ } else {
+ retval.lr_err = err;
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ }
}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_impl.h b/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
index 237910ede6..eb7f6410b2 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
@@ -61,8 +61,11 @@ typedef struct dlmgmt_link_s {
datalink_class_t ll_class;
uint32_t ll_media;
datalink_id_t ll_linkid;
- avl_node_t ll_node_by_name;
- avl_node_t ll_node_by_id;
+ zoneid_t ll_zoneid;
+ boolean_t ll_onloan;
+ avl_node_t ll_name_node;
+ avl_node_t ll_id_node;
+ avl_node_t ll_loan_node;
uint32_t ll_flags;
uint32_t ll_gen; /* generation number */
} dlmgmt_link_t;
@@ -77,21 +80,25 @@ typedef struct dlmgmt_dlconf_s {
datalink_class_t ld_class;
uint32_t ld_media;
int ld_id;
+ zoneid_t ld_zoneid;
uint32_t ld_gen;
avl_node_t ld_node;
} dlmgmt_dlconf_t;
extern boolean_t debug;
extern const char *progname;
+extern char cachefile[];
extern dladm_handle_t dld_handle;
-
+extern datalink_id_t dlmgmt_nextlinkid;
extern avl_tree_t dlmgmt_name_avl;
extern avl_tree_t dlmgmt_id_avl;
+extern avl_tree_t dlmgmt_loan_avl;
extern avl_tree_t dlmgmt_dlconf_avl;
boolean_t linkattr_equal(dlmgmt_linkattr_t **, const char *, void *,
size_t);
-int linkattr_unset(dlmgmt_linkattr_t **, const char *);
+dlmgmt_linkattr_t *linkattr_find(dlmgmt_linkattr_t *, const char *);
+void linkattr_unset(dlmgmt_linkattr_t **, const char *);
int linkattr_set(dlmgmt_linkattr_t **, const char *, void *,
size_t, dladm_datatype_t);
int linkattr_get(dlmgmt_linkattr_t **, const char *, void **,
@@ -100,12 +107,14 @@ int linkprop_getnext(dlmgmt_linkattr_t **, const char *,
char **, void **, size_t *, dladm_datatype_t *);
void link_destroy(dlmgmt_link_t *);
-dlmgmt_link_t *link_by_id(datalink_id_t);
-dlmgmt_link_t *link_by_name(const char *);
+int link_activate(dlmgmt_link_t *);
+boolean_t link_is_visible(dlmgmt_link_t *, zoneid_t);
+dlmgmt_link_t *link_by_id(datalink_id_t, zoneid_t);
+dlmgmt_link_t *link_by_name(const char *, zoneid_t);
int dlmgmt_create_common(const char *, datalink_class_t,
- uint32_t, uint32_t, dlmgmt_link_t **);
+ uint32_t, zoneid_t, uint32_t, dlmgmt_link_t **);
int dlmgmt_destroy_common(dlmgmt_link_t *, uint32_t);
-void dlmgmt_getattr_common(dlmgmt_linkattr_t **, const char *,
+int dlmgmt_getattr_common(dlmgmt_linkattr_t **, const char *,
dlmgmt_getattr_retval_t *);
void dlmgmt_advance(dlmgmt_link_t *);
@@ -113,24 +122,26 @@ void dlmgmt_table_lock(boolean_t);
void dlmgmt_table_unlock();
int dlconf_create(const char *, datalink_id_t, datalink_class_t,
- uint32_t, dlmgmt_dlconf_t **);
+ uint32_t, zoneid_t, dlmgmt_dlconf_t **);
void dlconf_destroy(dlmgmt_dlconf_t *);
void dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *);
void dlmgmt_dlconf_table_lock(boolean_t);
void dlmgmt_dlconf_table_unlock(void);
-int dlmgmt_generate_name(const char *, char *, size_t);
+int dlmgmt_generate_name(const char *, char *, size_t, zoneid_t);
-int dlmgmt_linktable_init(void);
+void dlmgmt_linktable_init(void);
void dlmgmt_linktable_fini(void);
+int dlmgmt_zone_init(zoneid_t);
+int dlmgmt_elevate_privileges(void);
+int dlmgmt_drop_privileges();
void dlmgmt_handler(void *, char *, size_t, door_desc_t *, uint_t);
void dlmgmt_log(int, const char *, ...);
-int dlmgmt_write_db_entry(datalink_id_t, uint32_t);
-int dlmgmt_delete_db_entry(datalink_id_t, uint32_t);
-int dlmgmt_db_init(void);
-
-#define DLMGMT_TMPFS_DIR "/etc/svc/volatile/dladm"
+int dlmgmt_write_db_entry(const char *, dlmgmt_link_t *, uint32_t);
+int dlmgmt_delete_db_entry(dlmgmt_link_t *, uint32_t);
+int dlmgmt_db_init(zoneid_t);
+void dlmgmt_db_fini(zoneid_t);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_main.c b/usr/src/cmd/dlmgmtd/dlmgmt_main.c
index 5a27fdc2c2..7b97664792 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_main.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_main.c
@@ -41,12 +41,13 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <priv_utils.h>
+#include <priv.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <syslog.h>
+#include <zone.h>
#include <sys/dld.h>
#include <sys/dld_ioc.h>
#include <sys/param.h>
@@ -66,19 +67,18 @@ static int pfds[2];
static int dlmgmt_door_fd = -1;
/*
- * This libdladm handle is global so that dlmgmt_upcall_linkprop_init()
- * can pass to libdladm. The handle is opened during dlmgmt_init_privileges()
- * with "ALL" privileges. It is not able to open DLMGMT_DOOR at that time as
- * it hasn't been created yet. This door in the handle is opened in the first
- * call to dladm_door_fd().
+ * This libdladm handle is global so that dlmgmt_upcall_linkprop_init() can
+ * pass to libdladm. The handle is opened with "ALL" privileges, before
+ * privileges are dropped in dlmgmt_drop_privileges(). It is not able to open
+ * DLMGMT_DOOR at that time as it hasn't been created yet. This door in the
+ * handle is opened in the first call to dladm_door_fd().
*/
dladm_handle_t dld_handle = NULL;
static void dlmgmtd_exit(int);
static int dlmgmt_init();
static void dlmgmt_fini();
-static int dlmgmt_init_privileges();
-static void dlmgmt_fini_privileges();
+static int dlmgmt_set_privileges();
static int
dlmgmt_set_doorfd(boolean_t start)
@@ -97,73 +97,162 @@ dlmgmt_set_doorfd(boolean_t start)
}
static int
-dlmgmt_door_init()
+dlmgmt_door_init(void)
{
- int fd;
- int err;
+ int err = 0;
- /*
- * Create the door file for dlmgmtd.
- */
- if ((fd = open(DLMGMT_DOOR, O_CREAT|O_RDONLY, 0644)) == -1) {
+ if ((dlmgmt_door_fd = door_create(dlmgmt_handler, NULL,
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
err = errno;
- dlmgmt_log(LOG_ERR, "open(%s) failed: %s",
- DLMGMT_DOOR, strerror(err));
+ dlmgmt_log(LOG_ERR, "door_create() failed: %s",
+ strerror(err));
return (err);
}
- (void) close(fd);
+ return (err);
+}
- if ((dlmgmt_door_fd = door_create(dlmgmt_handler, NULL,
- DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+static void
+dlmgmt_door_fini(void)
+{
+ if (dlmgmt_door_fd == -1)
+ return;
+
+ if (door_revoke(dlmgmt_door_fd) == -1) {
+ dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
+ DLMGMT_DOOR, strerror(errno));
+ }
+ (void) dlmgmt_set_doorfd(B_FALSE);
+ dlmgmt_door_fd = -1;
+}
+
+int
+dlmgmt_door_attach(zoneid_t zoneid, char *rootdir)
+{
+ int fd;
+ int err = 0;
+ char doorpath[MAXPATHLEN];
+
+ (void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir,
+ DLMGMT_DOOR);
+
+ /*
+ * Create the door file for dlmgmtd.
+ */
+ if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) {
err = errno;
- dlmgmt_log(LOG_ERR, "door_create() failed: %s",
+ dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath,
strerror(err));
return (err);
}
+ (void) close(fd);
+ if (chown(doorpath, UID_DLADM, GID_SYS) == -1)
+ return (errno);
+
/*
* fdetach first in case a previous daemon instance exited
* ungracefully.
*/
- (void) fdetach(DLMGMT_DOOR);
- if (fattach(dlmgmt_door_fd, DLMGMT_DOOR) != 0) {
+ (void) fdetach(doorpath);
+ if (fattach(dlmgmt_door_fd, doorpath) != 0) {
err = errno;
- dlmgmt_log(LOG_ERR, "fattach(%s) failed: %s",
- DLMGMT_DOOR, strerror(err));
- goto fail;
- }
- if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) {
- dlmgmt_log(LOG_ERR, "cannot set kernel doorfd: %s",
+ dlmgmt_log(LOG_ERR, "fattach(%s) failed: %s", doorpath,
strerror(err));
- (void) fdetach(DLMGMT_DOOR);
- goto fail;
+ } else if (zoneid == GLOBAL_ZONEID) {
+ if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) {
+ dlmgmt_log(LOG_ERR, "cannot set kernel doorfd: %s",
+ strerror(err));
+ }
}
- return (0);
-fail:
- (void) door_revoke(dlmgmt_door_fd);
- dlmgmt_door_fd = -1;
return (err);
}
-static void
-dlmgmt_door_fini()
+/*
+ * Create the /etc/svc/volatile/dladm/ directory if it doesn't exist, load the
+ * datalink.conf data for this zone, and create/attach the door rendezvous
+ * file.
+ */
+int
+dlmgmt_zone_init(zoneid_t zoneid)
{
- if (dlmgmt_door_fd == -1)
- return;
+ char rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN];
+ int err;
+ struct stat statbuf;
+
+ if (zoneid == GLOBAL_ZONEID) {
+ rootdir[0] = '\0';
+ } else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir,
+ sizeof (rootdir)) < 0) {
+ return (errno);
+ }
- if (door_revoke(dlmgmt_door_fd) == -1) {
- dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
- DLMGMT_DOOR, strerror(errno));
+ /*
+ * Create the DLMGMT_TMPFS_DIR directory.
+ */
+ (void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir,
+ DLMGMT_TMPFS_DIR);
+ if (stat(tmpfsdir, &statbuf) < 0) {
+ if (mkdir(tmpfsdir, (mode_t)0755) < 0)
+ return (errno);
+ } else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
+ return (ENOTDIR);
}
- (void) fdetach(DLMGMT_DOOR);
- (void) dlmgmt_set_doorfd(B_FALSE);
+ if ((chmod(tmpfsdir, 0755) < 0) ||
+ (chown(tmpfsdir, UID_DLADM, GID_SYS) < 0)) {
+ return (EPERM);
+ }
+
+ if ((err = dlmgmt_db_init(zoneid)) != 0)
+ return (err);
+ return (dlmgmt_door_attach(zoneid, rootdir));
}
+/*
+ * Initialize each running zone.
+ */
static int
-dlmgmt_init()
+dlmgmt_allzones_init(void)
{
- int err;
+ int err, i;
+ zoneid_t *zids = NULL;
+ uint_t nzids, nzids_saved;
+
+ if (zone_list(NULL, &nzids) != 0)
+ return (errno);
+again:
+ nzids *= 2;
+ if ((zids = malloc(nzids * sizeof (zoneid_t))) == NULL)
+ return (errno);
+ nzids_saved = nzids;
+ if (zone_list(zids, &nzids) != 0) {
+ free(zids);
+ return (errno);
+ }
+ if (nzids > nzids_saved) {
+ free(zids);
+ goto again;
+ }
+
+ for (i = 0; i < nzids; i++) {
+ if ((err = dlmgmt_zone_init(zids[i])) != 0)
+ break;
+ }
+ free(zids);
+ return (err);
+}
+
+static int
+dlmgmt_init(void)
+{
+ int err;
+ char *fmri, *c;
+ char filename[MAXPATHLEN];
+
+ if (dladm_open(&dld_handle) != DLADM_STATUS_OK) {
+ dlmgmt_log(LOG_ERR, "dladm_open() failed");
+ return (EPERM);
+ }
if (signal(SIGTERM, dlmgmtd_exit) == SIG_ERR ||
signal(SIGINT, dlmgmtd_exit) == SIG_ERR) {
@@ -173,20 +262,66 @@ dlmgmt_init()
return (err);
}
- if ((err = dlmgmt_linktable_init()) != 0)
- return (err);
+ /*
+ * First derive the name of the cache file from the FMRI name. This
+ * cache name is used to keep active datalink configuration.
+ */
+ if (debug) {
+ (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
+ DLMGMT_TMPFS_DIR, progname, ".debug.cache");
+ } else {
+ if ((fmri = getenv("SMF_FMRI")) == NULL) {
+ dlmgmt_log(LOG_ERR, "dlmgmtd is an smf(5) managed "
+ "service and should not be run from the command "
+ "line.");
+ return (EINVAL);
+ }
- if ((err = dlmgmt_db_init()) != 0 || (err = dlmgmt_door_init()) != 0)
- dlmgmt_linktable_fini();
+ /*
+ * The FMRI name is in the form of
+ * svc:/service/service:instance. We need to remove the
+ * prefix "svc:/" and replace '/' with '-'. The cache file
+ * name is in the form of "service:instance.cache".
+ */
+ if ((c = strchr(fmri, '/')) != NULL)
+ c++;
+ else
+ c = fmri;
+ (void) snprintf(filename, MAXPATHLEN, "%s.cache", c);
+ c = filename;
+ while ((c = strchr(c, '/')) != NULL)
+ *c = '-';
+
+ (void) snprintf(cachefile, MAXPATHLEN, "%s/%s",
+ DLMGMT_TMPFS_DIR, filename);
+ }
+
+ dlmgmt_linktable_init();
+ if ((err = dlmgmt_door_init()) != 0)
+ goto done;
+
+ /*
+ * Load datalink configuration and create dlmgmtd door files for all
+ * currently running zones.
+ */
+ if ((err = dlmgmt_allzones_init()) != 0)
+ dlmgmt_door_fini();
+done:
+ if (err != 0)
+ dlmgmt_linktable_fini();
return (err);
}
static void
-dlmgmt_fini()
+dlmgmt_fini(void)
{
dlmgmt_door_fini();
dlmgmt_linktable_fini();
+ if (dld_handle != NULL) {
+ dladm_close(dld_handle);
+ dld_handle = NULL;
+ }
}
/*
@@ -214,7 +349,6 @@ dlmgmtd_exit(int signo)
{
(void) close(pfds[1]);
dlmgmt_fini();
- dlmgmt_fini_privileges();
exit(EXIT_FAILURE);
}
@@ -226,65 +360,76 @@ usage(void)
}
/*
- * Set the uid of this daemon to the "dladm" user. Finish the following
- * operations before setuid() because they need root privileges:
- *
- * - create the /etc/svc/volatile/dladm directory;
- * - change its uid/gid to "dladm"/"sys";
- * - open the dld control node
+ * Restrict privileges to only those needed.
*/
-static int
-dlmgmt_init_privileges()
+int
+dlmgmt_drop_privileges(void)
{
- struct stat statbuf;
-
- /*
- * Create the DLMGMT_TMPFS_DIR directory.
- */
- if (stat(DLMGMT_TMPFS_DIR, &statbuf) < 0) {
- if (mkdir(DLMGMT_TMPFS_DIR, (mode_t)0755) < 0)
- return (errno);
- } else {
- if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
- return (ENOTDIR);
- }
-
- if ((chmod(DLMGMT_TMPFS_DIR, 0755) < 0) ||
- (chown(DLMGMT_TMPFS_DIR, UID_DLADM, GID_SYS) < 0)) {
- return (EPERM);
- }
+ priv_set_t *pset;
+ priv_ptype_t ptype;
+ zoneid_t zoneid = getzoneid();
+ int err = 0;
- /*
- * When dlmgmtd is started at boot, "ALL" privilege is required
- * to open the dld control node. The door isn't created yet.
- */
- if (dladm_open(&dld_handle) != DLADM_STATUS_OK) {
- dlmgmt_log(LOG_ERR, "dladm_open() failed");
- return (EPERM);
- }
+ if ((pset = priv_allocset()) == NULL)
+ return (errno);
/*
- * We need PRIV_SYS_DL_CONFIG for the DLDIOC_DOORSERVER ioctl,
- * and PRIV_SYS_CONFIG to post sysevents.
+ * The global zone needs PRIV_PROC_FORK so that it can fork() when it
+ * issues db ops in non-global zones, PRIV_SYS_CONFIG to post
+ * sysevents, and PRIV_SYS_DL_CONFIG to initialize link properties in
+ * dlmgmt_upcall_linkprop_init().
+ *
+ * We remove all privileges from the permitted (and thus effective)
+ * set in the non-global zone. When executing in a non-global zone,
+ * dlmgmtd only needs to read and write to files that it already owns.
*/
- if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, UID_DLADM,
- GID_SYS, PRIV_SYS_DL_CONFIG, PRIV_SYS_CONFIG, NULL) == -1) {
- dladm_close(dld_handle);
- dld_handle = NULL;
- return (EPERM);
+ priv_emptyset(pset);
+ if (zoneid == GLOBAL_ZONEID) {
+ ptype = PRIV_EFFECTIVE;
+ if (priv_addset(pset, PRIV_PROC_FORK) == -1 ||
+ priv_addset(pset, PRIV_SYS_CONFIG) == -1 ||
+ priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1)
+ err = errno;
+ } else {
+ ptype = PRIV_PERMITTED;
}
+ if (err == 0 && setppriv(PRIV_SET, ptype, pset) == -1)
+ err = errno;
+done:
+ priv_freeset(pset);
+ return (err);
+}
+int
+dlmgmt_elevate_privileges(void)
+{
+ priv_set_t *privset;
+ int err = 0;
- return (0);
+ if ((privset = priv_str_to_set("zone", ",", NULL)) == NULL)
+ return (errno);
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privset) == -1)
+ err = errno;
+ priv_freeset(privset);
+ return (err);
}
-static void
-dlmgmt_fini_privileges()
+/*
+ * Set the uid of this daemon to the "dladm" user and drop privileges to only
+ * those needed.
+ */
+static int
+dlmgmt_set_privileges(void)
{
- if (dld_handle != NULL) {
- dladm_close(dld_handle);
- dld_handle = NULL;
- }
+ int err;
+
+ (void) setgroups(0, NULL);
+ if (setegid(GID_SYS) == -1 || seteuid(UID_DLADM) == -1)
+ err = errno;
+ else
+ err = dlmgmt_drop_privileges();
+done:
+ return (err);
}
/*
@@ -347,7 +492,7 @@ dlmgmt_daemonize(void)
int
main(int argc, char *argv[])
{
- int opt;
+ int opt, err;
progname = strrchr(argv[0], '/');
if (progname != NULL)
@@ -371,14 +516,14 @@ main(int argc, char *argv[])
if (!debug && !dlmgmt_daemonize())
return (EXIT_FAILURE);
- if ((errno = dlmgmt_init_privileges()) != 0) {
- dlmgmt_log(LOG_ERR, "dlmgmt_init_privileges() failed: %s",
- strerror(errno));
+ if ((err = dlmgmt_init()) != 0) {
+ dlmgmt_log(LOG_ERR, "unable to initialize daemon: %s",
+ strerror(err));
goto child_out;
- }
-
- if (dlmgmt_init() != 0) {
- dlmgmt_fini_privileges();
+ } else if ((err = dlmgmt_set_privileges()) != 0) {
+ dlmgmt_log(LOG_ERR, "unable to set daemon privileges: %s",
+ strerror(err));
+ dlmgmt_fini();
goto child_out;
}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_util.c b/usr/src/cmd/dlmgmtd/dlmgmt_util.c
index 87d2ed394f..58e44b9182 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_util.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_util.c
@@ -33,20 +33,26 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include <strings.h>
+#include <string.h>
#include <syslog.h>
#include <stdarg.h>
+#include <zone.h>
#include <errno.h>
#include <libdlpi.h>
#include "dlmgmt_impl.h"
/*
- * There are two datalink AVL tables. One table (dlmgmt_name_avl) is keyed by
- * the link name, and the other (dlmgmt_id_avl) is keyed by the link id.
- * Each link will be present in both tables.
+ * There are three datalink AVL tables. The dlmgmt_name_avl tree contains all
+ * datalinks and is keyed by zoneid and link name. The dlmgmt_id_avl also
+ * contains all datalinks, and it is keyed by link ID. The dlmgmt_loan_avl is
+ * keyed by link name, and contains the set of global-zone links that are
+ * currently on loan to non-global zones.
*/
avl_tree_t dlmgmt_name_avl;
avl_tree_t dlmgmt_id_avl;
+avl_tree_t dlmgmt_loan_avl;
avl_tree_t dlmgmt_dlconf_avl;
@@ -58,20 +64,14 @@ static pthread_rwlock_t dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER;
typedef struct dlmgmt_prefix {
struct dlmgmt_prefix *lp_next;
char lp_prefix[MAXLINKNAMELEN];
+ zoneid_t lp_zoneid;
uint_t lp_nextppa;
} dlmgmt_prefix_t;
-static dlmgmt_prefix_t *dlmgmt_prefixlist;
+static dlmgmt_prefix_t dlmgmt_prefixlist;
-static datalink_id_t dlmgmt_nextlinkid;
+datalink_id_t dlmgmt_nextlinkid;
static datalink_id_t dlmgmt_nextconfid = 1;
-static int linkattr_add(dlmgmt_linkattr_t **,
- dlmgmt_linkattr_t *);
-static int linkattr_rm(dlmgmt_linkattr_t **,
- dlmgmt_linkattr_t *);
-static int link_create(const char *, datalink_class_t, uint32_t,
- uint32_t, dlmgmt_link_t **);
-
static void dlmgmt_advance_linkid(dlmgmt_link_t *);
static void dlmgmt_advance_ppa(dlmgmt_link_t *);
@@ -101,6 +101,24 @@ cmp_link_by_name(const void *v1, const void *v2)
return ((cmp == 0) ? 0 : ((cmp < 0) ? -1 : 1));
}
+/*
+ * Note that the zoneid associated with a link is effectively part of its
+ * name. This is essentially what results in having each zone have disjoint
+ * datalink namespaces.
+ */
+static int
+cmp_link_by_zname(const void *v1, const void *v2)
+{
+ const dlmgmt_link_t *link1 = v1;
+ const dlmgmt_link_t *link2 = v2;
+
+ if (link1->ll_zoneid < link2->ll_zoneid)
+ return (-1);
+ if (link1->ll_zoneid > link2->ll_zoneid)
+ return (1);
+ return (cmp_link_by_name(link1, link2));
+}
+
static int
cmp_link_by_id(const void *v1, const void *v2)
{
@@ -129,49 +147,46 @@ cmp_dlconf_by_id(const void *v1, const void *v2)
return (1);
}
-int
-dlmgmt_linktable_init()
+void
+dlmgmt_linktable_init(void)
{
/*
- * Initialize the prefix list. First add the "net" prefix to the list.
+ * Initialize the prefix list. First add the "net" prefix for the
+ * global zone to the list.
*/
- dlmgmt_prefixlist = malloc(sizeof (dlmgmt_prefix_t));
- if (dlmgmt_prefixlist == NULL) {
- dlmgmt_log(LOG_WARNING, "dlmgmt_linktable_init() failed: %s",
- strerror(ENOMEM));
- return (ENOMEM);
- }
-
- dlmgmt_prefixlist->lp_next = NULL;
- dlmgmt_prefixlist->lp_nextppa = 0;
- (void) strlcpy(dlmgmt_prefixlist->lp_prefix, "net", MAXLINKNAMELEN);
+ dlmgmt_prefixlist.lp_next = NULL;
+ dlmgmt_prefixlist.lp_zoneid = GLOBAL_ZONEID;
+ dlmgmt_prefixlist.lp_nextppa = 0;
+ (void) strlcpy(dlmgmt_prefixlist.lp_prefix, "net", MAXLINKNAMELEN);
- avl_create(&dlmgmt_name_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
- offsetof(dlmgmt_link_t, ll_node_by_name));
+ avl_create(&dlmgmt_name_avl, cmp_link_by_zname, sizeof (dlmgmt_link_t),
+ offsetof(dlmgmt_link_t, ll_name_node));
avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
- offsetof(dlmgmt_link_t, ll_node_by_id));
+ offsetof(dlmgmt_link_t, ll_id_node));
+ avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
+ offsetof(dlmgmt_link_t, ll_loan_node));
avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id,
sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node));
dlmgmt_nextlinkid = 1;
- return (0);
}
void
-dlmgmt_linktable_fini()
+dlmgmt_linktable_fini(void)
{
- dlmgmt_prefix_t *lpp, *next;
+ dlmgmt_prefix_t *lpp, *next;
- for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = next) {
+ for (lpp = dlmgmt_prefixlist.lp_next; lpp != NULL; lpp = next) {
next = lpp->lp_next;
free(lpp);
}
avl_destroy(&dlmgmt_dlconf_avl);
avl_destroy(&dlmgmt_name_avl);
+ avl_destroy(&dlmgmt_loan_avl);
avl_destroy(&dlmgmt_id_avl);
}
-static int
+static void
linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
{
if (*headp == NULL) {
@@ -181,10 +196,9 @@ linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
attrp->lp_next = *headp;
*headp = attrp;
}
- return (0);
}
-static int
+static void
linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
{
dlmgmt_linkattr_t *next, *prev;
@@ -197,8 +211,18 @@ linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
prev->lp_next = next;
else
*headp = next;
+}
- return (0);
+dlmgmt_linkattr_t *
+linkattr_find(dlmgmt_linkattr_t *headp, const char *attr)
+{
+ dlmgmt_linkattr_t *attrp;
+
+ for (attrp = headp; attrp != NULL; attrp = attrp->lp_next) {
+ if (strcmp(attrp->lp_name, attr) == 0)
+ break;
+ }
+ return (attrp);
}
int
@@ -206,24 +230,17 @@ linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
size_t attrsz, dladm_datatype_t type)
{
dlmgmt_linkattr_t *attrp;
- int err;
-
- /*
- * See whether the attr is already set.
- */
- for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) {
- if (strcmp(attrp->lp_name, attr) == 0)
- break;
- }
+ void *newval;
+ boolean_t new;
+ attrp = linkattr_find(*headp, attr);
if (attrp != NULL) {
/*
* It is already set. If the value changed, update it.
*/
if (linkattr_equal(headp, attr, attrval, attrsz))
return (0);
-
- free(attrp->lp_val);
+ new = B_FALSE;
} else {
/*
* It is not set yet, allocate the linkattr and prepend to the
@@ -232,73 +249,43 @@ linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL)
return (ENOMEM);
- if ((err = linkattr_add(headp, attrp)) != 0) {
- free(attrp);
- return (err);
- }
(void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN);
+ new = B_TRUE;
}
- if ((attrp->lp_val = calloc(1, attrsz)) == NULL) {
- (void) linkattr_rm(headp, attrp);
- free(attrp);
+ if ((newval = calloc(1, attrsz)) == NULL) {
+ if (new)
+ free(attrp);
return (ENOMEM);
}
+ if (!new)
+ free(attrp->lp_val);
+ attrp->lp_val = newval;
bcopy(attrval, attrp->lp_val, attrsz);
attrp->lp_sz = attrsz;
attrp->lp_type = type;
attrp->lp_linkprop = dladm_attr_is_linkprop(attr);
+ if (new)
+ linkattr_add(headp, attrp);
return (0);
}
-int
+void
linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr)
{
- dlmgmt_linkattr_t *attrp, *prev;
-
- /*
- * See whether the attr exists.
- */
- for (prev = NULL, attrp = *headp; attrp != NULL;
- prev = attrp, attrp = attrp->lp_next) {
- if (strcmp(attrp->lp_name, attr) == 0)
- break;
- }
-
- /*
- * This attribute is not set in the first place. Return success.
- */
- if (attrp == NULL)
- return (0);
-
- /*
- * Remove this attr from the list.
- */
- if (prev == NULL)
- *headp = attrp->lp_next;
- else
- prev->lp_next = attrp->lp_next;
+ dlmgmt_linkattr_t *attrp;
- free(attrp->lp_val);
- free(attrp);
- return (0);
+ if ((attrp = linkattr_find(*headp, attr)) != NULL)
+ linkattr_rm(headp, attrp);
}
int
linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp,
size_t *attrszp, dladm_datatype_t *typep)
{
- dlmgmt_linkattr_t *attrp = *headp;
+ dlmgmt_linkattr_t *attrp;
- /*
- * find the specific attr.
- */
- for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) {
- if (strcmp(attrp->lp_name, attr) == 0)
- break;
- }
-
- if (attrp == NULL)
+ if ((attrp = linkattr_find(*headp, attr)) == NULL)
return (ENOENT);
*attrvalp = attrp->lp_val;
@@ -369,7 +356,7 @@ dlmgmt_table_lock(boolean_t write)
}
void
-dlmgmt_table_unlock()
+dlmgmt_table_unlock(void)
{
(void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
(void) pthread_mutex_lock(&dlmgmt_avl_mutex);
@@ -377,34 +364,6 @@ dlmgmt_table_unlock()
(void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
}
-static int
-link_create(const char *name, datalink_class_t class, uint32_t media,
- uint32_t flags, dlmgmt_link_t **linkpp)
-{
- dlmgmt_link_t *linkp = NULL;
- int err = 0;
-
- if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID) {
- err = ENOSPC;
- goto done;
- }
-
- if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
- err = ENOMEM;
- goto done;
- }
-
- (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
- linkp->ll_class = class;
- linkp->ll_media = media;
- linkp->ll_linkid = dlmgmt_nextlinkid;
- linkp->ll_flags = flags;
- linkp->ll_gen = 0;
-done:
- *linkpp = linkp;
- return (err);
-}
-
void
link_destroy(dlmgmt_link_t *linkp)
{
@@ -418,56 +377,129 @@ link_destroy(dlmgmt_link_t *linkp)
free(linkp);
}
+/*
+ * Set the DLMGMT_ACTIVE flag on the link to note that it is active. When a
+ * link becomes active and it belongs to a non-global zone, it is also added
+ * to that zone.
+ */
+int
+link_activate(dlmgmt_link_t *linkp)
+{
+ int err = 0;
+ zoneid_t zoneid;
+
+ if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
+ /*
+ * This link was already added to a non-global zone. This can
+ * happen if dlmgmtd is restarted.
+ */
+ if (zoneid != linkp->ll_zoneid) {
+ if (link_by_name(linkp->ll_link, zoneid) != NULL) {
+ err = EEXIST;
+ goto done;
+ }
+ avl_remove(&dlmgmt_name_avl, linkp);
+ linkp->ll_zoneid = zoneid;
+ avl_add(&dlmgmt_name_avl, linkp);
+ avl_add(&dlmgmt_loan_avl, linkp);
+ linkp->ll_onloan = B_TRUE;
+ }
+ } else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
+ err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
+ }
+done:
+ if (err == 0)
+ linkp->ll_flags |= DLMGMT_ACTIVE;
+ return (err);
+}
+
+/*
+ * Is linkp visible from the caller's zoneid? It is if the link is in the
+ * same zone as the caller, or if the caller is in the global zone and the
+ * link is on loan to a non-global zone.
+ */
+boolean_t
+link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid)
+{
+ return (linkp->ll_zoneid == zoneid ||
+ (zoneid == GLOBAL_ZONEID && linkp->ll_onloan));
+}
+
dlmgmt_link_t *
-link_by_id(datalink_id_t linkid)
+link_by_id(datalink_id_t linkid, zoneid_t zoneid)
{
- dlmgmt_link_t link;
+ dlmgmt_link_t link, *linkp;
link.ll_linkid = linkid;
- return (avl_find(&dlmgmt_id_avl, &link, NULL));
+ linkp = avl_find(&dlmgmt_id_avl, &link, NULL);
+ if (zoneid != GLOBAL_ZONEID && linkp->ll_zoneid != zoneid)
+ linkp = NULL;
+ return (linkp);
}
dlmgmt_link_t *
-link_by_name(const char *name)
+link_by_name(const char *name, zoneid_t zoneid)
{
- dlmgmt_link_t link;
+ dlmgmt_link_t link, *linkp;
(void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
- return (avl_find(&dlmgmt_name_avl, &link, NULL));
+ link.ll_zoneid = zoneid;
+ linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
+ if (linkp == NULL && zoneid == GLOBAL_ZONEID) {
+ /* The link could be on loan to a non-global zone? */
+ linkp = avl_find(&dlmgmt_loan_avl, &link, NULL);
+ }
+ return (linkp);
}
int
dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
- uint32_t flags, dlmgmt_link_t **linkpp)
+ zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp)
{
- dlmgmt_link_t link, *linkp, *tmp;
+ dlmgmt_link_t *linkp = NULL;
avl_index_t name_where, id_where;
- int err;
+ int err = 0;
- /*
- * Validate the link.
- */
if (!dladm_valid_linkname(name))
return (EINVAL);
+ if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
+ return (ENOSPC);
- /*
- * Check to see whether this is an existing link name.
- */
- (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
- if ((linkp = avl_find(&dlmgmt_name_avl, &link, &name_where)) != NULL)
- return (EEXIST);
+ if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
- if ((err = link_create(name, class, media, flags, &linkp)) != 0)
- return (err);
+ (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
+ linkp->ll_class = class;
+ linkp->ll_media = media;
+ linkp->ll_linkid = dlmgmt_nextlinkid;
+ linkp->ll_zoneid = zoneid;
+ linkp->ll_gen = 0;
+
+ if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
+ avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
+ err = EEXIST;
+ goto done;
+ }
- link.ll_linkid = linkp->ll_linkid;
- tmp = avl_find(&dlmgmt_id_avl, &link, &id_where);
- assert(tmp == NULL);
avl_insert(&dlmgmt_name_avl, linkp, name_where);
avl_insert(&dlmgmt_id_avl, linkp, id_where);
+
+ if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) {
+ avl_remove(&dlmgmt_name_avl, linkp);
+ avl_remove(&dlmgmt_id_avl, linkp);
+ goto done;
+ }
+
+ linkp->ll_flags = flags;
dlmgmt_advance(linkp);
*linkpp = linkp;
- return (0);
+
+done:
+ if (err != 0)
+ free(linkp);
+ return (err);
}
int
@@ -479,8 +511,9 @@ dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
*/
return (ENOENT);
}
+
linkp->ll_flags &= ~flags;
- if (!(linkp->ll_flags & DLMGMT_PERSIST)) {
+ if (flags & DLMGMT_PERSIST) {
dlmgmt_linkattr_t *next, *attrp;
for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
@@ -491,6 +524,12 @@ dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
linkp->ll_head = NULL;
}
+ if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) {
+ (void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid);
+ if (linkp->ll_onloan)
+ avl_remove(&dlmgmt_loan_avl, linkp);
+ }
+
if (linkp->ll_flags == 0) {
avl_remove(&dlmgmt_id_avl, linkp);
avl_remove(&dlmgmt_name_avl, linkp);
@@ -500,7 +539,7 @@ dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
return (0);
}
-void
+int
dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr,
dlmgmt_getattr_retval_t *retvalp)
{
@@ -511,19 +550,16 @@ dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr,
err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype);
if (err != 0)
- goto done;
+ return (err);
assert(attrsz > 0);
- if (attrsz > MAXLINKATTRVALLEN) {
- err = EINVAL;
- goto done;
- }
+ if (attrsz > MAXLINKATTRVALLEN)
+ return (EINVAL);
retvalp->lr_type = attrtype;
retvalp->lr_attrsz = attrsz;
bcopy(attrval, retvalp->lr_attrval, attrsz);
-done:
- retvalp->lr_err = err;
+ return (0);
}
void
@@ -536,14 +572,14 @@ dlmgmt_dlconf_table_lock(boolean_t write)
}
void
-dlmgmt_dlconf_table_unlock()
+dlmgmt_dlconf_table_unlock(void)
{
(void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock);
}
int
dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class,
- uint32_t media, dlmgmt_dlconf_t **dlconfpp)
+ uint32_t media, zoneid_t zoneid, dlmgmt_dlconf_t **dlconfpp)
{
dlmgmt_dlconf_t *dlconfp = NULL;
int err = 0;
@@ -563,6 +599,7 @@ dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class,
dlconfp->ld_class = class;
dlconfp->ld_media = media;
dlconfp->ld_id = dlmgmt_nextconfid;
+ dlconfp->ld_zoneid = zoneid;
done:
*dlconfpp = dlconfp;
@@ -583,16 +620,19 @@ dlconf_destroy(dlmgmt_dlconf_t *dlconfp)
}
int
-dlmgmt_generate_name(const char *prefix, char *name, size_t size)
+dlmgmt_generate_name(const char *prefix, char *name, size_t size,
+ zoneid_t zoneid)
{
dlmgmt_prefix_t *lpp, *prev = NULL;
+ dlmgmt_link_t link, *linkp;
/*
* See whether the requested prefix is already in the list.
*/
- for (lpp = dlmgmt_prefixlist; lpp != NULL; prev = lpp,
- lpp = lpp->lp_next) {
- if (strcmp(prefix, lpp->lp_prefix) == 0)
+ for (lpp = &dlmgmt_prefixlist; lpp != NULL;
+ prev = lpp, lpp = lpp->lp_next) {
+ if (lpp->lp_zoneid == zoneid &&
+ strcmp(prefix, lpp->lp_prefix) == 0)
break;
}
@@ -600,8 +640,6 @@ dlmgmt_generate_name(const char *prefix, char *name, size_t size)
* Not found.
*/
if (lpp == NULL) {
- dlmgmt_link_t *linkp, link;
-
assert(prev != NULL);
/*
@@ -612,6 +650,7 @@ dlmgmt_generate_name(const char *prefix, char *name, size_t size)
prev->lp_next = lpp;
lpp->lp_next = NULL;
+ lpp->lp_zoneid = zoneid;
lpp->lp_nextppa = 0;
(void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN);
@@ -619,9 +658,9 @@ dlmgmt_generate_name(const char *prefix, char *name, size_t size)
* Now determine this prefix's nextppa.
*/
(void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d",
- prefix, lpp->lp_nextppa);
- linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
- if (linkp != NULL)
+ prefix, 0);
+ link.ll_zoneid = zoneid;
+ if ((linkp = avl_find(&dlmgmt_name_avl, &link, NULL)) != NULL)
dlmgmt_advance_ppa(linkp);
}
@@ -641,6 +680,7 @@ dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
{
dlmgmt_prefix_t *lpp;
char prefix[MAXLINKNAMELEN];
+ char linkname[MAXLINKNAMELEN];
uint_t start, ppa;
(void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
@@ -648,8 +688,9 @@ dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
/*
* See whether the requested prefix is already in the list.
*/
- for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) {
- if (strcmp(prefix, lpp->lp_prefix) == 0)
+ for (lpp = &dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) {
+ if (lpp->lp_zoneid == linkp->ll_zoneid &&
+ strcmp(prefix, lpp->lp_prefix) == 0)
break;
}
@@ -664,15 +705,13 @@ dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
while (lpp->lp_nextppa != start) {
if (lpp->lp_nextppa == (uint_t)-1) {
- dlmgmt_link_t link;
-
/*
* wrapped around. search from <prefix>1.
*/
lpp->lp_nextppa = 0;
- (void) snprintf(link.ll_link, MAXLINKNAMELEN,
+ (void) snprintf(linkname, MAXLINKNAMELEN,
"%s%d", lpp->lp_prefix, lpp->lp_nextppa);
- linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
+ linkp = link_by_name(linkname, lpp->lp_zoneid);
if (linkp == NULL)
return;
} else {
@@ -706,15 +745,11 @@ dlmgmt_advance_linkid(dlmgmt_link_t *linkp)
do {
if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) {
- dlmgmt_link_t link;
-
/*
* wrapped around. search from 1.
*/
dlmgmt_nextlinkid = 1;
- link.ll_linkid = 1;
- linkp = avl_find(&dlmgmt_id_avl, &link, NULL);
- if (linkp == NULL)
+ if ((linkp = link_by_id(1, GLOBAL_ZONEID)) == NULL)
return;
} else {
dlmgmt_nextlinkid++;