diff options
Diffstat (limited to 'usr/src/lib/libdladm/common/libdlmgmt.c')
-rw-r--r-- | usr/src/lib/libdladm/common/libdlmgmt.c | 676 |
1 files changed, 676 insertions, 0 deletions
diff --git a/usr/src/lib/libdladm/common/libdlmgmt.c b/usr/src/lib/libdladm/common/libdlmgmt.c new file mode 100644 index 0000000000..1826edf810 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlmgmt.c @@ -0,0 +1,676 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <door.h> +#include <errno.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/aggr.h> +#include <fcntl.h> +#include <libdladm.h> +#include <libdladm_impl.h> +#include <libdllink.h> +#include <libdlmgmt.h> + +/* + * Table of data type sizes indexed by dladm_datatype_t. + */ +static size_t dladm_datatype_size[] = { + 0, /* DLADM_TYPE_STR, use strnlen() */ + sizeof (boolean_t), /* DLADM_TYPE_BOOLEAN */ + sizeof (uint64_t) /* DLADM_TYPE_UINT64 */ +}; + +static dladm_status_t +dladm_door_call(void *arg, size_t asize, void *rbuf, size_t *rsizep) +{ + door_arg_t darg; + dlmgmt_retval_t *retvalp = rbuf; + int fd; + dladm_status_t status = DLADM_STATUS_OK; + + if ((fd = open(DLMGMT_DOOR, O_RDONLY)) == -1) + return (dladm_errno2status(errno)); + + darg.data_ptr = arg; + darg.data_size = asize; + darg.desc_ptr = NULL; + darg.desc_num = 0; + darg.rbuf = rbuf; + darg.rsize = *rsizep; + + if (door_call(fd, &darg) == -1) + status = dladm_errno2status(errno); + (void) close(fd); + + if (status != DLADM_STATUS_OK) + return (status); + + if (darg.rbuf != rbuf) { + /* + * The size of the input rbuf is not big enough so that + * the door allocate the rbuf itself. In this case, simply + * think something wrong with the door call. + */ + (void) munmap(darg.rbuf, darg.rsize); + return (DLADM_STATUS_TOOSMALL); + } + if (darg.rsize > *rsizep || darg.rsize < sizeof (uint_t)) + return (DLADM_STATUS_FAILED); + + if (retvalp->lr_err != 0) + status = dladm_errno2status(retvalp->lr_err); + else + *rsizep = darg.rsize; + return (status); +} + +/* + * Allocate a new linkid with the given name. Return the new linkid. + */ +dladm_status_t +dladm_create_datalink_id(const char *link, datalink_class_t class, + uint32_t media, uint32_t flags, datalink_id_t *linkidp) +{ + dlmgmt_door_createid_t createid; + dlmgmt_createid_retval_t retval; + uint32_t dlmgmt_flags; + dladm_status_t status; + size_t rsize; + + if (link == NULL || *link == '\0' || class == DATALINK_CLASS_ALL || + !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) || + linkidp == NULL) { + return (DLADM_STATUS_BADARG); + } + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0; + + (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN); + createid.ld_class = class; + createid.ld_media = media; + createid.ld_flags = dlmgmt_flags; + createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID; + createid.ld_prefix = (flags & DLADM_OPT_PREFIX); + rsize = sizeof (retval); + + status = dladm_door_call(&createid, sizeof (createid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *linkidp = retval.lr_linkid; + return (DLADM_STATUS_OK); +} + +/* + * Destroy the given link ID. + */ +dladm_status_t +dladm_destroy_datalink_id(datalink_id_t linkid, uint32_t flags) +{ + dlmgmt_door_destroyid_t destroyid; + dlmgmt_destroyid_retval_t retval; + uint32_t dlmgmt_flags; + size_t rsize; + dladm_status_t status; + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); + + destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID; + destroyid.ld_linkid = linkid; + destroyid.ld_flags = dlmgmt_flags; + rsize = sizeof (retval); + + status = dladm_door_call(&destroyid, sizeof (destroyid), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Remap a given link ID to a new name. + */ +dladm_status_t +dladm_remap_datalink_id(datalink_id_t linkid, const char *link) +{ + dlmgmt_door_remapid_t remapid; + dlmgmt_remapid_retval_t retval; + size_t rsize; + dladm_status_t status; + + remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID; + remapid.ld_linkid = linkid; + (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + status = dladm_door_call(&remapid, sizeof (remapid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Make a given link ID active. + */ +dladm_status_t +dladm_up_datalink_id(datalink_id_t linkid) +{ + dlmgmt_door_upid_t upid; + dlmgmt_upid_retval_t retval; + size_t rsize; + dladm_status_t status; + + upid.ld_cmd = DLMGMT_CMD_UP_LINKID; + upid.ld_linkid = linkid; + rsize = sizeof (retval); + + status = dladm_door_call(&upid, sizeof (upid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Create a new link with the given name. Return the new link's handle + */ +dladm_status_t +dladm_create_conf(const char *link, datalink_id_t linkid, + datalink_class_t class, uint32_t media, dladm_conf_t *confp) +{ + dlmgmt_door_createconf_t createconf; + dlmgmt_createconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (link == NULL || *link == '\0' || confp == NULL) + return (DLADM_STATUS_BADARG); + + (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN); + createconf.ld_class = class; + createconf.ld_media = media; + createconf.ld_linkid = linkid; + createconf.ld_cmd = DLMGMT_CMD_CREATECONF; + rsize = sizeof (retval); + + status = dladm_door_call(&createconf, sizeof (createconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *confp = retval.lr_conf; + return (DLADM_STATUS_OK); +} + +/* + * An active physical link reported by the dlmgmtd daemon might not be active + * anymore as this link might be removed during system shutdown. Check its + * real status by calling dladm_phys_info(). + */ +dladm_status_t +i_dladm_phys_status(datalink_id_t linkid, uint32_t *flagsp) +{ + dladm_phys_attr_t dpa; + dladm_status_t status; + + assert((*flagsp) & DLMGMT_ACTIVE); + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE); + if (status == DLADM_STATUS_NOTFOUND) { + /* + * No active status, this link was removed. Update its status + * in the daemon and delete all active linkprops. + */ + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); + (void) dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + + (*flagsp) &= ~DLMGMT_ACTIVE; + status = DLADM_STATUS_OK; + } + return (status); +} + +/* + * Walk each entry in the data link configuration repository and + * call fn on the linkid and arg. + */ +dladm_status_t +dladm_walk_datalink_id(int (*fn)(datalink_id_t, void *), void *argp, + datalink_class_t class, datalink_media_t dmedia, uint32_t flags) +{ + dlmgmt_door_getnext_t getnext; + dlmgmt_getnext_retval_t retval; + uint32_t dlmgmt_flags; + size_t rsize; + datalink_id_t linkid = DATALINK_INVALID_LINKID; + dladm_status_t status = DLADM_STATUS_OK; + + if (fn == NULL) + return (DLADM_STATUS_BADARG); + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); + + getnext.ld_cmd = DLMGMT_CMD_GETNEXT; + getnext.ld_class = class; + getnext.ld_dmedia = dmedia; + getnext.ld_flags = dlmgmt_flags; + rsize = sizeof (retval); + + do { + getnext.ld_linkid = linkid; + status = dladm_door_call(&getnext, sizeof (getnext), + &retval, &rsize); + if (status != DLADM_STATUS_OK) { + /* + * done with walking + */ + break; + } + + if (rsize != sizeof (retval)) { + status = DLADM_STATUS_BADARG; + break; + } + + linkid = retval.lr_linkid; + if ((retval.lr_class == DATALINK_CLASS_PHYS) && + (retval.lr_flags & DLMGMT_ACTIVE)) { + /* + * An active physical link reported by the dlmgmtd + * daemon might not be active anymore. Check its + * real status. + */ + if (i_dladm_phys_status(linkid, &retval.lr_flags) != + DLADM_STATUS_OK) { + continue; + } + + if (!(dlmgmt_flags & retval.lr_flags)) + continue; + } + + if (fn(linkid, argp) == DLADM_WALK_TERMINATE) + break; + } while (linkid != DATALINK_INVALID_LINKID); + + return (status); +} + +/* + * Get the link properties structure for the given link. + */ +dladm_status_t +dladm_read_conf(datalink_id_t linkid, dladm_conf_t *confp) +{ + dlmgmt_door_readconf_t readconf; + dlmgmt_readconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (linkid == DATALINK_INVALID_LINKID || confp == NULL) + return (DLADM_STATUS_BADARG); + + readconf.ld_linkid = linkid; + readconf.ld_cmd = DLMGMT_CMD_READCONF; + rsize = sizeof (retval); + + status = dladm_door_call(&readconf, sizeof (readconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *confp = retval.lr_conf; + return (DLADM_STATUS_OK); +} + +/* + * Commit the given link to the data link configuration repository so + * that it will persist across reboots. + */ +dladm_status_t +dladm_write_conf(dladm_conf_t conf) +{ + dlmgmt_door_writeconf_t writeconf; + dlmgmt_writeconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (conf == DLADM_INVALID_CONF) + return (DLADM_STATUS_BADARG); + + writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; + writeconf.ld_conf = conf; + rsize = sizeof (retval); + + status = dladm_door_call(&writeconf, sizeof (writeconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Given a link ID and a key, get the matching information from + * data link configuration repository. + */ +dladm_status_t +dladm_get_conf_field(dladm_conf_t conf, const char *attr, void *attrval, + size_t attrsz) +{ + dlmgmt_door_getattr_t getattr; + dlmgmt_getattr_retval_t *retvalp; + dladm_status_t status = DLADM_STATUS_OK; + size_t oldsize, size; + + if (conf == DLADM_INVALID_CONF || attrval == NULL || + attrsz == 0 || attr == NULL || *attr == '\0') { + return (DLADM_STATUS_BADARG); + } + + getattr.ld_cmd = DLMGMT_CMD_GETATTR; + getattr.ld_conf = conf; + (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); + + oldsize = size = attrsz + sizeof (dlmgmt_getattr_retval_t) - 1; + if ((retvalp = calloc(1, oldsize)) == NULL) + return (DLADM_STATUS_NOMEM); + + status = dladm_door_call(&getattr, sizeof (getattr), retvalp, &size); + if (status != DLADM_STATUS_OK) + goto done; + + assert(size <= oldsize); + size = size + 1 - sizeof (dlmgmt_getattr_retval_t); + bcopy(retvalp->lr_attr, attrval, size); +done: + free(retvalp); + return (status); +} + +/* + * Get the link ID that is associated with the given name. + */ +dladm_status_t +dladm_name2info(const char *link, datalink_id_t *linkidp, uint32_t *flagp, + datalink_class_t *classp, uint32_t *mediap) +{ + dlmgmt_door_getlinkid_t getlinkid; + dlmgmt_getlinkid_retval_t retval; + datalink_id_t linkid; + size_t rsize; + dladm_status_t status; + + getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; + (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + status = dladm_door_call(&getlinkid, sizeof (getlinkid), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + linkid = retval.lr_linkid; + if (retval.lr_class == DATALINK_CLASS_PHYS && + retval.lr_flags & DLMGMT_ACTIVE) { + /* + * An active physical link reported by the dlmgmtd daemon + * might not be active anymore. Check and set its real status. + */ + status = i_dladm_phys_status(linkid, &retval.lr_flags); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (linkidp != NULL) + *linkidp = linkid; + if (flagp != NULL) { + *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; + *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? + DLADM_OPT_PERSIST : 0; + } + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + + return (DLADM_STATUS_OK); +} + +/* + * Get the link name that is associated with the given id. + */ +dladm_status_t +dladm_datalink_id2info(datalink_id_t linkid, uint32_t *flagp, + datalink_class_t *classp, uint32_t *mediap, char *link, size_t len) +{ + dlmgmt_door_getname_t getname; + dlmgmt_getname_retval_t retval; + size_t rsize; + dladm_status_t status; + + if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || + (link == NULL && len != 0)) { + return (DLADM_STATUS_BADARG); + } + + getname.ld_cmd = DLMGMT_CMD_GETNAME; + getname.ld_linkid = linkid; + rsize = sizeof (retval); + status = dladm_door_call(&getname, sizeof (getname), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if ((rsize != sizeof (retval)) || + (len != 0 && (strlen(retval.lr_link) + 1 > len))) { + return (DLADM_STATUS_TOOSMALL); + } + + if (retval.lr_class == DATALINK_CLASS_PHYS && + retval.lr_flags & DLMGMT_ACTIVE) { + /* + * An active physical link reported by the dlmgmtd daemon + * might not be active anymore. Check and set its real status. + */ + status = i_dladm_phys_status(linkid, &retval.lr_flags); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (link != NULL) + (void) strlcpy(link, retval.lr_link, len); + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + if (flagp != NULL) { + *flagp = retval.lr_flags & DLMGMT_ACTIVE ? + DLADM_OPT_ACTIVE : 0; + *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? + DLADM_OPT_PERSIST : 0; + } + return (DLADM_STATUS_OK); +} + +/* + * Set the given attr with the given attrval for the given link. + */ +dladm_status_t +dladm_set_conf_field(dladm_conf_t conf, const char *attr, + dladm_datatype_t type, const void *attrval) +{ + dlmgmt_door_setattr_t *setattrp; + dlmgmt_setattr_retval_t retval; + dladm_status_t status; + size_t asize, attrsz, rsize; + + if (attr == NULL || attr == '\0' || attrval == NULL) + return (DLADM_STATUS_BADARG); + + if (type == DLADM_TYPE_STR) + attrsz = strlen(attrval) + 1; + else + attrsz = dladm_datatype_size[type]; + + asize = sizeof (dlmgmt_door_setattr_t) + attrsz - 1; + if ((setattrp = calloc(1, asize)) == NULL) + return (DLADM_STATUS_NOMEM); + + setattrp->ld_cmd = DLMGMT_CMD_SETATTR; + setattrp->ld_conf = conf; + (void) strlcpy(setattrp->ld_attr, attr, MAXLINKATTRLEN); + setattrp->ld_attrsz = attrsz; + setattrp->ld_type = type; + bcopy(attrval, &setattrp->ld_attrval, attrsz); + rsize = sizeof (retval); + + status = dladm_door_call(setattrp, asize, &retval, &rsize); + if (status != DLADM_STATUS_OK) + goto done; + + if (rsize != sizeof (retval)) + status = DLADM_STATUS_BADARG; + +done: + free(setattrp); + return (status); +} + +/* + * Unset the given attr the given link. + */ +dladm_status_t +dladm_unset_conf_field(dladm_conf_t conf, const char *attr) +{ + dlmgmt_door_unsetattr_t unsetattr; + dlmgmt_unsetattr_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (attr == NULL || attr == '\0') + return (DLADM_STATUS_BADARG); + + unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; + unsetattr.ld_conf = conf; + (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); + rsize = sizeof (retval); + + status = dladm_door_call(&unsetattr, sizeof (unsetattr), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Remove the given link ID and its entry from the data link configuration + * repository. + */ +dladm_status_t +dladm_remove_conf(datalink_id_t linkid) +{ + dlmgmt_door_removeconf_t removeconf; + dlmgmt_removeconf_retval_t retval; + size_t rsize; + dladm_status_t status; + + removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; + removeconf.ld_linkid = linkid; + rsize = sizeof (retval); + + status = dladm_door_call(&removeconf, sizeof (removeconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Free the contents of the link structure. + */ +void +dladm_destroy_conf(dladm_conf_t conf) +{ + dlmgmt_door_destroyconf_t destroyconf; + dlmgmt_destroyconf_retval_t retval; + size_t rsize; + + if (conf == DLADM_INVALID_CONF) + return; + + destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; + destroyconf.ld_conf = conf; + rsize = sizeof (retval); + + (void) dladm_door_call(&destroyconf, sizeof (destroyconf), &retval, + &rsize); +} |