xref: /illumos-gate/usr/src/cmd/dlmgmtd/dlmgmt_main.c (revision bbf21555)
1d62bc4baSyz /*
2d62bc4baSyz  * CDDL HEADER START
3d62bc4baSyz  *
4d62bc4baSyz  * The contents of this file are subject to the terms of the
5d62bc4baSyz  * Common Development and Distribution License (the "License").
6d62bc4baSyz  * You may not use this file except in compliance with the License.
7d62bc4baSyz  *
8d62bc4baSyz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz  * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz  * See the License for the specific language governing permissions
11d62bc4baSyz  * and limitations under the License.
12d62bc4baSyz  *
13d62bc4baSyz  * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz  * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz  * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz  * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz  *
19d62bc4baSyz  * CDDL HEADER END
20d62bc4baSyz  */
21d62bc4baSyz 
22d62bc4baSyz /*
23634e26ecSCasper H.S. Dik  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24d62bc4baSyz  * Use is subject to license terms.
25d62bc4baSyz  */
26d62bc4baSyz 
27d62bc4baSyz /*
28d62bc4baSyz  * The dlmgmtd daemon is started by the datalink-management SMF service.
29d62bc4baSyz  * This daemon is used to manage <link name, linkid> mapping and the
30d62bc4baSyz  * persistent datalink configuration.
31d62bc4baSyz  *
32d62bc4baSyz  * Today, the <link name, linkid> mapping and the persistent configuration
33d62bc4baSyz  * of datalinks is kept in /etc/dladm/datalink.conf, and the daemon keeps
34d62bc4baSyz  * a copy of the datalinks in the memory (see dlmgmt_id_avl and
35d62bc4baSyz  * dlmgmt_name_avl). The active <link name, linkid> mapping is kept in
36b9e076dcSyz  * /etc/svc/volatile/dladm cache file, so that the mapping can be recovered
37b9e076dcSyz  * when dlmgmtd exits for some reason (e.g., when dlmgmtd is accidentally
38b9e076dcSyz  * killed).
39d62bc4baSyz  */
40d62bc4baSyz 
41d62bc4baSyz #include <assert.h>
42d62bc4baSyz #include <errno.h>
43d62bc4baSyz #include <fcntl.h>
442b24ab6bSSebastien Roy #include <priv.h>
45d62bc4baSyz #include <signal.h>
46d62bc4baSyz #include <stdlib.h>
47d62bc4baSyz #include <stdio.h>
48d62bc4baSyz #include <strings.h>
49d62bc4baSyz #include <syslog.h>
502b24ab6bSSebastien Roy #include <zone.h>
51d62bc4baSyz #include <sys/dld.h>
5282a2fc47SJames Carlson #include <sys/dld_ioc.h>
53b9e076dcSyz #include <sys/param.h>
54b9e076dcSyz #include <sys/stat.h>
55d62bc4baSyz #include <unistd.h>
564ac67f02SAnurag S. Maskey #include <libdladm_impl.h>
57d62bc4baSyz #include <libdlmgmt.h>
58d62bc4baSyz #include "dlmgmt_impl.h"
59d62bc4baSyz 
60d62bc4baSyz const char		*progname;
61d62bc4baSyz boolean_t		debug;
62d62bc4baSyz static int		pfds[2];
634ac67f02SAnurag S. Maskey /*
644ac67f02SAnurag S. Maskey  * This file descriptor to DLMGMT_DOOR cannot be in the libdladm
654ac67f02SAnurag S. Maskey  * handle because the door isn't created when the handle is created.
664ac67f02SAnurag S. Maskey  */
67d62bc4baSyz static int		dlmgmt_door_fd = -1;
684ac67f02SAnurag S. Maskey 
694ac67f02SAnurag S. Maskey /*
702b24ab6bSSebastien Roy  * This libdladm handle is global so that dlmgmt_upcall_linkprop_init() can
712b24ab6bSSebastien Roy  * pass to libdladm.  The handle is opened with "ALL" privileges, before
722b24ab6bSSebastien Roy  * privileges are dropped in dlmgmt_drop_privileges().  It is not able to open
732b24ab6bSSebastien Roy  * DLMGMT_DOOR at that time as it hasn't been created yet.  This door in the
742b24ab6bSSebastien Roy  * handle is opened in the first call to dladm_door_fd().
754ac67f02SAnurag S. Maskey  */
764ac67f02SAnurag S. Maskey dladm_handle_t		dld_handle = NULL;
77b9e076dcSyz 
78b9e076dcSyz static void		dlmgmtd_exit(int);
79b9e076dcSyz static int		dlmgmt_init();
80b9e076dcSyz static void		dlmgmt_fini();
812b24ab6bSSebastien Roy static int		dlmgmt_set_privileges();
82d62bc4baSyz 
83d62bc4baSyz static int
dlmgmt_set_doorfd(boolean_t start)84d62bc4baSyz dlmgmt_set_doorfd(boolean_t start)
85d62bc4baSyz {
86d62bc4baSyz 	dld_ioc_door_t did;
87d62bc4baSyz 	int err = 0;
88d62bc4baSyz 
894ac67f02SAnurag S. Maskey 	assert(dld_handle != NULL);
90d62bc4baSyz 
91d62bc4baSyz 	did.did_start_door = start;
92d62bc4baSyz 
934ac67f02SAnurag S. Maskey 	if (ioctl(dladm_dld_fd(dld_handle), DLDIOC_DOORSERVER, &did) == -1)
94d62bc4baSyz 		err = errno;
95d62bc4baSyz 
96d62bc4baSyz 	return (err);
97d62bc4baSyz }
98d62bc4baSyz 
99d62bc4baSyz static int
dlmgmt_door_init(void)1002b24ab6bSSebastien Roy dlmgmt_door_init(void)
101d62bc4baSyz {
1022b24ab6bSSebastien Roy 	int err = 0;
103d62bc4baSyz 
1042b24ab6bSSebastien Roy 	if ((dlmgmt_door_fd = door_create(dlmgmt_handler, NULL,
1052b24ab6bSSebastien Roy 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
106b9e076dcSyz 		err = errno;
1072b24ab6bSSebastien Roy 		dlmgmt_log(LOG_ERR, "door_create() failed: %s",
1082b24ab6bSSebastien Roy 		    strerror(err));
109b9e076dcSyz 		return (err);
110b9e076dcSyz 	}
1112b24ab6bSSebastien Roy 	return (err);
1122b24ab6bSSebastien Roy }
113b9e076dcSyz 
1142b24ab6bSSebastien Roy static void
dlmgmt_door_fini(void)1152b24ab6bSSebastien Roy dlmgmt_door_fini(void)
1162b24ab6bSSebastien Roy {
1172b24ab6bSSebastien Roy 	if (dlmgmt_door_fd == -1)
1182b24ab6bSSebastien Roy 		return;
1192b24ab6bSSebastien Roy 
1202b24ab6bSSebastien Roy 	if (door_revoke(dlmgmt_door_fd) == -1) {
1212b24ab6bSSebastien Roy 		dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
1222b24ab6bSSebastien Roy 		    DLMGMT_DOOR, strerror(errno));
1232b24ab6bSSebastien Roy 	}
1242b24ab6bSSebastien Roy 	(void) dlmgmt_set_doorfd(B_FALSE);
1252b24ab6bSSebastien Roy 	dlmgmt_door_fd = -1;
1262b24ab6bSSebastien Roy }
1272b24ab6bSSebastien Roy 
1282b24ab6bSSebastien Roy int
dlmgmt_door_attach(zoneid_t zoneid,char * rootdir)1292b24ab6bSSebastien Roy dlmgmt_door_attach(zoneid_t zoneid, char *rootdir)
1302b24ab6bSSebastien Roy {
1312b24ab6bSSebastien Roy 	int	fd;
1322b24ab6bSSebastien Roy 	int	err = 0;
1332b24ab6bSSebastien Roy 	char	doorpath[MAXPATHLEN];
1342b24ab6bSSebastien Roy 
1352b24ab6bSSebastien Roy 	(void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir,
1362b24ab6bSSebastien Roy 	    DLMGMT_DOOR);
1372b24ab6bSSebastien Roy 
1382b24ab6bSSebastien Roy 	/*
1392b24ab6bSSebastien Roy 	 * Create the door file for dlmgmtd.
1402b24ab6bSSebastien Roy 	 */
1412b24ab6bSSebastien Roy 	if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) {
142d62bc4baSyz 		err = errno;
1432b24ab6bSSebastien Roy 		dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath,
144d62bc4baSyz 		    strerror(err));
145d62bc4baSyz 		return (err);
146d62bc4baSyz 	}
1472b24ab6bSSebastien Roy 	(void) close(fd);
1486ba597c5SAnurag S. Maskey 	if (chown(doorpath, UID_DLADM, GID_NETADM) == -1)
1492b24ab6bSSebastien Roy 		return (errno);
1502b24ab6bSSebastien Roy 
151fd4e42c3SSebastien Roy 	/*
152fd4e42c3SSebastien Roy 	 * fdetach first in case a previous daemon instance exited
153fd4e42c3SSebastien Roy 	 * ungracefully.
154fd4e42c3SSebastien Roy 	 */
1552b24ab6bSSebastien Roy 	(void) fdetach(doorpath);
1562b24ab6bSSebastien Roy 	if (fattach(dlmgmt_door_fd, doorpath) != 0) {
157d62bc4baSyz 		err = errno;
1582b24ab6bSSebastien Roy 		dlmgmt_log(LOG_ERR, "fattach(%s) failed: %s", doorpath,
159d62bc4baSyz 		    strerror(err));
1602b24ab6bSSebastien Roy 	} else if (zoneid == GLOBAL_ZONEID) {
1612b24ab6bSSebastien Roy 		if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) {
1622b24ab6bSSebastien Roy 			dlmgmt_log(LOG_ERR, "cannot set kernel doorfd: %s",
1632b24ab6bSSebastien Roy 			    strerror(err));
1642b24ab6bSSebastien Roy 		}
165d62bc4baSyz 	}
166d62bc4baSyz 
167d62bc4baSyz 	return (err);
168d62bc4baSyz }
169d62bc4baSyz 
1702b24ab6bSSebastien Roy /*
1712b24ab6bSSebastien Roy  * Create the /etc/svc/volatile/dladm/ directory if it doesn't exist, load the
1722b24ab6bSSebastien Roy  * datalink.conf data for this zone, and create/attach the door rendezvous
1732b24ab6bSSebastien Roy  * file.
1742b24ab6bSSebastien Roy  */
1752b24ab6bSSebastien Roy int
dlmgmt_zone_init(zoneid_t zoneid)1762b24ab6bSSebastien Roy dlmgmt_zone_init(zoneid_t zoneid)
177d62bc4baSyz {
1782b24ab6bSSebastien Roy 	char	rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN];
1792b24ab6bSSebastien Roy 	int	err;
1802b24ab6bSSebastien Roy 	struct stat statbuf;
1812b24ab6bSSebastien Roy 
1822b24ab6bSSebastien Roy 	if (zoneid == GLOBAL_ZONEID) {
1832b24ab6bSSebastien Roy 		rootdir[0] = '\0';
1842b24ab6bSSebastien Roy 	} else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir,
1852b24ab6bSSebastien Roy 	    sizeof (rootdir)) < 0) {
1862b24ab6bSSebastien Roy 		return (errno);
1872b24ab6bSSebastien Roy 	}
188b9e076dcSyz 
1892b24ab6bSSebastien Roy 	/*
1902b24ab6bSSebastien Roy 	 * Create the DLMGMT_TMPFS_DIR directory.
1912b24ab6bSSebastien Roy 	 */
1922b24ab6bSSebastien Roy 	(void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir,
1932b24ab6bSSebastien Roy 	    DLMGMT_TMPFS_DIR);
1942b24ab6bSSebastien Roy 	if (stat(tmpfsdir, &statbuf) < 0) {
1952b24ab6bSSebastien Roy 		if (mkdir(tmpfsdir, (mode_t)0755) < 0)
1962b24ab6bSSebastien Roy 			return (errno);
1972b24ab6bSSebastien Roy 	} else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
1982b24ab6bSSebastien Roy 		return (ENOTDIR);
199d62bc4baSyz 	}
200b9e076dcSyz 
2012b24ab6bSSebastien Roy 	if ((chmod(tmpfsdir, 0755) < 0) ||
2026ba597c5SAnurag S. Maskey 	    (chown(tmpfsdir, UID_DLADM, GID_NETADM) < 0)) {
2032b24ab6bSSebastien Roy 		return (EPERM);
2042b24ab6bSSebastien Roy 	}
2052b24ab6bSSebastien Roy 
2062b24ab6bSSebastien Roy 	if ((err = dlmgmt_db_init(zoneid)) != 0)
2072b24ab6bSSebastien Roy 		return (err);
2082b24ab6bSSebastien Roy 	return (dlmgmt_door_attach(zoneid, rootdir));
209d62bc4baSyz }
210d62bc4baSyz 
2112b24ab6bSSebastien Roy /*
2122b24ab6bSSebastien Roy  * Initialize each running zone.
2132b24ab6bSSebastien Roy  */
214d62bc4baSyz static int
dlmgmt_allzones_init(void)2152b24ab6bSSebastien Roy dlmgmt_allzones_init(void)
216d62bc4baSyz {
2172b24ab6bSSebastien Roy 	int		err, i;
2182b24ab6bSSebastien Roy 	zoneid_t	*zids = NULL;
2192b24ab6bSSebastien Roy 	uint_t		nzids, nzids_saved;
2202b24ab6bSSebastien Roy 
2212b24ab6bSSebastien Roy 	if (zone_list(NULL, &nzids) != 0)
222