libdllink.c revision d62bc4badc1c1f1549c961cfb8b420e650e1272b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <strings.h>
#include <librcm.h>
#include <libdlpi.h>
#include <libdevinfo.h>
#include <libdlaggr.h>
#include <libdlvlan.h>
#include <libdllink.h>
#include <libdlmgmt.h>
#include <libdladm_impl.h>
/*
* Return the attributes of the specified datalink from the DLD driver.
*/
static dladm_status_t
{
return (dladm_errno2status(errno));
return (DLADM_STATUS_OK);
}
struct i_dladm_walk_arg {
void *arg;
};
static int
{
char link[MAXLINKNAMELEN];
sizeof (link)) == DLADM_STATUS_OK) {
}
return (DLADM_WALK_CONTINUE);
}
/*
* Walk all datalinks.
*/
{
struct i_dladm_walk_arg walk_arg;
}
/*
* These routines are used by administration tools such as dladm(1M) to
* iterate through the list of MAC interfaces
*/
typedef struct dladm_mac_dev {
char dm_name[MAXNAMELEN];
struct dladm_mac_dev *dm_next;
typedef struct macadm_walk {
/*
* Local callback invoked for each DDI_NT_NET node.
*/
/* ARGSUSED */
static int
{
char mac[MAXNAMELEN];
/*
* Skip aggregations.
*/
return (DI_WALK_CONTINUE);
/*
* Skip softmacs.
*/
return (DI_WALK_CONTINUE);
while (dmdp) {
/*
* Skip duplicates.
*/
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
return (DI_WALK_CONTINUE);
}
/*
* Invoke the specified callback for each DDI_NT_NET node.
*/
{
return (dladm_errno2status(errno));
if (!done &&
}
}
return (DLADM_STATUS_OK);
}
/*
* Get the current attributes of the specified datalink.
*/
{
int fd;
return (dladm_errno2status(errno));
return (status);
}
const char *
{
const char *s;
switch (state) {
case LINK_STATE_UP:
s = "up";
break;
case LINK_STATE_DOWN:
s = "down";
break;
default:
s = "unknown";
break;
}
return (buf);
}
const char *
{
const char *s;
switch (duplex) {
case LINK_DUPLEX_FULL:
s = "full";
break;
case LINK_DUPLEX_HALF:
s = "half";
break;
default:
s = "unknown";
break;
}
return (buf);
}
/*
* Set zoneid of a given link
*/
{
int fd;
return (dladm_errno2status(errno));
return (status);
}
/*
* Get zoneid of a given link
*/
{
int fd;
return (dladm_errno2status(errno));
if (status == DLADM_STATUS_OK)
return (status);
}
/*
* Case 1: rename an existing link1 to a link2 that does not exist.
* Result: <linkid1, link2>
*/
static dladm_status_t
{
int fd;
/*
* Link is currently available. Check to see whether anything is
* holding this link to prevent a rename operation.
*/
if (flags & DLADM_OPT_ACTIVE) {
return (dladm_errno2status(errno));
return (status);
}
}
if (status != DLADM_STATUS_OK)
goto done;
/*
* Flush the current mapping to persistent configuration.
*/
if ((flags & DLADM_OPT_PERSIST) &&
}
done:
if (flags & DLADM_OPT_ACTIVE) {
if (status != DLADM_STATUS_OK) {
sizeof (dir));
}
}
return (status);
}
typedef struct link_hold_arg_s {
static int
{
int i;
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
return (DLADM_WALK_TERMINATE);
}
}
return (DLADM_WALK_CONTINUE);
}
static int
{
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
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
{
int fd;
char devname[MAXLINKNAMELEN];
/*
* First check if linkid1 is associated with any persistent
* aggregations or VLANs. If yes, return BUSY.
*/
return (DLADM_STATUS_LINKBUSY);
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.
*/
return (dladm_errno2status(errno));
if (status != DLADM_STATUS_OK) {
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.
*/
MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
sizeof (uint64_t))) != DLADM_STATUS_OK) ||
sizeof (uint64_t))) != DLADM_STATUS_OK) ||
(void) dladm_init_linkprop(linkid1);
return (status);
}
(void) dladm_write_conf(conf2);
/*
* Delete link1 and mark link2 up.
*/
(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.
*/
if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
goto done;
}
goto done;
RCM_SUCCESS) {
}
done:
(void) rcm_free_handle(rcm_hdl);
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
{
if (!dladm_valid_linkname(link1))
return (DLADM_STATUS_LINKINVAL);
if (status != DLADM_STATUS_OK)
goto done;
link1)) == DLADM_STATUS_OK) {
}
done:
return (status);
}
{
(flags2 == DLADM_OPT_PERSIST)) {
/*
* see whether link2 is a removed physical link.
*/
}
if (linkid1 != DATALINK_INVALID_LINKID) {
if (linkid2 == DATALINK_INVALID_LINKID) {
/*
* case 1: rename an existing link to a link that
* does not exist.
*/
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.
*/
!(flags1 & DLADM_OPT_ACTIVE)) {
} else {
linkid2);
}
} else {
}
} else if (remphy2) {
} else {
}
return (status);
}
typedef struct consumer_del_phys_arg_s {
static int
{
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
return (DLADM_WALK_CONTINUE);
}
static int
{
int i;
if (status != DLADM_STATUS_OK)
return (DLADM_WALK_CONTINUE);
break;
/*
* First delete all the VLANs on this aggregation, then
* delete the aggregation itself.
*/
} else {
}
}
return (DLADM_WALK_CONTINUE);
}
typedef struct del_phys_arg_s {
static int
{
goto done;
}
/*
* see whether this link is a removed physical link.
*/
(flags & DLADM_OPT_ACTIVE)) {
goto done;
}
}
(void) dladm_remove_conf(linkid);
done:
return (DLADM_WALK_CONTINUE);
}
{
if (linkid == DATALINK_ALL_LINKID) {
return (DLADM_STATUS_OK);
} else {
}
}
{
switch (flags) {
case DLADM_OPT_PERSIST: {
if (status != DLADM_STATUS_OK)
return (status);
return (status);
}
case DLADM_OPT_ACTIVE: {
int fd;
return (dladm_errno2status(errno));
< 0) {
return (status);
}
return (DLADM_STATUS_OK);
}
default:
return (DLADM_STATUS_BADARG);
}
}
typedef struct i_walk_dev_state_s {
const char *devname;
int
{
if ((status == DLADM_STATUS_OK) &&
return (DLADM_WALK_TERMINATE);
}
return (DLADM_WALK_CONTINUE);
}
/*
* Get the linkid from the physical device name.
*/
{
return (DLADM_STATUS_OK);
} else {
return (dladm_errno2status(ENOENT));
}
}
static int
{
int len;
/*
* device name length must not be 0, and it must end with digit.
*/
return (EINVAL);
return (EINVAL);
}
return (0);
}
{
char devname[MAXLINKNAMELEN];
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) {
if (status != DLADM_STATUS_OK)
goto done;
NULL, 0)) != DLADM_STATUS_OK) {
goto done;
}
}
switch (class) {
case DATALINK_CLASS_AGGR: {
if (status != DLADM_STATUS_OK)
goto done;
/*
* If the key was not specified when the aggregation
* is created, we cannot guess its /dev node name.
*/
goto done;
}
break;
}
case DATALINK_CLASS_PHYS: {
if (status != DLADM_STATUS_OK)
goto done;
break;
}
default:
goto done;
}
if (vid != VLAN_ID_NONE) {
char drv[MAXNAMELEN];
goto done;
}
} else {
}
done:
return (status);
}