/*
* 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
*/
/*
*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <door.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libdllink.h>
#include <libdlbridge.h>
#include <libdladm_impl.h>
#include <stp_in.h>
/*
* Bridge Administration Library.
*
* This library is used by administration tools such as dladm(1M) to configure
* bridges, and by the bridge daemon to retrieve configuration information.
*/
/* Bridge property-group */
/* Public bridge properties */
/* Private bridge properties */
/* Bridge properties to store during "down" */
/* TRILL property-group and property */
typedef struct scf_state {
} scf_state_t;
static void
{
}
static char *
{
char *fmri;
/* If the limit is unknown, then use an arbitrary value */
max_fmri = 1024;
}
return (fmri);
}
/*
* Start up SCF and bind the requested instance alone.
*/
static int
{
return (-1);
goto failure;
goto failure;
goto failure;
return (0);
return (-1);
}
/*
* Start up SCF and an exact FMRI. This is used for creating new instances and
*/
static dladm_status_t
{
return (DLADM_STATUS_NOMEM);
goto failure;
goto failure;
if (scf_error() == SCF_ERROR_NOT_FOUND)
goto failure;
}
goto failure;
return (DLADM_STATUS_OK);
return (status);
}
static void
{
}
/*
* This function sets up a composed view of the configuration information for
* the specified instance. When this is done, the get_property() function
* should be able to return individual parameters.
*/
static int
{
if (snap) {
goto failure;
goto failure;
}
goto failure;
goto failure;
NULL)
goto failure;
return (0);
return (-1);
}
static int
{
int retv;
return (-1);
return (-1);
retv = 0;
else
retv = -1;
return (retv);
}
static int
{
int retv;
return (-1);
return (-1);
retv = 0;
} else {
retv = -1;
}
return (retv);
}
static dladm_status_t
{
instname);
/* Knock on the door */
if (did == -1)
return (dladm_errno2status(errno));
return (DLADM_STATUS_NOMEM);
}
if (inlen != 0)
/* The door_call function doesn't restart, so take care of that */
do {
errno = 0;
break;
/* If we get an unexpected response, then return an error */
if (retv == 0) {
/* The daemon returns a single int for errors */
/* LINTED: pointer alignment */
retv = -1;
/* LINTED: pointer alignment */
}
/* Terminated daemon returns with zero data */
retv = -1;
}
}
if (retv == 0) {
if (is_list) {
void *newp;
retv = -1;
} else {
}
}
}
if (is_list) {
retv = -1;
}
}
/* Revoked door is the same as no door at all */
}
/*
* Wrapper function for making per-port calls.
*/
static dladm_status_t
{
if (status != DLADM_STATUS_OK)
return (status);
B_FALSE));
}
static dladm_status_t
{
void *bdptr;
char *fmri;
int refresh_count;
if (status == DLADM_STATUS_NOTFOUND)
return (DLADM_STATUS_OK);
if (status != DLADM_STATUS_OK)
return (status);
refresh_count = twoints[0];
return (DLADM_STATUS_NOMEM);
if (status == DLADM_STATUS_OK) {
int i = 0;
/*
* SMF doesn't give any synchronous behavior or dependency
* ordering for refresh operations, so we have to invent our
* own mechanism here. Get the refresh counter from the
* daemon, and wait for it to change. It's not pretty, but
* it's sufficient.
*/
while (++i <= 10) {
if (status != DLADM_STATUS_OK)
break;
if (twoints[0] != refresh_count)
break;
(void) usleep(100000);
}
return (DLADM_STATUS_NOMEM);
scf_error() == SCF_ERROR_NOT_FOUND ?
}
return (status);
}
/*
* Look up bridge property values from SCF and return them.
*/
{
cfg->field_mask = 0;
/* It's ok for this to be missing; it's installed separately */
0) {
if (trill_enabled)
}
&sstate) == 0) {
if (trill_enabled)
}
}
return (DLADM_STATUS_REPOSITORYINVAL);
!= 0) {
return (DLADM_STATUS_REPOSITORYINVAL);
}
}
}
}
}
}
return (DLADM_STATUS_OK);
}
/*
* Retrieve special non-settable and undocumented parameters.
*/
{
*tablemaxp = 10000;
return (DLADM_STATUS_REPOSITORYINVAL);
!= 0) {
return (DLADM_STATUS_REPOSITORYINVAL);
}
return (DLADM_STATUS_OK);
}
static boolean_t
{
return (B_FALSE);
goto out;
SCF_TYPE_COUNT) != 0 &&
SCF_TYPE_COUNT) != 0)
goto out;
return (B_TRUE);
out:
return (B_FALSE);
}
static boolean_t
{
return (B_FALSE);
goto out;
SCF_TYPE_BOOLEAN) != 0 &&
SCF_TYPE_BOOLEAN) != 0)
goto out;
return (B_TRUE);
out:
return (B_FALSE);
}
static boolean_t
{
return (B_FALSE);
goto out;
SCF_TYPE_ASTRING) != 0 &&
SCF_TYPE_ASTRING) != 0)
goto out;
goto out;
return (B_TRUE);
out:
return (B_FALSE);
}
static boolean_t
{
return (B_FALSE);
goto out;
SCF_TYPE_FMRI) != 0 &&
SCF_TYPE_FMRI) != 0)
goto out;
goto out;
return (B_TRUE);
out:
return (B_FALSE);
}
/*
* Set private bridge parameters.
*/
static void
{
int rv = 0;
char *fmri;
return;
!= 0)
goto out;
goto out;
goto out;
goto out;
do {
goto out;
goto out;
goto out;
goto out;
} while (rv == 0);
out:
}
(void) smf_refresh_instance(fmri);
}
}
static dladm_status_t
{
if (status == DLADM_STATUS_OK) {
/*
* Create the datalink entry for the bridge. Note that all of
* the real configuration information is in SMF.
*/
}
return (status);
}
/* Convert bridge protection option string to dladm_bridge_prot_t */
{
else
return (DLADM_STATUS_BADARG);
return (DLADM_STATUS_OK);
}
/* Convert bridge protection option from dladm_bridge_prot_t to string */
const char *
{
switch (brprot) {
case DLADM_BRIDGE_PROT_STP:
return ("stp");
case DLADM_BRIDGE_PROT_TRILL:
return ("trill");
default:
return ("unknown");
}
}
static dladm_status_t
{
return (DLADM_STATUS_NOMEM);
return (status);
}
/*
* Shut down a possibly-running service instance. If this is a permanent
* change, then delete it from the system.
*/
static dladm_status_t
{
char *state;
return (DLADM_STATUS_NOMEM);
if (smf_disable_instance(fmri,
/* If we can disable, then wait for it to happen. */
break;
usecs *= 2;
}
if (umax == 0) {
umax = 1;
}
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
return (DLADM_STATUS_OK);
} else {
}
}
return (status);
}
static dladm_status_t
{
}
/*
* To enable TRILL, we must create a new instance of the TRILL service, then
* add proper dependencies to it, and finally mark it as enabled. The
* dependencies will keep it from going on-line until the bridge is running.
*/
static dladm_status_t
{
int rv;
/*
* This check is here in case the user has installed and then removed
* the package. SMF should remove the manifest, but currently does
* not.
*/
return (DLADM_STATUS_OPTMISSING);
goto out;
0) {
goto out;
}
goto out;
goto out;
goto out;
}
goto out;
goto out;
do {
goto out;
goto out;
goto out;
SCF_PROPERTY_TYPE, "service"))
goto out;
goto out;
goto out;
} while (rv == 0);
if (rv != 1)
goto out;
out:
}
/*
* If we created an instance and then failed, then remove the instance
* from the system.
*/
if (status == DLADM_STATUS_OK)
return (status);
}
/*
* Create a new bridge or modify an existing one. Update the SMF configuration
* and add links.
*
* Input timer values are in IEEE scaled (* 256) format.
*/
{
int rv;
if (!dladm_valid_bridgename(name))
return (DLADM_STATUS_FAILED);
if (flags & DLADM_OPT_CREATE) {
/*
* This check is here in case the user has installed and then
* removed the package. SMF should remove the manifest, but
* currently does not.
*/
return (DLADM_STATUS_OPTMISSING);
if (status != DLADM_STATUS_OK)
return (status);
if ((flags & DLADM_OPT_PERSIST) &&
linkid) != DLADM_STATUS_OK))
goto dladm_fail;
}
if (brprot == DLADM_BRIDGE_PROT_TRILL)
else
if (status != DLADM_STATUS_OK)
goto dladm_fail;
goto out;
/* set up for a series of scf calls */
0) {
if (flags & DLADM_OPT_CREATE) {
goto out;
}
} else {
if (!(flags & DLADM_OPT_CREATE)) {
goto out;
}
goto out;
}
goto out;
goto out;
goto out;
}
do {
goto out;
goto out;
goto out;
goto out;
goto out;
goto out;
goto out;
} while (rv == 0);
if (rv != 1)
goto out;
}
/*
* If we're modifying an existing and running bridge, then tell the
* daemon to update the requested values.
*/
else
out:
}
/*
* If we created an instance and then failed, then remove the instance
* from the system.
*/
/*
* Remove the bridge linkid if we've allocated one in this function but
* we've failed to set up the SMF properties.
*/
}
return (status);
}
/*
* deleting any "general_ovr/enabled" (used for temporary services).
*/
{
}
/*
* Set a link as a member of a bridge, or remove bridge membership. If the
* DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running.
* In all other cases, we must tell the daemon to add or delete the link in
* order to stay in sync.
*/
const char *bridge)
{
return (DLADM_STATUS_FAILED);
if (status != DLADM_STATUS_OK)
return (status);
sizeof (oldbridge));
if (status == DLADM_STATUS_OK) {
/*
* Don't allow a link to be reassigned directly from one bridge
* to another. It must be removed first.
*/
goto out;
}
} else if (status != DLADM_STATUS_NOTFOUND) {
goto out;
}
if (*bridge != '\0') {
} else if (has_oldbridge) {
} else {
goto out;
}
if (status == DLADM_STATUS_OK)
out:
if (bridge[0] == '\0')
}
return (status);
}
/*
* Get the name of the bridge of which the given linkid is a member.
*/
{
return (status);
*bridge = '\0';
return (status);
}
{
if (status == DLADM_STATUS_NOTFOUND)
return (DLADM_STATUS_OK);
if (status == DLADM_STATUS_OK)
return (status);
}
typedef struct bridge_held_arg_s {
const char *bha_bridge;
static int
{
return (DLADM_WALK_CONTINUE);
sizeof (bridge));
return (DLADM_WALK_TERMINATE);
} else {
return (DLADM_WALK_CONTINUE);
}
}
/*
* Delete a previously created bridge.
*/
{
if (!dladm_valid_bridgename(bridge))
return (DLADM_STATUS_LINKINVAL);
/* Get the datalink ID for this bridge */
NULL, 0) != DLADM_STATUS_OK)
else if (class != DATALINK_CLASS_BRIDGE)
return (DLADM_STATUS_BADARG);
return (DLADM_STATUS_BADARG);
if (flags & DLADM_OPT_PERSIST) {
/*
* See whether there are any persistent links using this
* bridge. If so, we fail the operation.
*/
if (arg.bha_isheld)
return (DLADM_STATUS_LINKBUSY);
}
goto out;
/* Disable or remove the SMF instance */
if (status != DLADM_STATUS_OK)
goto out;
if (flags & DLADM_OPT_ACTIVE) {
/*
* Delete ACTIVE linkprop now that daemon is gone.
*/
}
if (flags & DLADM_OPT_PERSIST) {
}
out:
return (status);
}
/* Check if given name is valid for bridges */
{
const char *cp;
if (len == MAXLINKNAMELEN)
return (B_FALSE);
/*
* The bridge name cannot start or end with a digit.
*/
return (B_FALSE);
/*
* The legal characters within a bridge name are:
* alphanumeric (a-z, A-Z, 0-9), and the underscore ('_').
*/
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Convert a bridge-related observability node name back into the name of the
* bridge. Returns B_FALSE without making changes if the input name is not in
* a legal format.
*/
{
int llen;
return (B_FALSE);
return (B_TRUE);
}
/*
* Get bridge property values from the running daemon and return them in a
* common structure.
*/
{
if (status == DLADM_STATUS_OK) {
} else {
smcfg->field_mask = 0;
}
return (status);
}
/*
* Get bridge state from the running daemon and return in structure borrowed
* from librstp.
*/
{
}
/* Returns list of ports (datalink_id_t values) assigned to a bridge instance */
{
int *rbuf;
return (NULL);
return (NULL);
} else {
/*
* Returns an array of datalink_id_t values for all the ports
* part of the bridge instance. First entry in the array is the
* number of ports.
*/
}
}
void
{
}
/* Retrieve Bridge port configuration values */
{
0, sizeof (portcfg));
if (status != DLADM_STATUS_OK)
return (status);
switch (field) {
case PT_CFG_COST:
break;
case PT_CFG_PRIO:
break;
case PT_CFG_P2P:
break;
case PT_CFG_EDGE:
break;
case PT_CFG_NON_STP:
break;
case PT_CFG_MCHECK:
break;
}
return (status);
}
/* Retreive Bridge port status (disabled, bad SDU etc.) */
{
sizeof (*spsp)));
}
/* Retrieve Bridge forwarding status of the given link */
{
0, sizeof (twoints));
if (status == DLADM_STATUS_OK)
return (status);
}
/* Retrieve Bridge forwarding table entries */
{
int rc;
"%s0", bridge);
for (;;) {
break;
}
}
if (rc != 0) {
break;
}
break;
}
return (blf);
}
void
{
}
/* Retrieve list of TRILL nicknames from the TRILL module */
{
int fd;
return (NULL);
return (NULL);
}
for (;;) {
break;
}
}
break;
}
break;
}
return (tln);
}
void
{
}
/* Retrieve any stored TRILL nickname from TRILL SMF service */
{
return (nickname);
== 0 &&
return (nickname);
}
/* Stores TRILL nickname in SMF configuraiton for the TRILL service */
void
{
int rv = 0;
char *fmri;
return;
0)
goto out;
goto out;
goto out;
goto out;
}
do {
goto out;
nick))
goto out;
goto out;
} while (rv == 0);
out:
}
(void) smf_refresh_instance(fmri);
}
}
/*
* Get the bridge name from the given linkid. Replace the final 0 in the link
* name with \0.
*/
static dladm_status_t
{
if (status == DLADM_STATUS_OK)
return (status);
}
/*
* Bring up a persistent bridge. The bridge's SMF instance is created and
* enabled and its properties from datalink-<profile>.conf are applied to that
* SMF instance. This allows the bridge to be profile-specific.
*/
static int
{
sizeof (bridge))) != DLADM_STATUS_OK)
return (status);
/* Retrieve the properties from datalink.conf */
!= DLADM_STATUS_OK)
return (status);
/*
* Read back all the properties written out in i_dladm_bridge_down()
* and remove them from datalink.conf.
*/
goto done;
goto done;
goto done;
!= DLADM_STATUS_OK)
goto done;
goto done;
goto done;
!= DLADM_STATUS_OK ||
goto done;
!= DLADM_STATUS_OK)
goto done;
goto done;
sizeof (u64))) != DLADM_STATUS_OK ||
!= DLADM_STATUS_OK)
goto done;
/*
* Add the SMF instance for this bridge. dladm_configure_bridge()
* will add the instance only if DLADM_OPT_CREATE flag is passed, but
* passing that flag also tries to create a new linkid. Since we
* don't want that, we'll create the instance first and then configure
* the bridge.
*/
!= DLADM_STATUS_OK)
goto done;
!= 0) {
goto done;
}
/* Configure bridge, set TRILL nickname and private bridge parameters */
if (status != DLADM_STATUS_OK)
goto done;
/* Finally, enable the bridge */
/*
* Write the updated datalink.conf file, the properties written to
* datalink.conf in i_dladm_bridge_up() have been removed.
*/
!= DLADM_STATUS_OK)
goto done;
done:
return (DLADM_WALK_CONTINUE);
}
/*
* Bring up a previously created persistent bridge or all persistent bridges.
*/
{
if (linkid == DATALINK_ALL_LINKID) {
} else {
}
return (status);
}
/*
* Bring down an active bridge. The bridge's configuration is stored in
* datalink-<profile>.conf from the SMF instance, which is then removed. This
* allows bridges to be profile-specific.
*/
static int
{
sizeof (bridge))) != DLADM_STATUS_OK)
goto done;
/*
* Retrieve the bridge properties from the bridge and trill SMF
* services and write the protection and the values of these properties
* to datalink.conf.
*/
!= DLADM_STATUS_OK)
goto done;
!= DLADM_STATUS_OK)
goto done;
!= DLADM_STATUS_OK)
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
!= DLADM_STATUS_OK)
goto done;
/* The following are private bridge parameters */
goto done;
goto done;
/* The following is the TRILL nickname */
goto done;
!= DLADM_STATUS_OK)
goto done;
/*
* Disable and remove the instances of this bridge from
*/
done:
if (conf_opened)
return (DLADM_WALK_CONTINUE);
}
/*
* Bring down one bridge or all active bridges. Persistent configuration and
* linkid mapping in dlmgmtd is not removed. Downed bridge(s) can be brought
* up with dladm_bridge_up().
*/
{
if (linkid == DATALINK_ALL_LINKID) {
} else {
}
return (status);
}