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) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <unistd.h>
2N/A#include <errno.h>
2N/A#include <fcntl.h>
2N/A#include <assert.h>
2N/A#include <ctype.h>
2N/A#include <strings.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/dld.h>
2N/A#include <sys/vlan.h>
2N/A#include <zone.h>
2N/A#include <librcm.h>
2N/A#include <libdlpi.h>
2N/A#include <libdevinfo.h>
2N/A#include <libdlaggr.h>
2N/A#include <libdlbridge.h>
2N/A#include <libdlvlan.h>
2N/A#include <libdlvnic.h>
2N/A#include <libdlib.h>
2N/A#include <libdliptun.h>
2N/A#include <libdllink.h>
2N/A#include <libdlmgmt.h>
2N/A#include <libdlsim.h>
2N/A#include <libdladm_impl.h>
2N/A#include <libinetutil.h>
2N/A
2N/A/*
2N/A * Return the attributes of the specified datalink from the DLD driver.
2N/A */
2N/Astatic dladm_status_t
2N/Ai_dladm_info(dladm_handle_t handle, const datalink_id_t linkid,
2N/A dladm_attr_t *dap)
2N/A{
2N/A dld_ioc_attr_t dia;
2N/A
2N/A dia.dia_linkid = linkid;
2N/A
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0)
2N/A return (dladm_errno2status(errno));
2N/A
2N/A dap->da_max_sdu = dia.dia_max_sdu;
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Adladm_usagelog(dladm_handle_t handle, dladm_logtype_t type,
2N/A dld_ioc_usagelog_t *log_info)
2N/A{
2N/A if (type == DLADM_LOGTYPE_FLOW)
2N/A log_info->ul_type = MAC_LOGTYPE_FLOW;
2N/A else
2N/A log_info->ul_type = MAC_LOGTYPE_LINK;
2N/A
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0)
2N/A return (DLADM_STATUS_IOERR);
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type,
2N/A uint_t interval)
2N/A{
2N/A dld_ioc_usagelog_t log_info;
2N/A
2N/A log_info.ul_onoff = B_TRUE;
2N/A log_info.ul_interval = interval;
2N/A
2N/A return (dladm_usagelog(handle, type, &log_info));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type)
2N/A{
2N/A dld_ioc_usagelog_t log_info;
2N/A
2N/A log_info.ul_onoff = B_FALSE;
2N/A log_info.ul_interval = 0;
2N/A
2N/A return (dladm_usagelog(handle, type, &log_info));
2N/A}
2N/A
2N/Astruct i_dladm_walk_arg {
2N/A dladm_walkcb_t *fn;
2N/A void *arg;
2N/A};
2N/A
2N/Astatic int
2N/Ai_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2N/A{
2N/A struct i_dladm_walk_arg *walk_arg = arg;
2N/A char link[MAXLINKNAMELEN];
2N/A
2N/A if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link,
2N/A sizeof (link)) == DLADM_STATUS_OK) {
2N/A return (walk_arg->fn(link, walk_arg->arg));
2N/A }
2N/A
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Walk all datalinks.
2N/A */
2N/Adladm_status_t
2N/Adladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg,
2N/A datalink_class_t class, datalink_media_t dmedia, uint32_t flags)
2N/A{
2N/A struct i_dladm_walk_arg walk_arg;
2N/A
2N/A walk_arg.fn = fn;
2N/A walk_arg.arg = arg;
2N/A return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg,
2N/A class, dmedia, flags));
2N/A}
2N/A
2N/A#define MAXGRPPERLINK 64
2N/A
2N/Avoid
2N/Adladm_get_ring_index_list(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint_t **rxringlist, uint_t *p_nrxrings,
2N/A uint_t **txringlist, uint_t *p_ntxrings)
2N/A{
2N/A dld_ioc_ringidget_t *iom;
2N/A uint_t nrxrings = 0, ntxrings = 0;
2N/A int i;
2N/A int dsize = 0, buffersize;
2N/A
2N/Aretry:
2N/A buffersize = dsize + sizeof (dld_ioc_ringidget_t);
2N/A if ((iom = calloc(1, buffersize)) == NULL)
2N/A return;
2N/A iom->dir_size = dsize;
2N/A iom->dir_linkid = linkid;
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_GETRINGIDS, iom) < 0) {
2N/A if (errno == ENOBUFS) {
2N/A dsize = iom->dir_size;
2N/A free(iom);
2N/A goto retry;
2N/A }
2N/A goto done;
2N/A }
2N/A
2N/A if (iom->dir_rxdedicated == B_TRUE)
2N/A nrxrings = iom->dir_nrxrings;
2N/A
2N/A if (iom->dir_txdedicated == B_TRUE)
2N/A ntxrings = iom->dir_ntxrings;
2N/A
2N/Adone:
2N/A if (p_nrxrings) {
2N/A *rxringlist = malloc(nrxrings * sizeof (uint_t));
2N/A if (*rxringlist == NULL) {
2N/A *p_nrxrings = 0;
2N/A free(iom);
2N/A return;
2N/A }
2N/A *p_nrxrings = nrxrings;
2N/A for (i = 0; i < *p_nrxrings; i++)
2N/A (*rxringlist)[i] = iom->dir_ringids[i];
2N/A }
2N/A if (p_ntxrings) {
2N/A *txringlist = malloc(ntxrings * sizeof (uint_t));
2N/A if (*txringlist == NULL) {
2N/A *p_ntxrings = 0;
2N/A free(iom);
2N/A return;
2N/A }
2N/A *p_ntxrings = ntxrings;
2N/A for (i = 0; i < *p_ntxrings; i++)
2N/A (*txringlist)[i] =
2N/A iom->dir_ringids[i + iom->dir_nrxrings];
2N/A }
2N/A free(iom);
2N/A}
2N/A
2N/A
2N/Avoid
2N/Adladm_get_ring_counts(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint_t *p_nrxrings, uint_t *p_ntxrings)
2N/A{
2N/A uint_t bufsize, dsize;
2N/A int nhwgrp = MAXGRPPERLINK;
2N/A dld_ioc_hwgrpget_t *iomp = NULL;
2N/A uint_t nrxrings = 0, ntxrings = 0;
2N/A
2N/A dsize = nhwgrp * sizeof (dld_hwgrpinfo_t);
2N/Aretry:
2N/A bufsize = sizeof (dld_ioc_hwgrpget_t) + dsize;
2N/A
2N/A if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL)
2N/A goto done;
2N/A
2N/A iomp->dih_size = dsize;
2N/A iomp->dih_linkid = linkid;
2N/A
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp) < 0) {
2N/A if (errno == ENOBUFS) {
2N/A dsize = iomp->dih_size;
2N/A free(iomp);
2N/A goto retry;
2N/A }
2N/A goto done;
2N/A }
2N/A
2N/A nrxrings = iomp->dih_nrxrings;
2N/A ntxrings = iomp->dih_ntxrings;
2N/A
2N/Adone:
2N/A if (p_nrxrings)
2N/A *p_nrxrings = nrxrings;
2N/A if (p_ntxrings)
2N/A *p_ntxrings = ntxrings;
2N/A if (iomp != NULL)
2N/A free(iomp);
2N/A}
2N/A
2N/A
2N/Avoid
2N/Adladm_query_primary_linkid(dladm_handle_t handle, datalink_id_t linkid,
2N/A datalink_id_t *ulinkid)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A datalink_class_t class;
2N/A
2N/A *ulinkid = DATALINK_INVALID_LINKID;
2N/A
2N/A if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
2N/A NULL, NULL, 0)) != DLADM_STATUS_OK) {
2N/A return;
2N/A }
2N/A
2N/A switch (class) {
2N/A case DATALINK_CLASS_PHYS:
2N/A case DATALINK_CLASS_AGGR: {
2N/A *ulinkid = linkid;
2N/A break;
2N/A }
2N/A case DATALINK_CLASS_VNIC:
2N/A case DATALINK_CLASS_VLAN: {
2N/A dladm_vnic_attr_t vinfo;
2N/A status = dladm_vnic_info(handle, linkid, &vinfo,
2N/A DLADM_OPT_ACTIVE);
2N/A if (status != DLADM_STATUS_OK)
2N/A break;
2N/A
2N/A *ulinkid = vinfo.va_link_id;
2N/A break;
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This function walks thru all the ring groups for a given datalink
2N/A * and calls the callback function fn on each group.
2N/A */
2N/A
2N/Aint
2N/Adladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg,
2N/A boolean_t (*fn)(void *, dladm_hwgrp_attr_t *))
2N/A{
2N/A int bufsize, ret, dsize, increment;
2N/A int nhwgrp = MAXGRPPERLINK;
2N/A dld_ioc_hwgrpget_t *iomp = NULL;
2N/A
2N/A dsize = nhwgrp * sizeof (dld_hwgrpinfo_t);
2N/Aretry:
2N/A bufsize = sizeof (dld_ioc_hwgrpget_t) + dsize;
2N/A
2N/A /*
2N/A * After a successful call to ioctl(..., DLDIOC_GETHWGRP, iomp),
2N/A * iomp points to dld_ioc_hwgrpget_t, followed by information
2N/A * about dih_ngroups number of ring groups. Information about each
2N/A * ring group is variable in size and depends upon the number of
2N/A * rings in the group. Buffer pointed to by iomp looks like -
2N/A *
2N/A * dld_ioc_hwgrpget_t + <dih_ngroups number of group info>
2N/A * each group info is
2N/A * dld_hwgrpinfo_t + <(dhi_nrings - 1) number of rings>
2N/A */
2N/A
2N/A if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL)
2N/A return (-1);
2N/A
2N/A iomp->dih_size = dsize;
2N/A iomp->dih_linkid = linkid;
2N/A
2N/A ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp);
2N/A if ((ret < 0) && (errno == ENOBUFS)) {
2N/A dsize = iomp->dih_size;
2N/A free(iomp);
2N/A goto retry;
2N/A }
2N/A if (ret == 0) {
2N/A int i, j, rsize;
2N/A dld_hwgrpinfo_t *dhip;
2N/A dladm_hwgrp_attr_t *attr;
2N/A
2N/A dhip = (dld_hwgrpinfo_t *)(iomp + 1);
2N/A for (i = 0; i < iomp->dih_ngroups; i++) {
2N/A rsize = sizeof (dladm_hwgrp_attr_t)
2N/A + (dhip->dhi_nrings - 1) * sizeof (uint_t);
2N/A attr = (dladm_hwgrp_attr_t *)calloc(1, rsize);
2N/A if (attr == NULL)
2N/A break;
2N/A
2N/A (void) strlcpy(attr->hg_link_name,
2N/A dhip->dhi_link_name, sizeof (attr->hg_link_name));
2N/A attr->hg_grp_num = dhip->dhi_grp_num;
2N/A attr->hg_grp_type = dhip->dhi_grp_type;
2N/A attr->hg_nrings = dhip->dhi_nrings;
2N/A for (j = 0; j < dhip->dhi_nrings; j++)
2N/A attr->hg_rings[j] = dhip->dhi_rings[j];
2N/A dladm_sort_index_list(attr->hg_rings, attr->hg_nrings);
2N/A attr->hg_nclnts = dhip->dhi_nclnts;
2N/A (void) strlcpy(attr->hg_client_names,
2N/A dhip->dhi_clnts, sizeof (attr->hg_client_names));
2N/A
2N/A if (!(*fn)(arg, attr))
2N/A break;
2N/A
2N/A /*
2N/A * Data for each group is of variable size
2N/A * and follows the struture dld_hwgrpinfo_t.
2N/A */
2N/A
2N/A increment = sizeof (dld_hwgrpinfo_t) +
2N/A (dhip->dhi_nrings - 1) *
2N/A sizeof (dhip->dhi_rings[0]);
2N/A dhip = (dld_hwgrpinfo_t *)((uintptr_t)dhip + increment);
2N/A free(attr);
2N/A }
2N/A }
2N/A free(iomp);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Invoke the specified callback for each MAC address entry defined on
2N/A * the specified device.
2N/A */
2N/Aint
2N/Adladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg,
2N/A boolean_t (*fn)(void *, dladm_macaddr_attr_t *))
2N/A{
2N/A int bufsize, ret;
2N/A int nmacaddr = 1024;
2N/A dld_ioc_macaddrget_t *iomp = NULL;
2N/A
2N/A bufsize = sizeof (dld_ioc_macaddrget_t) +
2N/A nmacaddr * sizeof (dld_macaddrinfo_t);
2N/A
2N/A if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL)
2N/A return (-1);
2N/A
2N/A iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t);
2N/A iomp->dig_linkid = linkid;
2N/A
2N/A ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp);
2N/A if (ret == 0) {
2N/A int i;
2N/A dld_macaddrinfo_t *dmip;
2N/A dladm_macaddr_attr_t attr;
2N/A
2N/A dmip = (dld_macaddrinfo_t *)(iomp + 1);
2N/A for (i = 0; i < iomp->dig_count; i++) {
2N/A bzero(&attr, sizeof (attr));
2N/A
2N/A attr.ma_slot = dmip->dmi_slot;
2N/A attr.ma_flags = 0;
2N/A if (dmip->dmi_flags & DLDIOCMACADDR_USED)
2N/A attr.ma_flags |= DLADM_MACADDR_USED;
2N/A bcopy(dmip->dmi_addr, attr.ma_addr,
2N/A dmip->dmi_addrlen);
2N/A attr.ma_addrlen = dmip->dmi_addrlen;
2N/A (void) strlcpy(attr.ma_client_name,
2N/A dmip->dmi_client_name, MAXNAMELEN);
2N/A attr.ma_client_linkid = dmip->dma_client_linkid;
2N/A
2N/A if (!(*fn)(arg, &attr))
2N/A break;
2N/A dmip++;
2N/A }
2N/A }
2N/A free(iomp);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * These routines are used by administration tools such as dladm(1M) to
2N/A * iterate through the list of MAC interfaces
2N/A */
2N/A
2N/Atypedef struct dladm_mac_dev {
2N/A char dm_name[MAXNAMELEN];
2N/A struct dladm_mac_dev *dm_next;
2N/A} dladm_mac_dev_t;
2N/A
2N/Atypedef struct macadm_walk {
2N/A dladm_mac_dev_t *dmd_dev_list;
2N/A} dladm_mac_walk_t;
2N/A
2N/A/*
2N/A * Local callback invoked for each DDI_NT_NET node.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic int
2N/Ai_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg)
2N/A{
2N/A dladm_mac_walk_t *dmwp = arg;
2N/A dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list;
2N/A dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list;
2N/A char mac[MAXNAMELEN];
2N/A
2N/A (void) snprintf(mac, MAXNAMELEN, "%s%d",
2N/A di_driver_name(node), di_instance(node));
2N/A
2N/A /*
2N/A * Skip aggregations.
2N/A */
2N/A if (strcmp("aggr", di_driver_name(node)) == 0)
2N/A return (DI_WALK_CONTINUE);
2N/A
2N/A /*
2N/A * Skip softmacs.
2N/A */
2N/A if (strcmp("softmac", di_driver_name(node)) == 0)
2N/A return (DI_WALK_CONTINUE);
2N/A
2N/A while (dmdp) {
2N/A /*
2N/A * Skip duplicates.
2N/A */
2N/A if (strcmp(dmdp->dm_name, mac) == 0)
2N/A return (DI_WALK_CONTINUE);
2N/A
2N/A last_dmdp = &dmdp->dm_next;
2N/A dmdp = dmdp->dm_next;
2N/A }
2N/A
2N/A if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
2N/A return (DI_WALK_CONTINUE);
2N/A
2N/A (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
2N/A dmdp->dm_next = NULL;
2N/A *last_dmdp = dmdp;
2N/A
2N/A return (DI_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Invoke the specified callback for each DDI_NT_NET node.
2N/A */
2N/Adladm_status_t
2N/Adladm_mac_walk(int (*fn)(const char *, void *arg), void *arg)
2N/A{
2N/A di_node_t root;
2N/A dladm_mac_walk_t dmw;
2N/A dladm_mac_dev_t *dmdp, *next;
2N/A boolean_t done = B_FALSE;
2N/A
2N/A if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
2N/A return (dladm_errno2status(errno));
2N/A
2N/A dmw.dmd_dev_list = NULL;
2N/A
2N/A (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
2N/A i_dladm_mac_walk);
2N/A
2N/A di_fini(root);
2N/A
2N/A dmdp = dmw.dmd_dev_list;
2N/A for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
2N/A next = dmdp->dm_next;
2N/A if (!done &&
2N/A ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) {
2N/A done = B_TRUE;
2N/A }
2N/A free(dmdp);
2N/A }
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Get the current attributes of the specified datalink.
2N/A */
2N/Adladm_status_t
2N/Adladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap)
2N/A{
2N/A return (i_dladm_info(handle, linkid, dap));
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_linkstate2str(link_state_t state, char *buf)
2N/A{
2N/A const char *s;
2N/A
2N/A switch (state) {
2N/A case LINK_STATE_UP:
2N/A s = "up";
2N/A break;
2N/A case LINK_STATE_DOWN:
2N/A s = "down";
2N/A break;
2N/A default:
2N/A s = "unknown";
2N/A break;
2N/A }
2N/A (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
2N/A return (buf);
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_linkduplex2str(link_duplex_t duplex, char *buf)
2N/A{
2N/A const char *s;
2N/A
2N/A switch (duplex) {
2N/A case LINK_DUPLEX_FULL:
2N/A s = "full";
2N/A break;
2N/A case LINK_DUPLEX_HALF:
2N/A s = "half";
2N/A break;
2N/A default:
2N/A s = "unknown";
2N/A break;
2N/A }
2N/A (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
2N/A return (buf);
2N/A}
2N/A
2N/A/*
2N/A * Case 1: rename an existing link1 to a link2 that does not exist.
2N/A * Result: <linkid1, link2>
2N/A */
2N/Astatic dladm_status_t
2N/Ai_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
2N/A const char *link1, const char *link2, uint32_t flags)
2N/A{
2N/A dld_ioc_rename_t dir;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A
2N/A /*
2N/A * Link is currently available. Check to see whether anything is
2N/A * holding this link to prevent a rename operation.
2N/A */
2N/A if (flags & DLADM_OPT_ACTIVE) {
2N/A dir.dir_linkid1 = linkid1;
2N/A dir.dir_linkid2 = DATALINK_INVALID_LINKID;
2N/A (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
2N/A
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
2N/A status = dladm_errno2status(errno);
2N/A return (status);
2N/A }
2N/A }
2N/A
2N/A status = dladm_remap_datalink_id(handle, linkid1, link2);
2N/A if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
2N/A (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
2N/A (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/Atypedef struct link_hold_arg_s {
2N/A datalink_id_t linkid;
2N/A datalink_id_t holder;
2N/A uint32_t flags;
2N/A} link_hold_arg_t;
2N/A
2N/Astatic int
2N/Ai_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
2N/A{
2N/A link_hold_arg_t *hold_arg = arg;
2N/A dladm_aggr_grp_attr_t ginfo;
2N/A dladm_status_t status;
2N/A int i;
2N/A
2N/A status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (DLADM_WALK_CONTINUE);
2N/A
2N/A for (i = 0; i < ginfo.lg_nports; i++) {
2N/A if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) {
2N/A hold_arg->holder = aggrid;
2N/A return (DLADM_WALK_TERMINATE);
2N/A }
2N/A }
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/Astatic int
2N/Ai_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
2N/A{
2N/A link_hold_arg_t *hold_arg = arg;
2N/A dladm_vlan_attr_t vinfo;
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (DLADM_WALK_CONTINUE);
2N/A
2N/A if (vinfo.dv_linkid == hold_arg->linkid) {
2N/A hold_arg->holder = vlanid;
2N/A return (DLADM_WALK_TERMINATE);
2N/A }
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Case 2: rename an available physical link link1 to a REMOVED physical link
2N/A * link2. As a result, link1 directly inherits all datalinks configured
2N/A * over link2 (linkid2).
2N/A * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname,
2N/A * link2_other_attr>
2N/A */
2N/Astatic dladm_status_t
2N/Ai_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1,
2N/A datalink_id_t linkid2)
2N/A{
2N/A rcm_handle_t *rcm_hdl = NULL;
2N/A nvlist_t *nvl = NULL;
2N/A link_hold_arg_t arg;
2N/A dld_ioc_rename_t dir;
2N/A dladm_conf_t conf1, conf2;
2N/A char devname[MAXLINKNAMELEN];
2N/A uint64_t phymaj, phyinst;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A
2N/A /*
2N/A * First check if linkid1 is associated with any persistent
2N/A * aggregations or VLANs. If yes, return BUSY.
2N/A */
2N/A arg.linkid = linkid1;
2N/A arg.holder = DATALINK_INVALID_LINKID;
2N/A arg.flags = DLADM_OPT_PERSIST;
2N/A (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg,
2N/A DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2N/A if (arg.holder != DATALINK_INVALID_LINKID)
2N/A return (DLADM_STATUS_LINKBUSY);
2N/A
2N/A arg.flags = DLADM_OPT_PERSIST;
2N/A (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg,
2N/A DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2N/A if (arg.holder != DATALINK_INVALID_LINKID)
2N/A return (DLADM_STATUS_LINKBUSY);
2N/A
2N/A /*
2N/A * Send DLDIOC_RENAME to request to rename link1's linkid to
2N/A * be linkid2. This will check whether link1 is used by any
2N/A * aggregations or VLANs, or is held by any application. If yes,
2N/A * return failure.
2N/A */
2N/A dir.dir_linkid1 = linkid1;
2N/A dir.dir_linkid2 = linkid2;
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
2N/A status = dladm_errno2status(errno);
2N/A
2N/A if (status != DLADM_STATUS_OK) {
2N/A return (status);
2N/A }
2N/A
2N/A /*
2N/A * Now change the phymaj, phyinst and devname associated with linkid1
2N/A * to be associated with linkid2. Before doing that, the old active
2N/A * linkprop of linkid1 should be deleted.
2N/A */
2N/A (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0,
2N/A DLADM_OPT_ACTIVE);
2N/A
2N/A if (((status = dladm_getsnap_conf(handle, linkid1, &conf1)) !=
2N/A DLADM_STATUS_OK) ||
2N/A ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname,
2N/A MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
2N/A ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj,
2N/A sizeof (uint64_t))) != DLADM_STATUS_OK) ||
2N/A ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst,
2N/A sizeof (uint64_t))) != DLADM_STATUS_OK) ||
2N/A ((status = dladm_open_conf(handle, linkid2, &conf2)) !=
2N/A DLADM_STATUS_OK)) {
2N/A dir.dir_linkid1 = linkid2;
2N/A dir.dir_linkid2 = linkid1;
2N/A (void) dladm_init_linkprop(handle, linkid1, B_FALSE);
2N/A (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
2N/A return (status);
2N/A }
2N/A
2N/A dladm_destroy_conf(handle, conf1);
2N/A (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR,
2N/A devname);
2N/A (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64,
2N/A &phymaj);
2N/A (void) dladm_set_conf_field(handle, conf2, FPHYINST,
2N/A DLADM_TYPE_UINT64, &phyinst);
2N/A (void) dladm_write_conf(handle, conf2, linkid2);
2N/A dladm_destroy_conf(handle, conf2);
2N/A
2N/A /*
2N/A * Delete link1 and mark link2 up.
2N/A */
2N/A (void) dladm_remove_conf(handle, linkid1);
2N/A (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE |
2N/A DLADM_OPT_PERSIST);
2N/A (void) dladm_up_datalink_id(handle, linkid2);
2N/A
2N/A /*
2N/A * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be
2N/A * consumed by the RCM framework to restore all the datalink and
2N/A * IP configuration.
2N/A */
2N/A status = DLADM_STATUS_FAILED;
2N/A if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
2N/A (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) {
2N/A goto done;
2N/A }
2N/A
2N/A if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
2N/A goto done;
2N/A
2N/A if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) ==
2N/A RCM_SUCCESS) {
2N/A status = DLADM_STATUS_OK;
2N/A }
2N/A
2N/Adone:
2N/A if (rcm_hdl != NULL)
2N/A (void) rcm_free_handle(rcm_hdl);
2N/A if (nvl != NULL)
2N/A nvlist_free(nvl);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * case 3: rename a non-existent link to a REMOVED physical link.
2N/A * Set the removed physical link's device name to link1, so that
2N/A * when link1 attaches, it inherits all the link configuration of
2N/A * the removed physical link.
2N/A */
2N/Astatic dladm_status_t
2N/Ai_dladm_rename_link_c3(dladm_handle_t handle, const char *link1,
2N/A datalink_id_t linkid2)
2N/A{
2N/A dladm_conf_t conf;
2N/A dladm_status_t status;
2N/A
2N/A if (!dladm_valid_linkname(link1))
2N/A return (DLADM_STATUS_LINKINVAL);
2N/A
2N/A status = dladm_open_conf(handle, linkid2, &conf);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if ((status = dladm_set_conf_field(handle, conf, FDEVNAME,
2N/A DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) {
2N/A status = dladm_write_conf(handle, conf, linkid2);
2N/A }
2N/A
2N/A dladm_destroy_conf(handle, conf);
2N/A
2N/Adone:
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
2N/A{
2N/A datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
2N/A datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
2N/A uint32_t flags1, flags2;
2N/A datalink_class_t class1, class2;
2N/A uint32_t media1, media2;
2N/A boolean_t remphy2 = B_FALSE;
2N/A dladm_status_t status;
2N/A
2N/A (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1,
2N/A &media1);
2N/A if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2,
2N/A &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
2N/A (flags2 == DLADM_OPT_PERSIST)) {
2N/A /*
2N/A * see whether link2 is a removed physical link.
2N/A */
2N/A remphy2 = B_TRUE;
2N/A }
2N/A
2N/A if (linkid1 != DATALINK_INVALID_LINKID) {
2N/A if (linkid2 == DATALINK_INVALID_LINKID) {
2N/A /*
2N/A * case 1: rename an existing link to a link that
2N/A * does not exist.
2N/A */
2N/A status = i_dladm_rename_link_c1(handle, linkid1, link1,
2N/A link2, flags1);
2N/A } else if (remphy2) {
2N/A /*
2N/A * case 2: rename an available link to a REMOVED
2N/A * physical link. Return failure if link1 is not
2N/A * an active physical link.
2N/A */
2N/A if ((class1 != class2) || (media1 != media2) ||
2N/A !(flags1 & DLADM_OPT_ACTIVE)) {
2N/A status = DLADM_STATUS_BADARG;
2N/A } else {
2N/A status = i_dladm_rename_link_c2(handle, linkid1,
2N/A linkid2);
2N/A }
2N/A } else {
2N/A status = DLADM_STATUS_EXIST;
2N/A }
2N/A } else if (remphy2) {
2N/A status = i_dladm_rename_link_c3(handle, link1, linkid2);
2N/A } else {
2N/A status = DLADM_STATUS_NOTFOUND;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/Atypedef struct consumer_del_phys_arg_s {
2N/A datalink_id_t linkid;
2N/A} consumer_del_phys_arg_t;
2N/A
2N/Astatic int
2N/Ai_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
2N/A{
2N/A consumer_del_phys_arg_t *del_arg = arg;
2N/A dladm_vlan_attr_t vinfo;
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (DLADM_WALK_CONTINUE);
2N/A
2N/A if (vinfo.dv_linkid == del_arg->linkid)
2N/A (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST);
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/Astatic int
2N/Ai_dladm_part_link_del(dladm_handle_t handle, datalink_id_t partid, void *arg)
2N/A{
2N/A consumer_del_phys_arg_t *del_arg = arg;
2N/A dladm_part_attr_t pinfo;
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_part_info(handle, partid, &pinfo, DLADM_OPT_PERSIST);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (DLADM_WALK_CONTINUE);
2N/A
2N/A if (pinfo.dia_physlinkid == del_arg->linkid)
2N/A (void) dladm_part_delete(handle, partid, DLADM_OPT_PERSIST);
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/Astatic int
2N/Ai_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
2N/A{
2N/A consumer_del_phys_arg_t *del_arg = arg;
2N/A dladm_aggr_grp_attr_t ginfo;
2N/A dladm_status_t status;
2N/A dladm_aggr_port_attr_db_t port[1];
2N/A int i;
2N/A
2N/A status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (DLADM_WALK_CONTINUE);
2N/A
2N/A for (i = 0; i < ginfo.lg_nports; i++)
2N/A if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid)
2N/A break;
2N/A
2N/A if (i != ginfo.lg_nports) {
2N/A if (ginfo.lg_nports == 1 && i == 0) {
2N/A consumer_del_phys_arg_t aggr_del_arg;
2N/A
2N/A /*
2N/A * First delete all the VLANs on this aggregation, then
2N/A * delete the aggregation itself.
2N/A */
2N/A aggr_del_arg.linkid = aggrid;
2N/A (void) dladm_walk_datalink_id(i_dladm_vlan_link_del,
2N/A handle, &aggr_del_arg, DATALINK_CLASS_VLAN,
2N/A DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2N/A (void) dladm_aggr_delete(handle, aggrid,
2N/A DLADM_OPT_PERSIST);
2N/A } else {
2N/A port[0].lp_linkid = del_arg->linkid;
2N/A (void) dladm_aggr_remove(handle, aggrid, 1, port,
2N/A DLADM_OPT_PERSIST);
2N/A }
2N/A }
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/Atypedef struct del_phys_arg_s {
2N/A dladm_status_t rval;
2N/A} del_phys_arg_t;
2N/A
2N/Astatic int
2N/Ai_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2N/A{
2N/A uint32_t flags;
2N/A datalink_class_t class;
2N/A uint32_t media;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A del_phys_arg_t *del_phys_arg = arg;
2N/A consumer_del_phys_arg_t del_arg;
2N/A
2N/A if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
2N/A &media, NULL, 0)) != DLADM_STATUS_OK) {
2N/A goto done;
2N/A }
2N/A
2N/A /*
2N/A * see whether this link is a removed physical link.
2N/A */
2N/A if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) ||
2N/A (flags & DLADM_OPT_ACTIVE)) {
2N/A status = DLADM_STATUS_BADARG;
2N/A goto done;
2N/A }
2N/A
2N/A if (media == DL_ETHER) {
2N/A del_arg.linkid = linkid;
2N/A (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle,
2N/A &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
2N/A DLADM_OPT_PERSIST);
2N/A (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle,
2N/A &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
2N/A DLADM_OPT_PERSIST);
2N/A } else if (media == DL_IB) {
2N/A del_arg.linkid = linkid;
2N/A (void) dladm_walk_datalink_id(i_dladm_part_link_del, handle,
2N/A &del_arg, DATALINK_CLASS_PART, DL_IB, DLADM_OPT_PERSIST);
2N/A }
2N/A
2N/A (void) dladm_remove_conf(handle, linkid);
2N/A (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST);
2N/Adone:
2N/A del_phys_arg->rval = status;
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A del_phys_arg_t arg = {DLADM_STATUS_OK};
2N/A
2N/A if (linkid == DATALINK_ALL_LINKID) {
2N/A (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg,
2N/A DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
2N/A DLADM_OPT_PERSIST);
2N/A return (DLADM_STATUS_OK);
2N/A } else {
2N/A (void) i_dladm_phys_delete(handle, linkid, &arg);
2N/A return (arg.rval);
2N/A }
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_phys_info(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_phys_attr_t *dpap, uint32_t flags)
2N/A{
2N/A dladm_status_t status;
2N/A
2N/A assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
2N/A
2N/A switch (flags) {
2N/A case DLADM_OPT_PERSIST: {
2N/A dladm_conf_t conf;
2N/A
2N/A status = dladm_getsnap_conf(handle, linkid, &conf);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A status = dladm_get_conf_field(handle, conf, FDEVNAME,
2N/A dpap->dp_dev, MAXLINKNAMELEN);
2N/A dpap->dp_loc[0] = '\0';
2N/A if (status == DLADM_STATUS_OK) {
2N/A (void) dladm_get_conf_field(handle, conf, FPHYLOC,
2N/A dpap->dp_loc, DLD_LOC_STRSIZE);
2N/A }
2N/A dladm_destroy_conf(handle, conf);
2N/A return (status);
2N/A }
2N/A case DLADM_OPT_ACTIVE: {
2N/A dld_ioc_phys_attr_t dip;
2N/A
2N/A dip.dip_linkid = linkid;
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) {
2N/A status = dladm_errno2status(errno);
2N/A return (status);
2N/A }
2N/A dpap->dp_novanity = dip.dip_novanity;
2N/A (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN);
2N/A (void) strlcpy(dpap->dp_loc, dip.dip_loc,
2N/A DLD_LOC_STRSIZE);
2N/A if (dladm_get_phys_prefix(handle, dpap->dp_phys_prefix)
2N/A != DLADM_STATUS_OK || dip.dip_novanity)
2N/A dpap->dp_phys_prefix[0] = '\0';
2N/A return (DLADM_STATUS_OK);
2N/A }
2N/A default:
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A}
2N/A
2N/Atypedef struct i_walk_dev_state_s {
2N/A const char *devname;
2N/A datalink_id_t linkid;
2N/A boolean_t found;
2N/A} i_walk_dev_state_t;
2N/A
2N/Aint
2N/Ai_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2N/A{
2N/A dladm_phys_attr_t dpa;
2N/A dladm_status_t status;
2N/A i_walk_dev_state_t *statep = arg;
2N/A
2N/A status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST);
2N/A if ((status == DLADM_STATUS_OK) &&
2N/A (strcmp(statep->devname, dpa.dp_dev) == 0)) {
2N/A statep->found = B_TRUE;
2N/A statep->linkid = linkid;
2N/A return (DLADM_WALK_TERMINATE);
2N/A }
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Get the linkid from the physical device name.
2N/A */
2N/Adladm_status_t
2N/Adladm_dev2linkid(dladm_handle_t handle, const char *devname,
2N/A datalink_id_t *linkidp)
2N/A{
2N/A i_walk_dev_state_t state;
2N/A
2N/A state.found = B_FALSE;
2N/A state.devname = devname;
2N/A
2N/A (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state,
2N/A DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2N/A if (state.found == B_TRUE) {
2N/A *linkidp = state.linkid;
2N/A return (DLADM_STATUS_OK);
2N/A } else {
2N/A return (dladm_errno2status(ENOENT));
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Aparse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen)
2N/A{
2N/A char *cp, *tp;
2N/A int len;
2N/A
2N/A /*
2N/A * device name length must not be 0, and it must end with digit.
2N/A */
2N/A if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1]))
2N/A return (EINVAL);
2N/A
2N/A (void) strlcpy(driver, devname, maxlen);
2N/A cp = (char *)&driver[len - 1];
2N/A
2N/A for (tp = cp; isdigit(*tp); tp--) {
2N/A if (tp <= driver)
2N/A return (EINVAL);
2N/A }
2N/A
2N/A *ppa = atoi(tp + 1);
2N/A *(tp + 1) = '\0';
2N/A return (0);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev,
2N/A size_t len)
2N/A{
2N/A char devname[MAXLINKNAMELEN];
2N/A uint16_t vid = VLAN_ID_NONE;
2N/A datalink_class_t class;
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
2N/A NULL, 0);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A /*
2N/A * If this is a VLAN, we must first determine the class and linkid of
2N/A * the link the VLAN has been created over.
2N/A */
2N/A if (class == DATALINK_CLASS_VLAN) {
2N/A dladm_vlan_attr_t dva;
2N/A
2N/A status = dladm_vlan_info(handle, linkid, &dva,
2N/A DLADM_OPT_ACTIVE);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A linkid = dva.dv_linkid;
2N/A vid = dva.dv_vid;
2N/A
2N/A if ((status = dladm_datalink_id2info(handle, linkid, NULL,
2N/A &class, NULL, NULL, 0)) != DLADM_STATUS_OK) {
2N/A goto done;
2N/A }
2N/A }
2N/A
2N/A switch (class) {
2N/A case DATALINK_CLASS_AGGR: {
2N/A dladm_aggr_grp_attr_t dga;
2N/A
2N/A status = dladm_aggr_info(handle, linkid, &dga,
2N/A DLADM_OPT_ACTIVE);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (dga.lg_key == 0) {
2N/A /*
2N/A * If the key was not specified when the aggregation
2N/A * is created, we cannot guess its /dev node name.
2N/A */
2N/A status = DLADM_STATUS_BADARG;
2N/A goto done;
2N/A }
2N/A (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key);
2N/A break;
2N/A }
2N/A case DATALINK_CLASS_PHYS: {
2N/A dladm_phys_attr_t dpa;
2N/A
2N/A status = dladm_phys_info(handle, linkid, &dpa,
2N/A DLADM_OPT_PERSIST);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN);
2N/A break;
2N/A }
2N/A default:
2N/A status = DLADM_STATUS_BADARG;
2N/A goto done;
2N/A }
2N/A
2N/A if (vid != VLAN_ID_NONE) {
2N/A char drv[MAXNAMELEN];
2N/A uint_t ppa;
2N/A
2N/A if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) {
2N/A status = DLADM_STATUS_BADARG;
2N/A goto done;
2N/A }
2N/A if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len)
2N/A status = DLADM_STATUS_TOOSMALL;
2N/A } else {
2N/A if (strlcpy(dev, devname, len) >= len)
2N/A status = DLADM_STATUS_TOOSMALL;
2N/A }
2N/A
2N/Adone:
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_walk_cos(dladm_handle_t handle, datalink_id_t linkid, void *arg,
2N/A int (*fn)(void *, dladm_cos_attr_t *))
2N/A{
2N/A int bufsize, err, i, ncos = MAX_DCB_NTCS;
2N/A dld_ioc_cosget_t *icgp = NULL;
2N/A dld_cosinfo_t *dcp;
2N/A dladm_cos_attr_t attr;
2N/A
2N/A bufsize = sizeof (dld_ioc_cosget_t) + ncos * sizeof (dld_cosinfo_t);
2N/A if ((icgp = (dld_ioc_cosget_t *)calloc(1, bufsize)) == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A icgp->dic_size = ncos * sizeof (dld_cosinfo_t);
2N/A icgp->dic_linkid = linkid;
2N/A
2N/A if (ioctl(dladm_dld_fd(handle), DLDIOC_GETCOS, icgp) != 0) {
2N/A err = errno;
2N/A free(icgp);
2N/A return (dladm_errno2status(err));
2N/A }
2N/A
2N/A dcp = (dld_cosinfo_t *)(icgp + 1);
2N/A for (i = 0; i < icgp->dic_ncos; i++) {
2N/A bzero(&attr, sizeof (attr));
2N/A
2N/A (void) strlcpy(attr.ca_link_name, dcp->dci_link_name,
2N/A sizeof (attr.ca_link_name));
2N/A attr.ca_cos = i;
2N/A attr.ca_etsbw = dcp->dci_etsbw;
2N/A attr.ca_etsbw_eff = dcp->dci_etsbw_eff;
2N/A attr.ca_pfc = dcp->dci_pfc;
2N/A attr.ca_pfc_eff = dcp->dci_pfc_eff;
2N/A (void) strlcpy(attr.ca_client_names, dcp->dci_clnts,
2N/A sizeof (attr.ca_client_names));
2N/A
2N/A if ((*fn)(arg, &attr) == DLADM_WALK_TERMINATE)
2N/A break;
2N/A dcp++;
2N/A }
2N/A free(icgp);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Bring down *all* aggregations, bridges, IP tunnels, IB partitions, simnets,
2N/A * VLANs, VNICs.
2N/A */
2N/Avoid
2N/Adladm_down_all_links(dladm_handle_t handle)
2N/A{
2N/A (void) dladm_bridge_down(handle, DATALINK_ALL_LINKID);
2N/A (void) dladm_iptun_down(handle, DATALINK_ALL_LINKID);
2N/A (void) dladm_part_down(handle, DATALINK_ALL_LINKID, 0);
2N/A (void) dladm_vlan_down(handle, DATALINK_ALL_LINKID);
2N/A (void) dladm_vnic_down(handle, DATALINK_ALL_LINKID, 0);
2N/A (void) dladm_aggr_down(handle, DATALINK_ALL_LINKID);
2N/A /* Take down etherstubs after VNICs have been taken down */
2N/A (void) dladm_vnic_down(handle, DATALINK_ALL_LINKID,
2N/A DLADM_OPT_ETHERSTUB);
2N/A (void) dladm_simnet_down(handle, DATALINK_ALL_LINKID, 0);
2N/A}