libdllink.c revision 811fc8e17e28618ca5149abc18f576709fc5875b
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * CDDL HEADER START
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * The contents of this file are subject to the terms of the
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Common Development and Distribution License (the "License").
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * You may not use this file except in compliance with the License.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * or http://www.opensolaris.org/os/licensing.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * See the License for the specific language governing permissions
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * and limitations under the License.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * When distributing Covered Code, include this CDDL HEADER in each
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * If applicable, add the following below this CDDL HEADER, with the
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * fields enclosed by brackets "[]" replaced with your own identifying
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * information: Portions Copyright [yyyy] [name of copyright owner]
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * CDDL HEADER END
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Use is subject to license terms.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#pragma ident "%Z%%M% %I% %E% SMI"
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <sys/types.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <unistd.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <errno.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <fcntl.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <assert.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <ctype.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <strings.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <sys/stat.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <sys/dld.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <sys/vlan.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <librcm.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdlpi.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdevinfo.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdlaggr.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdlvlan.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdllink.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdlmgmt.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libdladm_impl.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe#include <libinetutil.h>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Return the attributes of the specified datalink from the DLD driver.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowestatic dladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowei_dladm_info(int fd, const datalink_id_t linkid, dladm_attr_t *dap)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dld_ioc_attr_t dia;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dia.dia_linkid = linkid;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (i_dladm_ioctl(fd, DLDIOC_ATTR, &dia, sizeof (dia)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_errno2status(errno));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dap->da_max_sdu = dia.dia_max_sdu;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DLADM_STATUS_OK);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowestruct i_dladm_walk_arg {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_walkcb_t *fn;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe void *arg;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe};
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowestatic int
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowei_dladm_walk(datalink_id_t linkid, void *arg)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe struct i_dladm_walk_arg *walk_arg = arg;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe char link[MAXLINKNAMELEN];
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe sizeof (link)) == DLADM_STATUS_OK) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (walk_arg->fn(link, walk_arg->arg));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DLADM_WALK_CONTINUE);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Walk all datalinks.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_walk(dladm_walkcb_t *fn, void *arg, datalink_class_t class,
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe datalink_media_t dmedia, uint32_t flags)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe struct i_dladm_walk_arg walk_arg;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe walk_arg.fn = fn;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe walk_arg.arg = arg;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_walk_datalink_id(i_dladm_walk, &walk_arg,
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe class, dmedia, flags));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * These routines are used by administration tools such as dladm(1M) to
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * iterate through the list of MAC interfaces
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowetypedef struct dladm_mac_dev {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe char dm_name[MAXNAMELEN];
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe struct dladm_mac_dev *dm_next;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe} dladm_mac_dev_t;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowetypedef struct macadm_walk {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_mac_dev_t *dmd_dev_list;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe} dladm_mac_walk_t;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Local callback invoked for each DDI_NT_NET node.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/* ARGSUSED */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowestatic int
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowei_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_mac_walk_t *dmwp = arg;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe char mac[MAXNAMELEN];
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) snprintf(mac, MAXNAMELEN, "%s%d",
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe di_driver_name(node), di_instance(node));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe /*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Skip aggregations.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (strcmp("aggr", di_driver_name(node)) == 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DI_WALK_CONTINUE);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe /*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Skip softmacs.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (strcmp("softmac", di_driver_name(node)) == 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DI_WALK_CONTINUE);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe while (dmdp) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe /*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Skip duplicates.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (strcmp(dmdp->dm_name, mac) == 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DI_WALK_CONTINUE);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe last_dmdp = &dmdp->dm_next;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dmdp = dmdp->dm_next;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DI_WALK_CONTINUE);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dmdp->dm_next = NULL;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *last_dmdp = dmdp;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DI_WALK_CONTINUE);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Invoke the specified callback for each DDI_NT_NET node.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_mac_walk(int (*fn)(const char *, void *arg), void *arg)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe di_node_t root;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_mac_walk_t dmw;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_mac_dev_t *dmdp, *next;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe boolean_t done = B_FALSE;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_errno2status(errno));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dmw.dmd_dev_list = NULL;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe i_dladm_mac_walk);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe di_fini(root);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dmdp = dmw.dmd_dev_list;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe next = dmdp->dm_next;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (!done &&
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe done = B_TRUE;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe free(dmdp);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (DLADM_STATUS_OK);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Get the current attributes of the specified datalink.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_info(datalink_id_t linkid, dladm_attr_t *dap)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe int fd;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_status_t status;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_errno2status(errno));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe status = i_dladm_info(fd, linkid, dap);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) close(fd);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (status);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Loweconst char *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_linkstate2str(link_state_t state, char *buf)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe const char *s;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe switch (state) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe case LINK_STATE_UP:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe s = "up";
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe break;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe case LINK_STATE_DOWN:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe s = "down";
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe break;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe default:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe s = "unknown";
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe break;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (buf);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Loweconst char *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_linkduplex2str(link_duplex_t duplex, char *buf)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe const char *s;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe switch (duplex) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe case LINK_DUPLEX_FULL:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe s = "full";
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe break;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe case LINK_DUPLEX_HALF:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe s = "half";
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe break;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe default:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe s = "unknown";
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe break;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (buf);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Set zoneid of a given link. Note that this function takes a link name
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * argument instead of a linkid, because a data-link (and its linkid) could
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * be created implicitly as the result of this function. For example, a VLAN
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * could be created if a VLAN PPA hack name is assigned to an exclusive
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * non-global zone.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_setzid(const char *link, zoneid_t zoneid)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe int fd;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_status_t status = DLADM_STATUS_OK;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dld_ioc_setzid_t dis;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_errno2status(errno));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe bzero(&dis, sizeof (dld_ioc_setzid_t));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) strlcpy(dis.dis_link, link, MAXLINKNAMELEN);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dis.dis_zid = zoneid;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (i_dladm_ioctl(fd, DLDIOC_SETZID, &dis, sizeof (dis)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe status = dladm_errno2status(errno);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) close(fd);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (status);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Get zoneid of a given link
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedladm_getzid(datalink_id_t linkid, zoneid_t *zoneidp)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe int fd;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_status_t status = DLADM_STATUS_OK;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dld_ioc_getzid_t dig;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_errno2status(errno));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe bzero(&dig, sizeof (dld_ioc_getzid_t));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dig.dig_linkid = linkid;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dig.dig_zid = -1;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (i_dladm_ioctl(fd, DLDIOC_GETZID, &dig, sizeof (dig)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe status = dladm_errno2status(errno);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) close(fd);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (status == DLADM_STATUS_OK)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *zoneidp = dig.dig_zid;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (status);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Case 1: rename an existing link1 to a link2 that does not exist.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Result: <linkid1, link2>
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowestatic dladm_status_t
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowei_dladm_rename_link_c1(datalink_id_t linkid1, const char *link1,
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe const char *link2, uint32_t flags)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dld_ioc_rename_t dir;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_conf_t conf;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_status_t status = DLADM_STATUS_OK;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe int fd;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe /*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Link is currently available. Check to see whether anything is
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * holding this link to prevent a rename operation.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (flags & DLADM_OPT_ACTIVE) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dir.dir_linkid1 = linkid1;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dir.dir_linkid2 = DATALINK_INVALID_LINKID;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (dladm_errno2status(errno));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe status = dladm_errno2status(errno);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) close(fd);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (status);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe status = dladm_remap_datalink_id(linkid1, link2);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (status != DLADM_STATUS_OK)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe goto done;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe /*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Flush the current mapping to persistent configuration.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((flags & DLADM_OPT_PERSIST) &&
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (((status = dladm_read_conf(linkid1, &conf)) != DLADM_STATUS_OK) ||
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe ((status = dladm_write_conf(conf)) != DLADM_STATUS_OK))) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) dladm_remap_datalink_id(linkid1, link1);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowedone:
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (flags & DLADM_OPT_ACTIVE) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (status != DLADM_STATUS_OK) {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir,
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe sizeof (dir));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe (void) close(fd);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe return (status);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe}
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowetypedef struct link_hold_arg_s {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe datalink_id_t linkid;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe datalink_id_t holder;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe uint32_t flags;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe} link_hold_arg_t;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowestatic int
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowei_dladm_aggr_link_hold(datalink_id_t aggrid, void *arg)
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe{
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe link_hold_arg_t *hold_arg = arg;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_aggr_grp_attr_t ginfo;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe dladm_status_t status;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe int i;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe status = dladm_aggr_info(aggrid, &ginfo, hold_arg->flags);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
for (i = 0; i < ginfo.lg_nports; i++) {
if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) {
hold_arg->holder = aggrid;
return (DLADM_WALK_TERMINATE);
}
}
return (DLADM_WALK_CONTINUE);
}
static int
i_dladm_vlan_link_hold(datalink_id_t vlanid, void *arg)
{
link_hold_arg_t *hold_arg = arg;
dladm_vlan_attr_t vinfo;
dladm_status_t status;
status = dladm_vlan_info(vlanid, &vinfo, hold_arg->flags);
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
if (vinfo.dv_linkid == hold_arg->linkid) {
hold_arg->holder = vlanid;
return (DLADM_WALK_TERMINATE);
}
return (DLADM_WALK_CONTINUE);
}
/*
* Case 2: rename an available physical link link1 to a REMOVED physical link
* link2. As a result, link1 directly inherits all datalinks configured
* over link2 (linkid2).
* Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname,
* link2_other_attr>
*/
static dladm_status_t
i_dladm_rename_link_c2(datalink_id_t linkid1, datalink_id_t linkid2)
{
rcm_handle_t *rcm_hdl = NULL;
nvlist_t *nvl = NULL;
link_hold_arg_t arg;
dld_ioc_rename_t dir;
int fd;
dladm_conf_t conf1, conf2;
char devname[MAXLINKNAMELEN];
uint64_t phymaj, phyinst;
dladm_status_t status = DLADM_STATUS_OK;
/*
* First check if linkid1 is associated with any persistent
* aggregations or VLANs. If yes, return BUSY.
*/
arg.linkid = linkid1;
arg.holder = DATALINK_INVALID_LINKID;
arg.flags = DLADM_OPT_PERSIST;
(void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, &arg,
DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
if (arg.holder != DATALINK_INVALID_LINKID)
return (DLADM_STATUS_LINKBUSY);
arg.flags = DLADM_OPT_PERSIST;
(void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, &arg,
DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
if (arg.holder != DATALINK_INVALID_LINKID)
return (DLADM_STATUS_LINKBUSY);
/*
* Send DLDIOC_RENAME to request to rename link1's linkid to
* be linkid2. This will check whether link1 is used by any
* aggregations or VLANs, or is held by any application. If yes,
* return failure.
*/
if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
return (dladm_errno2status(errno));
dir.dir_linkid1 = linkid1;
dir.dir_linkid2 = linkid2;
if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0)
status = dladm_errno2status(errno);
if (status != DLADM_STATUS_OK) {
(void) close(fd);
return (status);
}
/*
* Now change the phymaj, phyinst and devname associated with linkid1
* to be associated with linkid2. Before doing that, the old active
* linkprop of linkid1 should be deleted.
*/
(void) dladm_set_linkprop(linkid1, NULL, NULL, 0, DLADM_OPT_ACTIVE);
if (((status = dladm_read_conf(linkid1, &conf1)) != DLADM_STATUS_OK) ||
((status = dladm_get_conf_field(conf1, FDEVNAME, devname,
MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
((status = dladm_get_conf_field(conf1, FPHYMAJ, &phymaj,
sizeof (uint64_t))) != DLADM_STATUS_OK) ||
((status = dladm_get_conf_field(conf1, FPHYINST, &phyinst,
sizeof (uint64_t))) != DLADM_STATUS_OK) ||
((status = dladm_read_conf(linkid2, &conf2)) != DLADM_STATUS_OK)) {
dir.dir_linkid1 = linkid2;
dir.dir_linkid2 = linkid1;
(void) dladm_init_linkprop(linkid1);
(void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir));
(void) close(fd);
return (status);
}
(void) close(fd);
dladm_destroy_conf(conf1);
(void) dladm_set_conf_field(conf2, FDEVNAME, DLADM_TYPE_STR, devname);
(void) dladm_set_conf_field(conf2, FPHYMAJ, DLADM_TYPE_UINT64, &phymaj);
(void) dladm_set_conf_field(conf2, FPHYINST,
DLADM_TYPE_UINT64, &phyinst);
(void) dladm_write_conf(conf2);
dladm_destroy_conf(conf2);
/*
* Delete link1 and mark link2 up.
*/
(void) dladm_destroy_datalink_id(linkid1, DLADM_OPT_ACTIVE |
DLADM_OPT_PERSIST);
(void) dladm_remove_conf(linkid1);
(void) dladm_up_datalink_id(linkid2);
/*
* Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be
* consumed by the RCM framework to restore all the datalink and
* IP configuration.
*/
status = DLADM_STATUS_FAILED;
if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
(nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) {
goto done;
}
if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
goto done;
if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) ==
RCM_SUCCESS) {
status = DLADM_STATUS_OK;
}
done:
if (rcm_hdl != NULL)
(void) rcm_free_handle(rcm_hdl);
if (nvl != NULL)
nvlist_free(nvl);
return (status);
}
/*
* case 3: rename a non-existent link to a REMOVED physical link.
* Set the removed physical link's device name to link1, so that
* when link1 attaches, it inherits all the link configuration of
* the removed physical link.
*/
static dladm_status_t
i_dladm_rename_link_c3(const char *link1, datalink_id_t linkid2)
{
dladm_conf_t conf;
dladm_status_t status;
if (!dladm_valid_linkname(link1))
return (DLADM_STATUS_LINKINVAL);
status = dladm_read_conf(linkid2, &conf);
if (status != DLADM_STATUS_OK)
goto done;
if ((status = dladm_set_conf_field(conf, FDEVNAME, DLADM_TYPE_STR,
link1)) == DLADM_STATUS_OK) {
status = dladm_write_conf(conf);
}
dladm_destroy_conf(conf);
done:
return (status);
}
dladm_status_t
dladm_rename_link(const char *link1, const char *link2)
{
datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
uint32_t flags1, flags2;
datalink_class_t class1, class2;
uint32_t media1, media2;
boolean_t remphy2 = B_FALSE;
dladm_status_t status;
(void) dladm_name2info(link1, &linkid1, &flags1, &class1, &media1);
if ((dladm_name2info(link2, &linkid2, &flags2, &class2, &media2) ==
DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
(flags2 == DLADM_OPT_PERSIST)) {
/*
* see whether link2 is a removed physical link.
*/
remphy2 = B_TRUE;
}
if (linkid1 != DATALINK_INVALID_LINKID) {
if (linkid2 == DATALINK_INVALID_LINKID) {
/*
* case 1: rename an existing link to a link that
* does not exist.
*/
status = i_dladm_rename_link_c1(linkid1, link1, link2,
flags1);
} else if (remphy2) {
/*
* case 2: rename an available link to a REMOVED
* physical link. Return failure if link1 is not
* an active physical link.
*/
if ((class1 != class2) || (media1 != media2) ||
!(flags1 & DLADM_OPT_ACTIVE)) {
status = DLADM_STATUS_BADARG;
} else {
status = i_dladm_rename_link_c2(linkid1,
linkid2);
}
} else {
status = DLADM_STATUS_EXIST;
}
} else if (remphy2) {
status = i_dladm_rename_link_c3(link1, linkid2);
} else {
status = DLADM_STATUS_NOTFOUND;
}
return (status);
}
typedef struct consumer_del_phys_arg_s {
datalink_id_t linkid;
} consumer_del_phys_arg_t;
static int
i_dladm_vlan_link_del(datalink_id_t vlanid, void *arg)
{
consumer_del_phys_arg_t *del_arg = arg;
dladm_vlan_attr_t vinfo;
dladm_status_t status;
status = dladm_vlan_info(vlanid, &vinfo, DLADM_OPT_PERSIST);
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
if (vinfo.dv_linkid == del_arg->linkid)
(void) dladm_vlan_delete(vlanid, DLADM_OPT_PERSIST);
return (DLADM_WALK_CONTINUE);
}
static int
i_dladm_aggr_link_del(datalink_id_t aggrid, void *arg)
{
consumer_del_phys_arg_t *del_arg = arg;
dladm_aggr_grp_attr_t ginfo;
dladm_status_t status;
dladm_aggr_port_attr_db_t port[1];
int i;
status = dladm_aggr_info(aggrid, &ginfo, DLADM_OPT_PERSIST);
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
for (i = 0; i < ginfo.lg_nports; i++)
if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid)
break;
if (i != ginfo.lg_nports) {
if (ginfo.lg_nports == 1 && i == 0) {
consumer_del_phys_arg_t aggr_del_arg;
/*
* First delete all the VLANs on this aggregation, then
* delete the aggregation itself.
*/
aggr_del_arg.linkid = aggrid;
(void) dladm_walk_datalink_id(i_dladm_vlan_link_del,
&aggr_del_arg, DATALINK_CLASS_VLAN,
DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
(void) dladm_aggr_delete(aggrid, DLADM_OPT_PERSIST);
} else {
port[0].lp_linkid = del_arg->linkid;
(void) dladm_aggr_remove(aggrid, 1, port,
DLADM_OPT_PERSIST);
}
}
return (DLADM_WALK_CONTINUE);
}
typedef struct del_phys_arg_s {
dladm_status_t rval;
} del_phys_arg_t;
static int
i_dladm_phys_delete(datalink_id_t linkid, void *arg)
{
uint32_t flags;
datalink_class_t class;
uint32_t media;
dladm_status_t status = DLADM_STATUS_OK;
del_phys_arg_t *del_phys_arg = arg;
consumer_del_phys_arg_t del_arg;
if ((status = dladm_datalink_id2info(linkid, &flags, &class,
&media, NULL, 0)) != DLADM_STATUS_OK) {
goto done;
}
/*
* see whether this link is a removed physical link.
*/
if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) ||
(flags & DLADM_OPT_ACTIVE)) {
status = DLADM_STATUS_BADARG;
goto done;
}
if (media == DL_ETHER) {
del_arg.linkid = linkid;
(void) dladm_walk_datalink_id(i_dladm_aggr_link_del, &del_arg,
DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
DLADM_OPT_PERSIST);
(void) dladm_walk_datalink_id(i_dladm_vlan_link_del, &del_arg,
DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
DLADM_OPT_PERSIST);
}
(void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST);
(void) dladm_remove_conf(linkid);
done:
del_phys_arg->rval = status;
return (DLADM_WALK_CONTINUE);
}
dladm_status_t
dladm_phys_delete(datalink_id_t linkid)
{
del_phys_arg_t arg = {DLADM_STATUS_OK};
if (linkid == DATALINK_ALL_LINKID) {
(void) dladm_walk_datalink_id(i_dladm_phys_delete, &arg,
DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
DLADM_OPT_PERSIST);
return (DLADM_STATUS_OK);
} else {
(void) i_dladm_phys_delete(linkid, &arg);
return (arg.rval);
}
}
dladm_status_t
dladm_phys_info(datalink_id_t linkid, dladm_phys_attr_t *dpap, uint32_t flags)
{
dladm_status_t status;
assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
switch (flags) {
case DLADM_OPT_PERSIST: {
dladm_conf_t conf;
status = dladm_read_conf(linkid, &conf);
if (status != DLADM_STATUS_OK)
return (status);
status = dladm_get_conf_field(conf, FDEVNAME, dpap->dp_dev,
MAXLINKNAMELEN);
dladm_destroy_conf(conf);
return (status);
}
case DLADM_OPT_ACTIVE: {
dld_ioc_phys_attr_t dip;
int fd;
if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
return (dladm_errno2status(errno));
dip.dip_linkid = linkid;
if (i_dladm_ioctl(fd, DLDIOC_PHYS_ATTR, &dip, sizeof (dip))
< 0) {
status = dladm_errno2status(errno);
(void) close(fd);
return (status);
}
(void) close(fd);
dpap->dp_novanity = dip.dip_novanity;
(void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN);
return (DLADM_STATUS_OK);
}
default:
return (DLADM_STATUS_BADARG);
}
}
typedef struct i_walk_dev_state_s {
const char *devname;
datalink_id_t linkid;
boolean_t found;
} i_walk_dev_state_t;
int
i_dladm_walk_dev2linkid(datalink_id_t linkid, void *arg)
{
dladm_phys_attr_t dpa;
dladm_status_t status;
i_walk_dev_state_t *statep = arg;
status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST);
if ((status == DLADM_STATUS_OK) &&
(strcmp(statep->devname, dpa.dp_dev) == 0)) {
statep->found = B_TRUE;
statep->linkid = linkid;
return (DLADM_WALK_TERMINATE);
}
return (DLADM_WALK_CONTINUE);
}
/*
* Get the linkid from the physical device name.
*/
dladm_status_t
dladm_dev2linkid(const char *devname, datalink_id_t *linkidp)
{
i_walk_dev_state_t state;
state.found = B_FALSE;
state.devname = devname;
(void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, &state,
DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
if (state.found == B_TRUE) {
*linkidp = state.linkid;
return (DLADM_STATUS_OK);
} else {
return (dladm_errno2status(ENOENT));
}
}
static int
parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen)
{
char *cp, *tp;
int len;
/*
* device name length must not be 0, and it must end with digit.
*/
if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1]))
return (EINVAL);
(void) strlcpy(driver, devname, maxlen);
cp = (char *)&driver[len - 1];
for (tp = cp; isdigit(*tp); tp--) {
if (tp <= driver)
return (EINVAL);
}
*ppa = atoi(tp + 1);
*(tp + 1) = '\0';
return (0);
}
dladm_status_t
dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len)
{
char devname[MAXLINKNAMELEN];
uint16_t vid = VLAN_ID_NONE;
datalink_class_t class;
dladm_status_t status;
status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0);
if (status != DLADM_STATUS_OK)
goto done;
/*
* If this is a VLAN, we must first determine the class and linkid of
* the link the VLAN has been created over.
*/
if (class == DATALINK_CLASS_VLAN) {
dladm_vlan_attr_t dva;
status = dladm_vlan_info(linkid, &dva, DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK)
goto done;
linkid = dva.dv_linkid;
vid = dva.dv_vid;
if ((status = dladm_datalink_id2info(linkid, NULL, &class, NULL,
NULL, 0)) != DLADM_STATUS_OK) {
goto done;
}
}
switch (class) {
case DATALINK_CLASS_AGGR: {
dladm_aggr_grp_attr_t dga;
status = dladm_aggr_info(linkid, &dga, DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK)
goto done;
if (dga.lg_key == 0) {
/*
* If the key was not specified when the aggregation
* is created, we cannot guess its /dev node name.
*/
status = DLADM_STATUS_BADARG;
goto done;
}
(void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key);
break;
}
case DATALINK_CLASS_PHYS: {
dladm_phys_attr_t dpa;
status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST);
if (status != DLADM_STATUS_OK)
goto done;
(void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN);
break;
}
default:
status = DLADM_STATUS_BADARG;
goto done;
}
if (vid != VLAN_ID_NONE) {
char drv[MAXNAMELEN];
uint_t ppa;
if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) {
status = DLADM_STATUS_BADARG;
goto done;
}
if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len)
status = DLADM_STATUS_TOOSMALL;
} else {
if (strlcpy(dev, devname, len) >= len)
status = DLADM_STATUS_TOOSMALL;
}
done:
return (status);
}
dladm_status_t
dladm_get_single_mac_stat(datalink_id_t linkid, const char *name, uint8_t type,
void *val)
{
char module[DLPI_LINKNAME_MAX];
uint_t instance;
char link[DLPI_LINKNAME_MAX];
dladm_status_t status;
uint32_t flags, media;
kstat_ctl_t *kcp;
kstat_t *ksp;
dladm_phys_attr_t dpap;
if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media,
link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
return (status);
if (media != DL_ETHER)
return (DLADM_STATUS_LINKINVAL);
status = dladm_phys_info(linkid, &dpap, DLADM_OPT_PERSIST);
if (status != DLADM_STATUS_OK)
return (status);
status = dladm_parselink(dpap.dp_dev, module, &instance);
if (status != DLADM_STATUS_OK)
return (status);
if ((kcp = kstat_open()) == NULL)
return (dladm_errno2status(errno));
/*
* The kstat query could fail if the underlying MAC
* driver was already detached.
*/
if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
(ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL)
goto bail;
if (kstat_read(kcp, ksp, NULL) == -1)
goto bail;
if (dladm_kstat_value(ksp, name, type, val) < 0)
goto bail;
(void) kstat_close(kcp);
return (DLADM_STATUS_OK);
bail:
(void) kstat_close(kcp);
return (dladm_errno2status(errno));
}
int
dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
{
kstat_named_t *knp;
if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
return (-1);
if (knp->data_type != type)
return (-1);
switch (type) {
case KSTAT_DATA_UINT64:
*(uint64_t *)buf = knp->value.ui64;
break;
case KSTAT_DATA_UINT32:
*(uint32_t *)buf = knp->value.ui32;
break;
default:
return (-1);
}
return (0);
}
dladm_status_t
dladm_parselink(const char *dev, char *provider, uint_t *ppa)
{
ifspec_t ifsp;
if (dev == NULL || !ifparse_ifspec(dev, &ifsp))
return (DLADM_STATUS_LINKINVAL);
if (provider != NULL)
(void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX);
if (ppa != NULL)
*ppa = ifsp.ifsp_ppa;
return (DLADM_STATUS_OK);
}