2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <assert.h>
2N/A#include <door.h>
2N/A#include <errno.h>
2N/A#include <fcntl.h>
2N/A#include <libdladm_impl.h>
2N/A#include <libdladm.h>
2N/A#include <libdlflow_impl.h>
2N/A#include <libdlflow.h>
2N/A#include <libdllink.h>
2N/A#include <libdlmgmt.h>
2N/A#include <libnwam.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <sys/aggr.h>
2N/A#include <sys/mman.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/types.h>
2N/A#include <unistd.h>
2N/A#include <zone.h>
2N/A
2N/A/*
2N/A * Table of data type sizes indexed by dladm_datatype_t.
2N/A */
2N/Astatic size_t dladm_datatype_size[] = {
2N/A 0, /* DLADM_TYPE_STR, use strnlen() */
2N/A sizeof (boolean_t), /* DLADM_TYPE_BOOLEAN */
2N/A sizeof (uint64_t) /* DLADM_TYPE_UINT64 */
2N/A};
2N/A
2N/Astatic dladm_status_t
2N/Adladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf,
2N/A size_t *rsizep)
2N/A{
2N/A door_arg_t darg;
2N/A int door_fd;
2N/A dladm_status_t status;
2N/A boolean_t reopen = B_FALSE;
2N/A
2N/A darg.data_ptr = arg;
2N/A darg.data_size = asize;
2N/A darg.desc_ptr = NULL;
2N/A darg.desc_num = 0;
2N/A darg.rbuf = rbuf;
2N/A darg.rsize = *rsizep;
2N/A
2N/Areopen:
2N/A /* The door descriptor is opened if it isn't already */
2N/A if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A if (door_call(door_fd, &darg) == -1) {
2N/A /*
2N/A * Stale door descriptor is possible if dlmgmtd was re-started
2N/A * since last door_fd open so try re-opening door file.
2N/A */
2N/A if (!reopen && errno == EBADF) {
2N/A (void) close(handle->door_fd);
2N/A handle->door_fd = -1;
2N/A reopen = B_TRUE;
2N/A goto reopen;
2N/A }
2N/A status = dladm_errno2status(errno);
2N/A }
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A if (darg.rbuf != rbuf) {
2N/A /*
2N/A * The size of the input rbuf is not big enough so that
2N/A * the door allocate the rbuf itself. In this case, return
2N/A * the required size to the caller.
2N/A */
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A *rsizep = darg.rsize;
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A } else if (darg.rsize != *rsizep) {
2N/A return (DLADM_STATUS_FAILED);
2N/A }
2N/A
2N/A return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err));
2N/A}
2N/A
2N/A/*
2N/A * Allocate a new linkid with the given name for the given zone.
2N/A * Return the new linkid.
2N/A */
2N/Adladm_status_t
2N/Adladm_create_datalink_id_zone(dladm_handle_t handle, const char *link,
2N/A datalink_class_t class, uint32_t media, uint32_t flags,
2N/A zoneid_t zoneid, datalink_id_t *linkidp)
2N/A{
2N/A dlmgmt_door_createid_t createid;
2N/A dlmgmt_createid_retval_t retval;
2N/A uint32_t dlmgmt_flags;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (link == NULL || class == DATALINK_CLASS_ALL ||
2N/A !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST |
2N/A DLADM_OPT_AUTOVNIC)) || linkidp == NULL) {
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A
2N/A dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
2N/A dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0;
2N/A dlmgmt_flags |= ((flags & DLADM_OPT_AUTOVNIC) ? DLMGMT_AUTOVNIC: 0);
2N/A
2N/A (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN);
2N/A createid.ld_class = class;
2N/A createid.ld_media = media;
2N/A createid.ld_flags = dlmgmt_flags;
2N/A createid.ld_zoneid = zoneid;
2N/A createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID;
2N/A createid.ld_prefix = (flags & DLADM_OPT_PREFIX);
2N/A
2N/A if ((status = dladm_door_call(handle, &createid, sizeof (createid),
2N/A &retval, &sz)) == DLADM_STATUS_OK) {
2N/A *linkidp = retval.lr_linkid;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Allocate a new linkid with the given name. Return the new linkid.
2N/A */
2N/Adladm_status_t
2N/Adladm_create_datalink_id(dladm_handle_t handle, const char *link,
2N/A datalink_class_t class, uint32_t media, uint32_t flags,
2N/A datalink_id_t *linkidp)
2N/A{
2N/A return (dladm_create_datalink_id_zone(handle, link, class,
2N/A media, flags, getzoneid(), linkidp));
2N/A}
2N/A
2N/A/*
2N/A * Destroy the given link ID.
2N/A */
2N/Adladm_status_t
2N/Adladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint32_t flags)
2N/A{
2N/A dlmgmt_door_destroyid_t destroyid;
2N/A dlmgmt_destroyid_retval_t retval;
2N/A uint32_t dlmgmt_flags;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
2N/A dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
2N/A
2N/A destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID;
2N/A destroyid.ld_linkid = linkid;
2N/A destroyid.ld_flags = dlmgmt_flags;
2N/A
2N/A return (dladm_door_call(handle, &destroyid, sizeof (destroyid),
2N/A &retval, &sz));
2N/A}
2N/A
2N/A/*
2N/A * Remap a given link ID to a new name.
2N/A */
2N/Adladm_status_t
2N/Adladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
2N/A const char *link)
2N/A{
2N/A dlmgmt_door_remapid_t remapid;
2N/A dlmgmt_remapid_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID;
2N/A (void) strlcpy(remapid.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A remapid.ld_linkid = linkid;
2N/A (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN);
2N/A
2N/A return (dladm_door_call(handle, &remapid, sizeof (remapid),
2N/A &retval, &sz));
2N/A}
2N/A
2N/A/*
2N/A * Make a given link ID active.
2N/A */
2N/Adladm_status_t
2N/Adladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A dlmgmt_door_upid_t upid;
2N/A dlmgmt_upid_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A upid.ld_cmd = DLMGMT_CMD_UP_LINKID;
2N/A upid.ld_linkid = linkid;
2N/A
2N/A return (dladm_door_call(handle, &upid, sizeof (upid), &retval, &sz));
2N/A}
2N/A
2N/A/*
2N/A * Create a new link with the given name. Return the new link's handle
2N/A */
2N/Adladm_status_t
2N/Adladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid,
2N/A datalink_class_t class, uint32_t media, dladm_conf_t *confp)
2N/A{
2N/A dlmgmt_door_createconf_t createconf;
2N/A dlmgmt_createconf_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (link == NULL || confp == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN);
2N/A createconf.ld_class = class;
2N/A createconf.ld_media = media;
2N/A createconf.ld_linkid = linkid;
2N/A createconf.ld_cmd = DLMGMT_CMD_CREATECONF;
2N/A confp->ds_confid = DLADM_INVALID_CONF;
2N/A
2N/A if ((status = dladm_door_call(handle, &createconf, sizeof (createconf),
2N/A &retval, &sz)) == DLADM_STATUS_OK) {
2N/A confp->ds_readonly = B_FALSE;
2N/A confp->ds_confid = retval.lr_confid;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Adladm_get_flow_prop(dladm_handle_t handle, const char *flow, zoneid_t zoneid,
2N/A mac_resource_props_t *flow_prop)
2N/A{
2N/A uint64_t uint_attrval;
2N/A dladm_status_t s;
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FMAXBW, zoneid,
2N/A &uint_attrval, sizeof (uint_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK) {
2N/A flow_prop->mrp_maxbw = uint_attrval;
2N/A flow_prop->mrp_mask |= MRP_MAXBW;
2N/A }
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Adladm_get_flow_desc(dladm_handle_t handle, const char *flow, zoneid_t zoneid,
2N/A flow_desc_t *flow_desc)
2N/A{
2N/A uint64_t uint_attrval = 0;
2N/A char str_attrval[MAXOBJATTRVALLEN];
2N/A dladm_status_t s;
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FDSFIELD, zoneid,
2N/A &uint_attrval, sizeof (uint_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A
2N/A if (s == DLADM_STATUS_OK) {
2N/A bcopy(&uint_attrval, &flow_desc->fd_dsfield, 1);
2N/A flow_desc->fd_mask |= FLOW_IP_DSFIELD;
2N/A }
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FDSFIELD_MASK, zoneid,
2N/A &uint_attrval, sizeof (uint_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK)
2N/A bcopy(&uint_attrval, &flow_desc->fd_dsfield_mask, 1);
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FLOCAL_IP_ADDR, zoneid,
2N/A str_attrval, sizeof (str_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK) {
2N/A (void) dladm_check_ip_addr(str_attrval, B_TRUE, flow_desc);
2N/A flow_desc->fd_mask |= FLOW_IP_LOCAL;
2N/A }
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FREMOTE_IP_ADDR, zoneid,
2N/A str_attrval, sizeof (str_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK) {
2N/A (void) dladm_check_ip_addr(str_attrval, B_FALSE, flow_desc);
2N/A flow_desc->fd_mask |= FLOW_IP_REMOTE;
2N/A }
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FTRANSPORT, zoneid,
2N/A &uint_attrval, sizeof (uint_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK) {
2N/A flow_desc->fd_protocol = uint_attrval;
2N/A flow_desc->fd_mask |= FLOW_IP_PROTOCOL;
2N/A }
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FLOCAL_PORT, zoneid,
2N/A &uint_attrval, sizeof (uint_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK) {
2N/A flow_desc->fd_local_port = uint_attrval;
2N/A flow_desc->fd_mask |= FLOW_ULP_PORT_LOCAL;
2N/A }
2N/A
2N/A s = dladm_get_flowconf_field(handle, flow, FREMOTE_PORT, zoneid,
2N/A &uint_attrval, sizeof (uint_attrval));
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A if (s == DLADM_STATUS_OK) {
2N/A flow_desc->fd_remote_port = uint_attrval;
2N/A flow_desc->fd_mask |= FLOW_ULP_PORT_REMOTE;
2N/A }
2N/A return (s == DLADM_STATUS_NOTFOUND ? DLADM_STATUS_OK : s);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_get_persist_flow(dladm_handle_t handle, const char *flow,
2N/A dladm_flow_attr_t *attr, int *ret_err)
2N/A{
2N/A dlmgmt_door_readflowconf_t flow_entry;
2N/A dlmgmt_readflowconf_retval_t retval;
2N/A dladm_status_t status, s = DLADM_STATUS_OK;
2N/A size_t sz = sizeof (retval);
2N/A char fname[MAXFLOWNAMELEN];
2N/A char zname[ZONENAME_MAX];
2N/A zoneid_t zoneid;
2N/A
2N/A bzero(fname, MAXFLOWNAMELEN);
2N/A bzero(zname, ZONENAME_MAX);
2N/A flow_entry.ld_cmd = DLMGMT_CMD_READFLOWCONF;
2N/A flow_entry.ld_zoneid = zoneid = dladm_extra_names(flow, fname, zname);
2N/A (void) strlcpy(flow_entry.ld_flow, fname, sizeof (flow_entry.ld_flow));
2N/A
2N/A if ((status = dladm_door_call(handle, &flow_entry, sizeof (flow_entry),
2N/A &retval, &sz)) == DLADM_STATUS_OK) {
2N/A char str_attrval[MAXOBJATTRVALLEN];
2N/A
2N/A *ret_err = retval.lr_err;
2N/A if (*ret_err != 0)
2N/A return (dladm_errno2status(errno));
2N/A (void) strlcpy(attr->fa_flowname, flow, MAXFLOWNAMELEN);
2N/A attr->fa_flow_desc.fd_zoneid = zoneid;
2N/A
2N/A /* get LINKOVER property, this is a must prop */
2N/A status = dladm_get_flowconf_field(handle, fname, FLINKOVER,
2N/A zoneid, str_attrval, sizeof (str_attrval));
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A /*
2N/A * returned status ignored, cause it is ok that the underline
2N/A * link is missing.
2N/A */
2N/A (void) dladm_name2info(handle, str_attrval,
2N/A &attr->fa_linkid, NULL, NULL, NULL);
2N/A
2N/A /*
2N/A * Get flow_desc and mac_resource, these props don't have to
2N/A * set. So NOTFOUND is ok.
2N/A */
2N/A s = dladm_get_flow_prop(handle, fname, zoneid,
2N/A &attr->fa_resource_props);
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A
2N/A s = dladm_get_flow_desc(handle, fname, zoneid,
2N/A &attr->fa_flow_desc);
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A }
2N/A
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A else
2N/A return (s == DLADM_STATUS_NOTFOUND ? DLADM_STATUS_OK : s);
2N/A}
2N/A
2N/A/* get the flowconf who is next to the "flowname" flow */
2N/Adladm_status_t
2N/Adladm_get_flownext(dladm_handle_t handle, const char *flowname, zoneid_t zoneid,
2N/A dld_flowinfo_t *flowinfo, int *ret_err)
2N/A{
2N/A dlmgmt_door_flowgetnext_t flow_next;
2N/A dlmgmt_flowgetnext_retval_t retval;
2N/A dladm_status_t status, s = DLADM_STATUS_OK;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A flow_next.ld_cmd = DLMGMT_CMD_FLOWGETNEXT;
2N/A (void) strlcpy(flow_next.ld_flow, flowname, sizeof (flow_next.ld_flow));
2N/A flow_next.ld_zoneid = zoneid;
2N/A
2N/A if ((status = dladm_door_call(handle, &flow_next, sizeof (flow_next),
2N/A &retval, &sz)) == DLADM_STATUS_OK) {
2N/A char str_attrval[MAXOBJATTRVALLEN];
2N/A
2N/A *ret_err = retval.lr_err;
2N/A if (*ret_err != 0)
2N/A return (dladm_errno2status(errno));
2N/A (void) strlcpy(flowinfo->fi_flowname, retval.lr_name,
2N/A MAXFLOWNAMELEN);
2N/A flowinfo->fi_flow_desc.fd_zoneid = retval.lr_zoneid;
2N/A flowinfo->fi_linkid = retval.lr_linkid;
2N/A
2N/A /* get LINKOVER property, this is a must prop */
2N/A status = dladm_get_flowconf_field(handle, retval.lr_name,
2N/A FLINKOVER, retval.lr_zoneid, str_attrval,
2N/A sizeof (str_attrval));
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A (void) dladm_name2info(handle, str_attrval,
2N/A &flowinfo->fi_linkid, NULL, NULL, NULL);
2N/A
2N/A /*
2N/A * Get flow_desc and mac_resource, these props don't have to
2N/A * set. So NOTFOUND is ok.
2N/A */
2N/A s = dladm_get_flow_prop(handle, retval.lr_name,
2N/A retval.lr_zoneid, &flowinfo->fi_resource_props);
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A
2N/A s = dladm_get_flow_desc(handle, retval.lr_name,
2N/A retval.lr_zoneid, &flowinfo->fi_flow_desc);
2N/A if (s != DLADM_STATUS_OK && s != DLADM_STATUS_NOTFOUND)
2N/A return (s);
2N/A }
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A else
2N/A return (s == DLADM_STATUS_NOTFOUND ? DLADM_STATUS_OK : s);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_create_flowconf(dladm_handle_t handle, const char *flow,
2N/A datalink_id_t linkid)
2N/A{
2N/A dlmgmt_door_createflowconf_t flow_conf;
2N/A dlmgmt_createflowconf_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (flow == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A flow_conf.ld_cmd = DLMGMT_CMD_CREATEFLOWCONF;
2N/A (void) strlcpy(flow_conf.ld_flow, flow, MAXFLOWNAMELEN);
2N/A flow_conf.ld_linkid = linkid;
2N/A status = dladm_door_call(handle, &flow_conf, sizeof (flow_conf),
2N/A &retval, &sz);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * An active physical link reported by the dlmgmtd daemon might not be active
2N/A * anymore as this link might be removed during system shutdown. Check its
2N/A * real status by calling dladm_phys_info().
2N/A */
2N/Adladm_status_t
2N/Ai_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint32_t *flagsp)
2N/A{
2N/A dladm_phys_attr_t dpa;
2N/A dladm_status_t status;
2N/A
2N/A assert((*flagsp) & DLMGMT_ACTIVE);
2N/A
2N/A status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE);
2N/A if (status == DLADM_STATUS_NOTFOUND) {
2N/A /*
2N/A * No active status, this link was removed. Update its status
2N/A * in the daemon and delete all active linkprops.
2N/A *
2N/A * Note that the operation could fail. If it does, return
2N/A * failure now since otherwise dladm_set_linkprop() might
2N/A * call back to i_dladm_phys_status() recursively.
2N/A */
2N/A if ((status = dladm_destroy_datalink_id(handle, linkid,
2N/A DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
2N/A DLADM_OPT_ACTIVE);
2N/A
2N/A (*flagsp) &= ~DLMGMT_ACTIVE;
2N/A status = DLADM_STATUS_OK;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Utility function to search for a zone ID in an array of zone IDs.
2N/A */
2N/Adladm_status_t
2N/Adladm_search_zonelist(zoneid_t zid, uint32_t zonecnt, zoneid_t *zonelist)
2N/A{
2N/A int idx;
2N/A
2N/A for (idx = 0; idx < zonecnt; idx++) {
2N/A if (zonelist[idx] == zid)
2N/A return (DLADM_STATUS_OK);
2N/A }
2N/A
2N/A return (DLADM_STATUS_NOTFOUND);
2N/A}
2N/A
2N/Astatic void
2N/Ai_dladm_init_linkinfo(dladm_datalink_info_t *di, datalink_id_t linkid,
2N/A const char *linkname, uint32_t flags, datalink_class_t class,
2N/A uint32_t media, zoneid_t zoneid)
2N/A{
2N/A di->di_linkid = linkid;
2N/A assert(sizeof (di->di_linkname) > strlen(linkname));
2N/A (void) strcpy(di->di_linkname, linkname);
2N/A di->di_class = class;
2N/A di->di_media = media;
2N/A di->di_flags = flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0;
2N/A di->di_flags |= (flags & DLMGMT_PERSIST) ? DLADM_OPT_PERSIST : 0;
2N/A di->di_zoneid = zoneid;
2N/A}
2N/A
2N/A/*
2N/A * Walk each entry in the data link configuration repository and
2N/A * call fn on the linkid and arg. Caller must supply one of the
2N/A * two callback fns. The first callback fn is called for each
2N/A * datalink along with the datalink ID argument, the second callback
2N/A * is called with datalink ID and the name of the datalink.
2N/A */
2N/Astatic dladm_status_t
2N/Adladm_walk_datalink_common(datalink_id_t linkid, int (*fn)(dladm_handle_t,
2N/A datalink_id_t, void *), dladm_walk_datalink_cb_t *fn2, dladm_handle_t
2N/A handle, void *argp, datalink_class_t class, datalink_media_t dmedia,
2N/A uint32_t flags, uint32_t zonecnt, zoneid_t *zonelist)
2N/A{
2N/A dlmgmt_door_getnext_t getnext;
2N/A dlmgmt_getnext_retval_t retval;
2N/A uint32_t dlmgmt_flags;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A dladm_datalink_info_t di;
2N/A size_t sz = sizeof (retval);
2N/A zoneid_t caller_zone = getzoneid();
2N/A
2N/A if (fn == NULL && fn2 == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (fn != NULL && fn2 != NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (linkid != DATALINK_ALL_LINKID) {
2N/A assert(fn == NULL && fn2 != NULL);
2N/A di.di_linkid = linkid;
2N/A status = dladm_datalink_id2linkinfo(handle, di.di_linkid,
2N/A &di.di_flags, &di.di_class, &di.di_media, di.di_linkname,
2N/A sizeof (di.di_linkname), &di.di_zoneid);
2N/A if (status == DLADM_STATUS_OK)
2N/A (void) fn2(handle, &di, argp);
2N/A return (status);
2N/A }
2N/A
2N/A dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
2N/A dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
2N/A dlmgmt_flags |= ((flags & DLADM_OPT_ALLZONES) ? DLMGMT_ALLZONES: 0);
2N/A
2N/A getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
2N/A getnext.ld_class = class;
2N/A getnext.ld_dmedia = dmedia;
2N/A getnext.ld_flags = dlmgmt_flags;
2N/A getnext.ld_zoneprefix = B_TRUE;
2N/A
2N/A do {
2N/A getnext.ld_linkid = linkid;
2N/A if ((status = dladm_door_call(handle, &getnext,
2N/A sizeof (getnext), &retval, &sz)) != DLADM_STATUS_OK) {
2N/A /*
2N/A * Done with walking. If no next datalink is found,
2N/A * return success.
2N/A */
2N/A if (status == DLADM_STATUS_NOTFOUND)
2N/A status = DLADM_STATUS_OK;
2N/A break;
2N/A }
2N/A linkid = retval.lr_linkid;
2N/A if ((retval.lr_class == DATALINK_CLASS_PHYS) &&
2N/A (retval.lr_flags & DLMGMT_ACTIVE)) {
2N/A /*
2N/A * An active physical link reported by the dlmgmtd
2N/A * daemon might not be active anymore. Check its
2N/A * real status.
2N/A */
2N/A if (i_dladm_phys_status(handle, linkid,
2N/A &retval.lr_flags) != DLADM_STATUS_OK) {
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * Skip to next link now if we are only looking
2N/A * for active links.
2N/A */
2N/A if (!(dlmgmt_flags & retval.lr_flags))
2N/A continue;
2N/A }
2N/A
2N/A if (fn != NULL) {
2N/A if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE)
2N/A break;
2N/A continue;
2N/A }
2N/A
2N/A i_dladm_init_linkinfo(&di, linkid, retval.lr_link,
2N/A retval.lr_flags, retval.lr_class, retval.lr_media,
2N/A retval.lr_zoneid);
2N/A /*
2N/A * If datalink is on loan to a NGZ then we have to call
2N/A * the callback twice, with and without a zonename prefix.
2N/A */
2N/A if (retval.lr_onloan && caller_zone == GLOBAL_ZONEID) {
2N/A assert(retval.lr_zoneid != GLOBAL_ZONEID);
2N/A
2N/A /*
2N/A * First check if we should use the non-prefixed link
2N/A * name that is associated with the global zone.
2N/A */
2N/A if ((zonecnt == 0 ||
2N/A (dladm_search_zonelist(GLOBAL_ZONEID, zonecnt,
2N/A zonelist) == DLADM_STATUS_OK)) && fn2(handle,
2N/A &di, argp) == DLADM_WALK_TERMINATE)
2N/A break;
2N/A
2N/A (void) strcpy(di.di_linkname, retval.lr_zoneprefixlink);
2N/A
2N/A /*
2N/A * Next, check if we should use the prefixed link name
2N/A * that is loaned to the non-global zone.
2N/A */
2N/A if ((zonecnt == 0 ||
2N/A (dladm_search_zonelist(retval.lr_zoneid, zonecnt,
2N/A zonelist) == DLADM_STATUS_OK)) && fn2(handle,
2N/A &di, argp) == DLADM_WALK_TERMINATE)
2N/A break;
2N/A } else {
2N/A /*
2N/A * For all other datalinks first check if -z option was
2N/A * used the datalink is part of the given -z option
2N/A * zone list.
2N/A */
2N/A if (zonecnt > 0 &&
2N/A dladm_search_zonelist(retval.lr_zoneid, zonecnt,
2N/A zonelist) != DLADM_STATUS_OK)
2N/A continue;
2N/A
2N/A (void) strcpy(di.di_linkname, retval.lr_zoneprefixlink);
2N/A
2N/A if (fn2(handle, &di, argp) == DLADM_WALK_TERMINATE)
2N/A break;
2N/A }
2N/A } while (linkid != DATALINK_INVALID_LINKID);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Datalink walker function that requires the callback function to
2N/A * accept a datalink information structure. This walker should be
2N/A * used when printing out datalink names as datalinks in non-global
2N/A * zones are displayed in the global zone with a zonename prefix.
2N/A */
2N/Adladm_status_t
2N/Adladm_walk_datalinks(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_walk_datalink_cb_t *fn, void *argp, datalink_class_t class,
2N/A datalink_media_t dmedia, uint32_t flags, uint32_t zonecnt,
2N/A zoneid_t *zonelist)
2N/A{
2N/A return (dladm_walk_datalink_common(linkid, NULL, fn, handle, argp,
2N/A class, dmedia, flags, zonecnt, zonelist));
2N/A}
2N/A
2N/A/*
2N/A * Walk each physical device present on the system in order based on the
2N/A * relative locations of the physical devices, calling fn() and passing in
2N/A * argp. Walk is possible only for active config. DLADM_OPT_FORCE is
2N/A * supported but optional). Attributes are walked in order determined by
2N/A * their current relative physical locations.
2N/A */
2N/Adladm_status_t
2N/Adladm_walk_phys_info(dladm_handle_t handle,
2N/A int (*fn)(dladm_handle_t, datalink_id_t, dladm_phys_attr_t *, void *),
2N/A void *argp, uint32_t flags)
2N/A{
2N/A dlmgmt_door_getnextphysattr_t getnext;
2N/A dlmgmt_getnextphysattr_retval_t retval;
2N/A dladm_status_t status;
2N/A dladm_phys_attr_t dpa;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A assert((flags & ~(DLADM_OPT_ACTIVE|DLADM_OPT_FORCE)) == 0);
2N/A
2N/A getnext.ld_cmd = DLMGMT_CMD_GETNEXTPHYSATTR;
2N/A getnext.ld_dev[0] = '\0';
2N/A getnext.ld_flags = flags;
2N/A
2N/A do {
2N/A if ((status = dladm_door_call(handle, &getnext,
2N/A sizeof (getnext), &retval, &sz)) != DLADM_STATUS_OK) {
2N/A /*
2N/A * Done with walking. If no next device is found,
2N/A * return success.
2N/A */
2N/A if (status == DLADM_STATUS_NOTFOUND)
2N/A status = DLADM_STATUS_OK;
2N/A break;
2N/A }
2N/A /*
2N/A * "force" option is only needed for initial door call to
2N/A * refresh physical location data.
2N/A */
2N/A getnext.ld_flags = flags & ~DLADM_OPT_FORCE;
2N/A status = dladm_phys_info(handle, retval.lr_linkid, &dpa,
2N/A getnext.ld_flags);
2N/A switch (status) {
2N/A case DLADM_STATUS_OK:
2N/A if (fn != NULL && fn(handle, retval.lr_linkid, &dpa,
2N/A argp) == DLADM_WALK_TERMINATE)
2N/A return (status);
2N/A break;
2N/A case DLADM_STATUS_NOTFOUND:
2N/A /* Device may have been removed */
2N/A break;
2N/A default:
2N/A return (status);
2N/A }
2N/A (void) strlcpy(getnext.ld_dev, retval.lr_dev,
2N/A sizeof (getnext.ld_dev));
2N/A } while (strlen(getnext.ld_dev) > 0);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Reinitialize physical links.
2N/A */
2N/Adladm_status_t
2N/Adladm_reinit_phys(dladm_handle_t handle, const char *phys_prefix)
2N/A{
2N/A dlmgmt_door_reinit_phys_t reinit;
2N/A dlmgmt_reinit_phys_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A reinit.ld_cmd = DLMGMT_CMD_REINIT_PHYS;
2N/A (void) strlcpy(reinit.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A if (phys_prefix == NULL) {
2N/A reinit.ld_phys_prefix[0] = '\0';
2N/A } else {
2N/A (void) strlcpy(reinit.ld_phys_prefix, phys_prefix,
2N/A MAXLINKNAMELEN);
2N/A }
2N/A return (dladm_door_call(handle, &reinit, sizeof (reinit),
2N/A &retval, &sz));
2N/A}
2N/A
2N/A/*
2N/A * check if given flow exists
2N/A */
2N/Adladm_status_t
2N/Adladm_read_flowconf(dladm_handle_t handle, const char *name,
2N/A boolean_t *onloan)
2N/A{
2N/A dlmgmt_door_readflowconf_t flowconf;
2N/A dlmgmt_readflowconf_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A char zname[ZONENAME_MAX];
2N/A char fname[MAXFLOWNAMELEN];
2N/A
2N/A if (name[0] == '\0')
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A bzero(zname, ZONENAME_MAX);
2N/A bzero(fname, MAXFLOWNAMELEN);
2N/A flowconf.ld_zoneid = dladm_extra_names(name, fname, zname);
2N/A (void) strlcpy(flowconf.ld_flow, fname, MAXFLOWNAMELEN);
2N/A flowconf.ld_cmd = DLMGMT_CMD_READFLOWCONF;
2N/A
2N/A status = dladm_door_call(handle, &flowconf, sizeof (flowconf),
2N/A &retval, &sz);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A if (onloan != NULL)
2N/A *onloan = retval.lr_onloan;
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Walk each entry in the data link configuration repository and
2N/A * call fn on the linkid and arg.
2N/A */
2N/Adladm_status_t
2N/Adladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *),
2N/A dladm_handle_t handle, void *argp, datalink_class_t class,
2N/A datalink_media_t dmedia, uint32_t flags)
2N/A{
2N/A return (dladm_walk_datalink_common(DATALINK_ALL_LINKID, fn, NULL,
2N/A handle, argp, class, dmedia, flags, 0, NULL));
2N/A}
2N/A
2N/A/*
2N/A * Get a handle of a copy of the link configuration (kept in the daemon)
2N/A * for the given link so it can be updated later by dladm_write_conf().
2N/A */
2N/Adladm_status_t
2N/Adladm_open_conf(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_conf_t *confp)
2N/A{
2N/A dlmgmt_door_openconf_t openconf;
2N/A dlmgmt_openconf_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz;
2N/A
2N/A if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A sz = sizeof (retval);
2N/A openconf.ld_linkid = linkid;
2N/A openconf.ld_cmd = DLMGMT_CMD_OPENCONF;
2N/A confp->ds_confid = DLADM_INVALID_CONF;
2N/A if ((status = dladm_door_call(handle, &openconf,
2N/A sizeof (openconf), &retval, &sz)) == DLADM_STATUS_OK) {
2N/A confp->ds_readonly = B_FALSE;
2N/A confp->ds_confid = retval.lr_confid;
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Get the handle of a local snapshot of the link configuration. Note that
2N/A * any operations with this handle are read-only, i.e., one can not update
2N/A * the configuration with this handle.
2N/A */
2N/Adladm_status_t
2N/Adladm_getsnap_conf(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_conf_t *confp)
2N/A{
2N/A dlmgmt_door_getconfsnapshot_t snapshot;
2N/A dlmgmt_getconfsnapshot_retval_t *retvalp;
2N/A char *nvlbuf;
2N/A dladm_status_t status;
2N/A int err;
2N/A size_t sz;
2N/A
2N/A if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A sz = sizeof (dlmgmt_getconfsnapshot_retval_t);
2N/A snapshot.ld_linkid = linkid;
2N/A snapshot.ld_cmd = DLMGMT_CMD_GETCONFSNAPSHOT;
2N/Aagain:
2N/A if ((retvalp = malloc(sz)) == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A if ((status = dladm_door_call(handle, &snapshot, sizeof (snapshot),
2N/A retvalp, &sz)) == DLADM_STATUS_TOOSMALL) {
2N/A free(retvalp);
2N/A goto again;
2N/A }
2N/A
2N/A if (status != DLADM_STATUS_OK) {
2N/A free(retvalp);
2N/A return (status);
2N/A }
2N/A
2N/A confp->ds_readonly = B_TRUE;
2N/A nvlbuf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t);
2N/A if ((err = nvlist_unpack(nvlbuf, retvalp->lr_nvlsz,
2N/A &(confp->ds_nvl), NV_ENCODE_NATIVE)) != 0) {
2N/A status = dladm_errno2status(err);
2N/A }
2N/A free(retvalp);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Commit the given flow to the configuration repository so that it will
2N/A * persist across reboots.
2N/A */
2N/Adladm_status_t
2N/Adladm_write_flowconf(dladm_handle_t handle, const char *name, const char *root)
2N/A{
2N/A dlmgmt_door_writeflowconf_t flowconf;
2N/A dlmgmt_writeflowconf_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (name == NULL || name[0] == '\0')
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A bzero(&flowconf, sizeof (dlmgmt_door_writeflowconf_t));
2N/A flowconf.ld_cmd = DLMGMT_CMD_WRITEFLOWCONF;
2N/A (void) strlcpy(flowconf.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A (void) strlcpy(flowconf.ld_flow, name, MAXFLOWNAMELEN);
2N/A if (root != NULL)
2N/A (void) strlcpy(flowconf.ld_root, root, MAXPATHLEN);
2N/A
2N/A return (dladm_door_call(handle, &flowconf, sizeof (flowconf), &retval,
2N/A &sz));
2N/A}
2N/A
2N/A/*
2N/A * Return the underlying links for the link represented by the conf object.
2N/A * The caller MUST free the string that is returned.
2N/A */
2N/Astatic char *
2N/Ai_dladm_get_over_links(dladm_handle_t handle, dladm_conf_t conf,
2N/A datalink_class_t class)
2N/A{
2N/A char *prop, links[MAXLINKNAMELEN];
2N/A
2N/A /*
2N/A * Determine which property is used to store the underlying links for
2N/A * this link class.
2N/A */
2N/A switch (class) {
2N/A case DATALINK_CLASS_PHYS:
2N/A case DATALINK_CLASS_ETHERSTUB:
2N/A case DATALINK_CLASS_BRIDGE:
2N/A case DATALINK_CLASS_IPTUN:
2N/A return (NULL);
2N/A case DATALINK_CLASS_AGGR:
2N/A prop = FPORTS;
2N/A break;
2N/A case DATALINK_CLASS_SIMNET:
2N/A prop = FSIMNETPEER;
2N/A break;
2N/A case DATALINK_CLASS_VLAN:
2N/A case DATALINK_CLASS_VNIC:
2N/A case DATALINK_CLASS_PART:
2N/A prop = FLINKOVER;
2N/A break;
2N/A default:
2N/A return (NULL);
2N/A }
2N/A
2N/A /* Then, retrieve the links from that property */
2N/A if (dladm_get_conf_field(handle, conf, prop, links, sizeof (links))
2N/A != DLADM_STATUS_OK)
2N/A return (NULL);
2N/A
2N/A return (strdup(links));
2N/A}
2N/A
2N/A/*
2N/A * Commit the given link to the data link configuration repository so
2N/A * that it will persist across reboots.
2N/A */
2N/Adladm_status_t
2N/Adladm_write_conf(dladm_handle_t handle, dladm_conf_t conf, datalink_id_t linkid)
2N/A{
2N/A dlmgmt_door_writeconf_t writeconf;
2N/A dlmgmt_writeconf_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A dladm_status_t status;
2N/A datalink_class_t class;
2N/A char *overlinks, linkname[MAXLINKNAMELEN];
2N/A
2N/A if (conf.ds_confid == DLADM_INVALID_CONF)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (conf.ds_readonly)
2N/A return (DLADM_STATUS_DENIED);
2N/A
2N/A writeconf.ld_cmd = DLMGMT_CMD_WRITECONF;
2N/A (void) strlcpy(writeconf.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A writeconf.ld_confid = conf.ds_confid;
2N/A
2N/A status = dladm_door_call(handle, &writeconf, sizeof (writeconf),
2N/A &retval, &sz);
2N/A
2N/A /*
2N/A * If the door call to write the configuration is successful, send a
2N/A * door call to nwamd to read in this newly created configuration.
2N/A */
2N/A if (status == DLADM_STATUS_OK) {
2N/A if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
2N/A linkname, sizeof (linkname)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A /* find the links under this link for vnics, aggrs, etc. */
2N/A overlinks = i_dladm_get_over_links(handle, conf, class);
2N/A
2N/A nwam_ncu_external_action(NWAM_NCU_TYPE_LINK, linkname,
2N/A handle->dh_profile, overlinks, B_TRUE);
2N/A free(overlinks);
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Given a flow name and an attribute name, get the attribute value from
2N/A * flow configuration repository.
2N/A */
2N/Adladm_status_t
2N/Adladm_get_flowconf_field(dladm_handle_t handle, const char *flowname,
2N/A const char *attr, zoneid_t zoneid, void *attrval, size_t attrsz)
2N/A{
2N/A dlmgmt_door_getflowattr_t flowgetattr;
2N/A dlmgmt_getattr_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (flowname[0] == '\0' || attrval == NULL ||
2N/A attrsz == 0 || attr == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A flowgetattr.ld_cmd = DLMGMT_CMD_GETFLOWATTR;
2N/A flowgetattr.ld_zoneid = zoneid;
2N/A (void) strlcpy(flowgetattr.ld_flow, flowname, MAXFLOWNAMELEN);
2N/A (void) strlcpy(flowgetattr.ld_attr, attr, MAXOBJATTRLEN);
2N/A
2N/A if ((status = dladm_door_call(handle, &flowgetattr,
2N/A sizeof (flowgetattr), &retval, &sz)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A if (retval.lr_attrsz > attrsz)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Given a dladm_conf_t, get the specific configuration field
2N/A *
2N/A * If the specified dladm_conf_t is a read-only snapshot of the configuration,
2N/A * get a specific link propertie from that snapshot (nvl), otherwise, get
2N/A * the link protperty from the dlmgmtd daemon using the given confid.
2N/A */
2N/Adladm_status_t
2N/Adladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
2N/A void *attrval, size_t attrsz)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A
2N/A if (attrval == NULL || attrsz == 0 || attr == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (conf.ds_readonly) {
2N/A uchar_t *oattrval;
2N/A uint32_t oattrsz;
2N/A int err;
2N/A
2N/A if ((err = nvlist_lookup_byte_array(conf.ds_nvl, (char *)attr,
2N/A &oattrval, &oattrsz)) != 0) {
2N/A return (dladm_errno2status(err));
2N/A }
2N/A if (oattrsz > attrsz)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A bcopy(oattrval, attrval, oattrsz);
2N/A } else {
2N/A dlmgmt_door_getattr_t getattr;
2N/A dlmgmt_getattr_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (conf.ds_confid == DLADM_INVALID_CONF)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A getattr.ld_cmd = DLMGMT_CMD_GETATTR;
2N/A getattr.ld_confid = conf.ds_confid;
2N/A (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
2N/A
2N/A if ((status = dladm_door_call(handle, &getattr,
2N/A sizeof (getattr), &retval, &sz)) != DLADM_STATUS_OK) {
2N/A return (status);
2N/A }
2N/A
2N/A if (retval.lr_attrsz > attrsz)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Get next property attribute from data link configuration repository.
2N/A * If last_attr is "", return the first property.
2N/A */
2N/A/* ARGSUSED */
2N/Adladm_status_t
2N/Adladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf,
2N/A const char *last_attr, char *attr, void *attrval, size_t attrsz,
2N/A size_t *attrszp)
2N/A{
2N/A nvlist_t *nvl = conf.ds_nvl;
2N/A nvpair_t *last = NULL, *nvp;
2N/A uchar_t *oattrval;
2N/A uint32_t oattrsz;
2N/A int err;
2N/A
2N/A if (nvl == NULL || attrval == NULL || attrsz == 0 || attr == NULL ||
2N/A !conf.ds_readonly)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A while ((nvp = nvlist_next_nvpair(nvl, last)) != NULL) {
2N/A if (last_attr[0] == '\0')
2N/A break;
2N/A if (last != NULL && strcmp(last_attr, nvpair_name(last)) == 0)
2N/A break;
2N/A last = nvp;
2N/A }
2N/A
2N/A if (nvp == NULL)
2N/A return (DLADM_STATUS_NOTFOUND);
2N/A
2N/A if ((err = nvpair_value_byte_array(nvp, (uchar_t **)&oattrval,
2N/A &oattrsz)) != NULL) {
2N/A return (dladm_errno2status(err));
2N/A }
2N/A
2N/A *attrszp = oattrsz;
2N/A if (oattrsz > attrsz)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A (void) strlcpy(attr, nvpair_name(nvp), MAXLINKATTRLEN);
2N/A bcopy(oattrval, attrval, oattrsz);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Get the link ID that is associated with the given name.
2N/A */
2N/Adladm_status_t
2N/Adladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
2N/A uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
2N/A{
2N/A dlmgmt_door_getlinkid_t getlinkid;
2N/A dlmgmt_getlinkid_retval_t retval;
2N/A datalink_id_t linkid;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
2N/A (void) strlcpy(getlinkid.ld_link, link, sizeof (getlinkid.ld_link));
2N/A
2N/A if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
2N/A &retval, &sz)) != DLADM_STATUS_OK) {
2N/A return (status);
2N/A }
2N/A
2N/A linkid = retval.lr_linkid;
2N/A if (retval.lr_class == DATALINK_CLASS_PHYS &&
2N/A retval.lr_flags & DLMGMT_ACTIVE) {
2N/A /*
2N/A * An active physical link reported by the dlmgmtd daemon
2N/A * might not be active anymore. Check and set its real status.
2N/A */
2N/A status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A }
2N/A
2N/A if (linkidp != NULL)
2N/A *linkidp = linkid;
2N/A if (flagp != NULL) {
2N/A *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0;
2N/A *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
2N/A DLADM_OPT_PERSIST : 0;
2N/A *flagp |= retval.lr_onloan ? DLADM_OPT_ONLOAN : 0;
2N/A }
2N/A if (classp != NULL)
2N/A *classp = retval.lr_class;
2N/A if (mediap != NULL)
2N/A *mediap = retval.lr_media;
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Get the link attributes including zoneid
2N/A */
2N/Adladm_status_t
2N/Adladm_datalink_id2linkinfo(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
2N/A size_t len, zoneid_t *zoneid)
2N/A{
2N/A dlmgmt_door_getname_t getname;
2N/A dlmgmt_getname_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0))
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A getname.ld_cmd = DLMGMT_CMD_GETNAME;
2N/A getname.ld_linkid = linkid;
2N/A getname.ld_zoneprefix = B_TRUE;
2N/A if ((status = dladm_door_call(handle, &getname, sizeof (getname),
2N/A &retval, &sz)) != DLADM_STATUS_OK) {
2N/A return (status);
2N/A }
2N/A
2N/A if (len != 0 && (strlen(retval.lr_link) + 1 > len))
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A if (retval.lr_class == DATALINK_CLASS_PHYS &&
2N/A retval.lr_flags & DLMGMT_ACTIVE) {
2N/A /*
2N/A * An active physical link reported by the dlmgmtd daemon
2N/A * might not be active anymore. Check and set its real status.
2N/A */
2N/A status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A }
2N/A
2N/A if (link != NULL) {
2N/A if (strlcpy(link, retval.lr_link, len) >= len)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A }
2N/A if (classp != NULL)
2N/A *classp = retval.lr_class;
2N/A if (mediap != NULL)
2N/A *mediap = retval.lr_media;
2N/A if (flagp != NULL) {
2N/A *flagp = retval.lr_flags & DLMGMT_ACTIVE ?
2N/A DLADM_OPT_ACTIVE : 0;
2N/A *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
2N/A DLADM_OPT_PERSIST : 0;
2N/A *flagp |= retval.lr_onloan ? DLADM_OPT_ONLOAN : 0;
2N/A }
2N/A
2N/A if (zoneid != NULL)
2N/A *zoneid = retval.lr_zoneid;
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Get the link name that is associated with the given id.
2N/A */
2N/Adladm_status_t
2N/Adladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
2N/A size_t len)
2N/A{
2N/A return (dladm_datalink_id2linkinfo(handle, linkid, flagp, classp,
2N/A mediap, link, len, NULL));
2N/A}
2N/A
2N/A/*
2N/A * Set the given attr with the given attrval for the given flow.
2N/A */
2N/Adladm_status_t
2N/Adladm_set_flowconf_field(dladm_handle_t handle, const char *flow,
2N/A const char *attr, dladm_datatype_t type, const void *attrval)
2N/A{
2N/A dlmgmt_door_setflowattr_t setattr;
2N/A dlmgmt_setflowattr_retval_t retval;
2N/A size_t attrsz, sz = sizeof (retval);
2N/A
2N/A if (attr == NULL || attrval == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (type == DLADM_TYPE_STR)
2N/A attrsz = strlen(attrval) + 1;
2N/A else
2N/A attrsz = dladm_datatype_size[type];
2N/A
2N/A if (attrsz > MAXOBJATTRVALLEN)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A setattr.ld_cmd = DLMGMT_CMD_SETFLOWATTR;
2N/A (void) strlcpy(setattr.ld_flow, flow, MAXFLOWNAMELEN);
2N/A (void) strlcpy(setattr.ld_attr, attr, MAXOBJATTRLEN);
2N/A setattr.ld_attrsz = attrsz;
2N/A setattr.ld_type = type;
2N/A bcopy(attrval, &setattr.ld_attrval, attrsz);
2N/A
2N/A return (dladm_door_call(handle, &setattr, sizeof (setattr), &retval,
2N/A &sz));
2N/A}
2N/A
2N/A/*
2N/A * Set the given attr with the given attrval for the given link.
2N/A */
2N/Adladm_status_t
2N/Adladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
2N/A dladm_datatype_t type, const void *attrval)
2N/A{
2N/A dlmgmt_door_setattr_t setattr;
2N/A dlmgmt_setattr_retval_t retval;
2N/A size_t attrsz;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (attr == NULL || attrval == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (conf.ds_readonly)
2N/A return (DLADM_STATUS_DENIED);
2N/A
2N/A if (type == DLADM_TYPE_STR)
2N/A attrsz = strlen(attrval) + 1;
2N/A else
2N/A attrsz = dladm_datatype_size[type];
2N/A
2N/A if (attrsz > MAXOBJATTRVALLEN)
2N/A return (DLADM_STATUS_TOOSMALL);
2N/A
2N/A setattr.ld_cmd = DLMGMT_CMD_SETATTR;
2N/A setattr.ld_confid = conf.ds_confid;
2N/A (void) strlcpy(setattr.ld_attr, attr, MAXOBJATTRLEN);
2N/A setattr.ld_attrsz = attrsz;
2N/A setattr.ld_type = type;
2N/A bcopy(attrval, &setattr.ld_attrval, attrsz);
2N/A
2N/A return (dladm_door_call(handle, &setattr, sizeof (setattr),
2N/A &retval, &sz));
2N/A}
2N/A
2N/A/*
2N/A * Unset the given attr the given link.
2N/A */
2N/Adladm_status_t
2N/Adladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf,
2N/A const char *attr)
2N/A{
2N/A dlmgmt_door_unsetattr_t unsetattr;
2N/A dlmgmt_unsetattr_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (attr == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (conf.ds_readonly)
2N/A return (DLADM_STATUS_DENIED);
2N/A
2N/A unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR;
2N/A unsetattr.ld_confid = conf.ds_confid;
2N/A (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN);
2N/A
2N/A return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr),
2N/A &retval, &sz));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_get_phys_prefix(dladm_handle_t handle, char *phys_prefix)
2N/A{
2N/A dlmgmt_door_getphys_prefix_t getphys_prefix;
2N/A dlmgmt_getphys_prefix_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A dladm_status_t status;
2N/A
2N/A if (phys_prefix == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A getphys_prefix.ld_cmd = DLMGMT_CMD_GETPHYS_PREFIX;
2N/A status = dladm_door_call(handle, &getphys_prefix,
2N/A sizeof (getphys_prefix), &retval, &sz);
2N/A if (status == DLADM_STATUS_OK) {
2N/A (void) strlcpy(phys_prefix, retval.lr_phys_prefix,
2N/A MAXLINKNAMELEN);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Remove the flow and its entry from the data link configuration
2N/A * repository.
2N/A */
2N/Adladm_status_t
2N/Adladm_remove_flowconf(dladm_handle_t handle, const char *flowname,
2N/A const char *root)
2N/A{
2N/A dlmgmt_door_removeflowconf_t flowconf;
2N/A dlmgmt_removeflowconf_retval_t retval;
2N/A dladm_status_t status;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A bzero(&flowconf, sizeof (dlmgmt_door_removeflowconf_t));
2N/A flowconf.ld_cmd = DLMGMT_CMD_REMOVEFLOWCONF;
2N/A (void) strlcpy(flowconf.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A (void) strlcpy(flowconf.ld_flow, flowname, MAXFLOWNAMELEN);
2N/A if (root != NULL)
2N/A (void) strlcpy(flowconf.ld_root, root, MAXPATHLEN);
2N/A
2N/A status = dladm_door_call(handle, &flowconf, sizeof (flowconf),
2N/A &retval, &sz);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Remove the given link ID and its entry from the data link configuration
2N/A * repository.
2N/A */
2N/Adladm_status_t
2N/Adladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A dlmgmt_door_removeconf_t removeconf;
2N/A dlmgmt_removeconf_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A dladm_status_t status;
2N/A datalink_class_t class;
2N/A char linkname[MAXLINKNAMELEN];
2N/A
2N/A removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF;
2N/A (void) strlcpy(removeconf.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A removeconf.ld_linkid = linkid;
2N/A
2N/A status = dladm_door_call(handle, &removeconf, sizeof (removeconf),
2N/A &retval, &sz);
2N/A
2N/A /*
2N/A * If the door call to remove configuration is successful, send a door
2N/A * call to nwamd to remove the configuration.
2N/A */
2N/A if (status == DLADM_STATUS_OK) {
2N/A if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
2N/A linkname, sizeof (linkname)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A /* no need to determine what links are underneath */
2N/A nwam_ncu_external_action(NWAM_NCU_TYPE_LINK, linkname,
2N/A handle->dh_profile, NULL, B_FALSE);
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Free the contents of the link structure.
2N/A */
2N/Avoid
2N/Adladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf)
2N/A{
2N/A dlmgmt_door_destroyconf_t dconf;
2N/A dlmgmt_destroyconf_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A if (conf.ds_readonly) {
2N/A nvlist_free(conf.ds_nvl);
2N/A } else {
2N/A if (conf.ds_confid == DLADM_INVALID_CONF)
2N/A return;
2N/A
2N/A dconf.ld_cmd = DLMGMT_CMD_DESTROYCONF;
2N/A dconf.ld_confid = conf.ds_confid;
2N/A
2N/A (void) dladm_door_call(handle, &dconf, sizeof (dconf),
2N/A &retval, &sz);
2N/A }
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_zone_boot(dladm_handle_t handle, zoneid_t zoneid)
2N/A{
2N/A dlmgmt_door_zoneboot_t zoneboot;
2N/A dlmgmt_zoneboot_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A zoneboot.ld_cmd = DLMGMT_CMD_ZONEBOOT;
2N/A (void) strlcpy(zoneboot.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A zoneboot.ld_zoneid = zoneid;
2N/A return (dladm_door_call(handle, &zoneboot, sizeof (zoneboot),
2N/A &retval, &sz));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_zone_halt(dladm_handle_t handle, zoneid_t zoneid)
2N/A{
2N/A dlmgmt_door_zonehalt_t zonehalt;
2N/A dlmgmt_zonehalt_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A zonehalt.ld_cmd = DLMGMT_CMD_ZONEHALT;
2N/A zonehalt.ld_profile[0] = '\0';
2N/A zonehalt.ld_zoneid = zoneid;
2N/A return (dladm_door_call(handle, &zonehalt, sizeof (zonehalt),
2N/A &retval, &sz));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_zone_upgrade(dladm_handle_t handle, zoneid_t zoneid)
2N/A{
2N/A dlmgmt_door_zoneupgrade_t zoneupgrade;
2N/A dlmgmt_zoneupgrade_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A zoneupgrade.ld_cmd = DLMGMT_CMD_ZONE_UPGRADE;
2N/A zoneupgrade.ld_profile[0] = '\0';
2N/A zoneupgrade.ld_zoneid = zoneid;
2N/A return (dladm_door_call(handle, &zoneupgrade, sizeof (zoneupgrade),
2N/A &retval, &sz));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_init_profile(dladm_handle_t handle)
2N/A{
2N/A dlmgmt_door_prof_t iprof;
2N/A dlmgmt_prof_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A iprof.ld_cmd = DLMGMT_CMD_INIT_PROFILE;
2N/A (void) strlcpy(iprof.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A return (dladm_door_call(handle, &iprof, sizeof (iprof), &retval, &sz));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_fini_profile(dladm_handle_t handle)
2N/A{
2N/A dlmgmt_door_prof_t fprof;
2N/A dlmgmt_prof_retval_t retval;
2N/A size_t sz = sizeof (retval);
2N/A
2N/A fprof.ld_cmd = DLMGMT_CMD_FINI_PROFILE;
2N/A (void) strlcpy(fprof.ld_profile, handle->dh_profile,
2N/A NETCFG_PROFILE_LEN);
2N/A return (dladm_door_call(handle, &fprof, sizeof (fprof), &retval, &sz));
2N/A}