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) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <sys/types.h>
2N/A#include <string.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <stropts.h>
2N/A#include <ctype.h>
2N/A#include <errno.h>
2N/A#include <stdlib.h>
2N/A#include <door.h>
2N/A#include <sys/mman.h>
2N/A#include <libscf.h>
2N/A#include <libscf_priv.h>
2N/A#include <libdllink.h>
2N/A#include <libdlbridge.h>
2N/A#include <libdladm_impl.h>
2N/A#include <stp_in.h>
2N/A#include <net/bridge.h>
2N/A#include <net/trill.h>
2N/A#include <sys/socket.h>
2N/A#include <sys/dld_ioc.h>
2N/A
2N/A/*
2N/A * Bridge Administration Library.
2N/A *
2N/A * This library is used by administration tools such as dladm(1M) to configure
2N/A * bridges, and by the bridge daemon to retrieve configuration information.
2N/A */
2N/A
2N/A#define BRIDGE_SVC_NAME "network/bridge"
2N/A#define TRILL_SVC_NAME "network/routing/trill"
2N/A
2N/A#define DEFAULT_TIMEOUT 60000000
2N/A#define INIT_WAIT_USECS 50000
2N/A#define MAXPORTS 256
2N/A
2N/A/* Bridge property-group */
2N/A#define BRIDGE_PROP_PG_CONFIG "config"
2N/A/* Public bridge properties */
2N/A#define BRIDGE_PROP_PRIORITY "priority"
2N/A#define BRIDGE_PROP_MAX_AGE "max-age"
2N/A#define BRIDGE_PROP_HELLO_TIME "hello-time"
2N/A#define BRIDGE_PROP_FWD_DELAY "forward-delay"
2N/A#define BRIDGE_PROP_FORCE_PROTOCOL "force-protocol"
2N/A/* Private bridge properties */
2N/A#define BRIDGE_PROP_DEBUG "debug"
2N/A#define BRIDGE_PROP_TABLE_MAX "table-maximum"
2N/A/* Bridge properties to store during "down" */
2N/A#define BRIDGE_PROP_FIELD_MASK "field-mask"
2N/A#define BRIDGE_PROP_PROTECT "protect"
2N/A
2N/A/* TRILL property-group and property */
2N/A#define TRILL_PROP_PG_CONFIG "config"
2N/A#define TRILL_PROP_NICK "nickname"
2N/A
2N/Atypedef struct scf_state {
2N/A scf_handle_t *ss_handle;
2N/A scf_instance_t *ss_inst;
2N/A scf_service_t *ss_svc;
2N/A scf_snapshot_t *ss_snap;
2N/A scf_propertygroup_t *ss_pg;
2N/A scf_property_t *ss_prop;
2N/A} scf_state_t;
2N/A
2N/Astatic void
2N/Ashut_down_scf(scf_state_t *sstate)
2N/A{
2N/A scf_instance_destroy(sstate->ss_inst);
2N/A (void) scf_handle_unbind(sstate->ss_handle);
2N/A scf_handle_destroy(sstate->ss_handle);
2N/A}
2N/A
2N/Astatic char *
2N/Aalloc_fmri(const char *service, const char *instance_name)
2N/A{
2N/A ssize_t max_fmri;
2N/A char *fmri;
2N/A
2N/A /* If the limit is unknown, then use an arbitrary value */
2N/A if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1)
2N/A max_fmri = 1024;
2N/A if ((fmri = malloc(max_fmri)) != NULL) {
2N/A (void) snprintf(fmri, max_fmri, "svc:/%s:%s", service,
2N/A instance_name);
2N/A }
2N/A return (fmri);
2N/A}
2N/A
2N/A/*
2N/A * Start up SCF and bind the requested instance alone.
2N/A */
2N/Astatic int
2N/Abind_instance(const char *service, const char *instance_name,
2N/A scf_state_t *sstate)
2N/A{
2N/A char *fmri = NULL;
2N/A
2N/A (void) memset(sstate, 0, sizeof (*sstate));
2N/A
2N/A if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
2N/A return (-1);
2N/A
2N/A if (scf_handle_bind(sstate->ss_handle) != 0)
2N/A goto failure;
2N/A sstate->ss_inst = scf_instance_create(sstate->ss_handle);
2N/A if (sstate->ss_inst == NULL)
2N/A goto failure;
2N/A
2N/A fmri = alloc_fmri(service, instance_name);
2N/A
2N/A if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL,
2N/A sstate->ss_inst, NULL, NULL,
2N/A SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0)
2N/A goto failure;
2N/A free(fmri);
2N/A return (0);
2N/A
2N/Afailure:
2N/A free(fmri);
2N/A shut_down_scf(sstate);
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Start up SCF and an exact FMRI. This is used for creating new instances and
2N/A * enable/disable actions.
2N/A */
2N/Astatic dladm_status_t
2N/Aexact_instance(const char *fmri, scf_state_t *sstate)
2N/A{
2N/A dladm_status_t status;
2N/A
2N/A (void) memset(sstate, 0, sizeof (*sstate));
2N/A
2N/A if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A status = DLADM_STATUS_FAILED;
2N/A if (scf_handle_bind(sstate->ss_handle) != 0)
2N/A goto failure;
2N/A sstate->ss_svc = scf_service_create(sstate->ss_handle);
2N/A if (sstate->ss_svc == NULL)
2N/A goto failure;
2N/A if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL,
2N/A sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
2N/A if (scf_error() == SCF_ERROR_NOT_FOUND)
2N/A status = DLADM_STATUS_OPTMISSING;
2N/A goto failure;
2N/A }
2N/A sstate->ss_inst = scf_instance_create(sstate->ss_handle);
2N/A if (sstate->ss_inst == NULL)
2N/A goto failure;
2N/A return (DLADM_STATUS_OK);
2N/A
2N/Afailure:
2N/A shut_down_scf(sstate);
2N/A return (status);
2N/A}
2N/A
2N/Astatic void
2N/Adrop_composed(scf_state_t *sstate)
2N/A{
2N/A scf_property_destroy(sstate->ss_prop);
2N/A scf_pg_destroy(sstate->ss_pg);
2N/A scf_snapshot_destroy(sstate->ss_snap);
2N/A}
2N/A
2N/A/*
2N/A * This function sets up a composed view of the configuration information for
2N/A * the specified instance. When this is done, the get_property() function
2N/A * should be able to return individual parameters.
2N/A */
2N/Astatic int
2N/Aget_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate)
2N/A{
2N/A sstate->ss_snap = NULL;
2N/A sstate->ss_pg = NULL;
2N/A sstate->ss_prop = NULL;
2N/A
2N/A if (snap) {
2N/A sstate->ss_snap = scf_snapshot_create(sstate->ss_handle);
2N/A if (sstate->ss_snap == NULL)
2N/A goto failure;
2N/A if (scf_instance_get_snapshot(sstate->ss_inst, "running",
2N/A sstate->ss_snap) != 0)
2N/A goto failure;
2N/A }
2N/A if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL)
2N/A goto failure;
2N/A if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg,
2N/A sstate->ss_pg) != 0)
2N/A goto failure;
2N/A if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) ==
2N/A NULL)
2N/A goto failure;
2N/A return (0);
2N/A
2N/Afailure:
2N/A drop_composed(sstate);
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Aget_count(const char *lprop, scf_state_t *sstate, uint64_t *answer)
2N/A{
2N/A scf_value_t *val;
2N/A int retv;
2N/A
2N/A if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
2N/A return (-1);
2N/A if ((val = scf_value_create(sstate->ss_handle)) == NULL)
2N/A return (-1);
2N/A
2N/A if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
2N/A scf_value_get_count(val, answer) == 0)
2N/A retv = 0;
2N/A else
2N/A retv = -1;
2N/A scf_value_destroy(val);
2N/A return (retv);
2N/A}
2N/A
2N/Astatic int
2N/Aget_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer)
2N/A{
2N/A scf_value_t *val;
2N/A int retv;
2N/A uint8_t bval;
2N/A
2N/A if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
2N/A return (-1);
2N/A if ((val = scf_value_create(sstate->ss_handle)) == NULL)
2N/A return (-1);
2N/A
2N/A if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
2N/A scf_value_get_boolean(val, &bval) == 0) {
2N/A retv = 0;
2N/A *answer = bval != 0;
2N/A } else {
2N/A retv = -1;
2N/A }
2N/A scf_value_destroy(val);
2N/A return (retv);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Abridge_door_call(const char *instname, bridge_door_type_t dtype,
2N/A datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp,
2N/A boolean_t is_list)
2N/A{
2N/A char doorname[MAXPATHLEN];
2N/A int did, retv, etmp;
2N/A bridge_door_cmd_t *bdc;
2N/A door_arg_t arg;
2N/A
2N/A (void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME,
2N/A instname);
2N/A
2N/A /* Knock on the door */
2N/A did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
2N/A if (did == -1)
2N/A return (dladm_errno2status(errno));
2N/A
2N/A if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) {
2N/A (void) close(did);
2N/A return (DLADM_STATUS_NOMEM);
2N/A }
2N/A bdc->bdc_type = dtype;
2N/A bdc->bdc_linkid = linkid;
2N/A if (inlen != 0)
2N/A (void) memcpy(bdc + 1, *bufp, inlen);
2N/A
2N/A (void) memset(&arg, 0, sizeof (arg));
2N/A arg.data_ptr = (char *)bdc;
2N/A arg.data_size = sizeof (*bdc) + inlen;
2N/A arg.rbuf = *bufp;
2N/A arg.rsize = *buflenp;
2N/A
2N/A /* The door_call function doesn't restart, so take care of that */
2N/A do {
2N/A errno = 0;
2N/A if ((retv = door_call(did, &arg)) == 0)
2N/A break;
2N/A } while (errno == EINTR);
2N/A
2N/A /* If we get an unexpected response, then return an error */
2N/A if (retv == 0) {
2N/A /* The daemon returns a single int for errors */
2N/A /* LINTED: pointer alignment */
2N/A if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) {
2N/A retv = -1;
2N/A /* LINTED: pointer alignment */
2N/A errno = *(int *)arg.rbuf;
2N/A }
2N/A /* Terminated daemon returns with zero data */
2N/A if (arg.data_size == 0) {
2N/A retv = -1;
2N/A errno = EBADF;
2N/A }
2N/A }
2N/A
2N/A if (retv == 0) {
2N/A if (arg.rbuf != *bufp) {
2N/A if (is_list) {
2N/A void *newp;
2N/A
2N/A newp = realloc(*bufp, arg.data_size);
2N/A if (newp == NULL) {
2N/A retv = -1;
2N/A } else {
2N/A *bufp = newp;
2N/A (void) memcpy(*bufp, arg.rbuf,
2N/A arg.data_size);
2N/A }
2N/A }
2N/A (void) munmap(arg.rbuf, arg.rsize);
2N/A }
2N/A if (is_list) {
2N/A *buflenp = arg.data_size;
2N/A } else if (arg.data_size != *buflenp || arg.rbuf != *bufp) {
2N/A errno = EINVAL;
2N/A retv = -1;
2N/A }
2N/A }
2N/A
2N/A etmp = errno;
2N/A (void) close(did);
2N/A
2N/A /* Revoked door is the same as no door at all */
2N/A if (etmp == EBADF)
2N/A etmp = ENOENT;
2N/A
2N/A return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp));
2N/A}
2N/A
2N/A/*
2N/A * Wrapper function for making per-port calls.
2N/A */
2N/Astatic dladm_status_t
2N/Aport_door_call(dladm_handle_t handle, datalink_id_t linkid,
2N/A bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen)
2N/A{
2N/A char bridge[MAXLINKNAMELEN];
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen,
2N/A B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Abridge_refresh(const char *bridge)
2N/A{
2N/A dladm_status_t status;
2N/A int twoints[2];
2N/A void *bdptr;
2N/A size_t buflen;
2N/A char *fmri;
2N/A int refresh_count;
2N/A
2N/A buflen = sizeof (twoints);
2N/A bdptr = twoints;
2N/A status = bridge_door_call(bridge, bdcBridgeGetRefreshCount,
2N/A DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE);
2N/A if (status == DLADM_STATUS_NOTFOUND)
2N/A return (DLADM_STATUS_OK);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A refresh_count = twoints[0];
2N/A if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A status = smf_refresh_instance(fmri) == 0 ?
2N/A DLADM_STATUS_OK : DLADM_STATUS_FAILED;
2N/A free(fmri);
2N/A if (status == DLADM_STATUS_OK) {
2N/A int i = 0;
2N/A
2N/A /*
2N/A * SMF doesn't give any synchronous behavior or dependency
2N/A * ordering for refresh operations, so we have to invent our
2N/A * own mechanism here. Get the refresh counter from the
2N/A * daemon, and wait for it to change. It's not pretty, but
2N/A * it's sufficient.
2N/A */
2N/A while (++i <= 10) {
2N/A buflen = sizeof (twoints);
2N/A bdptr = twoints;
2N/A status = bridge_door_call(bridge,
2N/A bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID,
2N/A &bdptr, 0, &buflen, B_FALSE);
2N/A if (status != DLADM_STATUS_OK)
2N/A break;
2N/A if (twoints[0] != refresh_count)
2N/A break;
2N/A (void) usleep(100000);
2N/A }
2N/A fmri = alloc_fmri(TRILL_SVC_NAME, bridge);
2N/A if (fmri == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A status = smf_refresh_instance(fmri) == 0 ||
2N/A scf_error() == SCF_ERROR_NOT_FOUND ?
2N/A DLADM_STATUS_OK : DLADM_STATUS_FAILED;
2N/A free(fmri);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Look up bridge property values from SCF and return them.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg,
2N/A dladm_bridge_prot_t *brprotp)
2N/A{
2N/A scf_state_t sstate;
2N/A uint64_t value;
2N/A boolean_t trill_enabled;
2N/A
2N/A cfg->field_mask = 0;
2N/A cfg->bridge_priority = DEF_BR_PRIO;
2N/A cfg->max_age = DEF_BR_MAXAGE;
2N/A cfg->hello_time = DEF_BR_HELLOT;
2N/A cfg->forward_delay = DEF_BR_FWDELAY;
2N/A cfg->force_version = DEF_FORCE_VERS;
2N/A
2N/A (void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name));
2N/A
2N/A *brprotp = DLADM_BRIDGE_PROT_STP;
2N/A
2N/A /* It's ok for this to be missing; it's installed separately */
2N/A if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) {
2N/A trill_enabled = B_FALSE;
2N/A if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) ==
2N/A 0) {
2N/A (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
2N/A &trill_enabled);
2N/A if (trill_enabled)
2N/A *brprotp = DLADM_BRIDGE_PROT_TRILL;
2N/A drop_composed(&sstate);
2N/A }
2N/A if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE,
2N/A &sstate) == 0) {
2N/A (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
2N/A &trill_enabled);
2N/A if (trill_enabled)
2N/A *brprotp = DLADM_BRIDGE_PROT_TRILL;
2N/A drop_composed(&sstate);
2N/A }
2N/A shut_down_scf(&sstate);
2N/A }
2N/A
2N/A cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ?
2N/A STP_ENABLED : STP_DISABLED;
2N/A cfg->field_mask |= BR_CFG_STATE;
2N/A
2N/A if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
2N/A return (DLADM_STATUS_REPOSITORYINVAL);
2N/A
2N/A if (get_composed_properties(BRIDGE_PROP_PG_CONFIG, B_TRUE, &sstate)
2N/A != 0) {
2N/A shut_down_scf(&sstate);
2N/A return (DLADM_STATUS_REPOSITORYINVAL);
2N/A }
2N/A
2N/A if (get_count(BRIDGE_PROP_PRIORITY, &sstate, &value) == 0) {
2N/A cfg->bridge_priority = value;
2N/A cfg->field_mask |= BR_CFG_PRIO;
2N/A }
2N/A if (get_count(BRIDGE_PROP_MAX_AGE, &sstate, &value) == 0) {
2N/A cfg->max_age = value / IEEE_TIMER_SCALE;
2N/A cfg->field_mask |= BR_CFG_AGE;
2N/A }
2N/A if (get_count(BRIDGE_PROP_HELLO_TIME, &sstate, &value) == 0) {
2N/A cfg->hello_time = value / IEEE_TIMER_SCALE;
2N/A cfg->field_mask |= BR_CFG_HELLO;
2N/A }
2N/A if (get_count(BRIDGE_PROP_FWD_DELAY, &sstate, &value) == 0) {
2N/A cfg->forward_delay = value / IEEE_TIMER_SCALE;
2N/A cfg->field_mask |= BR_CFG_DELAY;
2N/A }
2N/A if (get_count(BRIDGE_PROP_FORCE_PROTOCOL, &sstate, &value) == 0) {
2N/A cfg->force_version = value;
2N/A cfg->field_mask |= BR_CFG_FORCE_VER;
2N/A }
2N/A
2N/A drop_composed(&sstate);
2N/A shut_down_scf(&sstate);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Retrieve special non-settable and undocumented parameters.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp,
2N/A uint32_t *tablemaxp)
2N/A{
2N/A scf_state_t sstate;
2N/A uint64_t value;
2N/A
2N/A *debugp = B_FALSE;
2N/A *tablemaxp = 10000;
2N/A
2N/A if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
2N/A return (DLADM_STATUS_REPOSITORYINVAL);
2N/A
2N/A if (get_composed_properties(BRIDGE_PROP_PG_CONFIG, B_TRUE, &sstate)
2N/A != 0) {
2N/A shut_down_scf(&sstate);
2N/A return (DLADM_STATUS_REPOSITORYINVAL);
2N/A }
2N/A
2N/A (void) get_boolean(BRIDGE_PROP_DEBUG, &sstate, debugp);
2N/A if (get_count(BRIDGE_PROP_TABLE_MAX, &sstate, &value) == 0)
2N/A *tablemaxp = (uint32_t)value;
2N/A
2N/A drop_composed(&sstate);
2N/A shut_down_scf(&sstate);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Aset_count_property(scf_handle_t *handle, scf_transaction_t *tran,
2N/A const char *propname, uint64_t propval)
2N/A{
2N/A scf_transaction_entry_t *entry;
2N/A scf_value_t *value = NULL;
2N/A
2N/A if ((entry = scf_entry_create(handle)) == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((value = scf_value_create(handle)) == NULL)
2N/A goto out;
2N/A if (scf_transaction_property_new(tran, entry, propname,
2N/A SCF_TYPE_COUNT) != 0 &&
2N/A scf_transaction_property_change(tran, entry, propname,
2N/A SCF_TYPE_COUNT) != 0)
2N/A goto out;
2N/A scf_value_set_count(value, propval);
2N/A if (scf_entry_add_value(entry, value) == 0)
2N/A return (B_TRUE);
2N/A
2N/Aout:
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A
2N/A scf_entry_destroy_children(entry);
2N/A scf_entry_destroy(entry);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Aset_boolean_property(scf_handle_t *handle, scf_transaction_t *tran,
2N/A const char *propname, boolean_t propval)
2N/A{
2N/A scf_transaction_entry_t *entry;
2N/A scf_value_t *value = NULL;
2N/A
2N/A if ((entry = scf_entry_create(handle)) == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((value = scf_value_create(handle)) == NULL)
2N/A goto out;
2N/A if (scf_transaction_property_new(tran, entry, propname,
2N/A SCF_TYPE_BOOLEAN) != 0 &&
2N/A scf_transaction_property_change(tran, entry, propname,
2N/A SCF_TYPE_BOOLEAN) != 0)
2N/A goto out;
2N/A scf_value_set_boolean(value, propval);
2N/A if (scf_entry_add_value(entry, value) == 0)
2N/A return (B_TRUE);
2N/A
2N/Aout:
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A
2N/A scf_entry_destroy_children(entry);
2N/A scf_entry_destroy(entry);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Aset_string_property(scf_handle_t *handle, scf_transaction_t *tran,
2N/A const char *propname, const char *propval)
2N/A{
2N/A scf_transaction_entry_t *entry;
2N/A scf_value_t *value = NULL;
2N/A
2N/A if ((entry = scf_entry_create(handle)) == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((value = scf_value_create(handle)) == NULL)
2N/A goto out;
2N/A if (scf_transaction_property_new(tran, entry, propname,
2N/A SCF_TYPE_ASTRING) != 0 &&
2N/A scf_transaction_property_change(tran, entry, propname,
2N/A SCF_TYPE_ASTRING) != 0)
2N/A goto out;
2N/A if (scf_value_set_astring(value, propval) != 0)
2N/A goto out;
2N/A if (scf_entry_add_value(entry, value) == 0)
2N/A return (B_TRUE);
2N/A
2N/Aout:
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A
2N/A scf_entry_destroy_children(entry);
2N/A scf_entry_destroy(entry);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Aset_fmri_property(scf_handle_t *handle, scf_transaction_t *tran,
2N/A const char *propname, const char *propval)
2N/A{
2N/A scf_transaction_entry_t *entry;
2N/A scf_value_t *value = NULL;
2N/A
2N/A if ((entry = scf_entry_create(handle)) == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((value = scf_value_create(handle)) == NULL)
2N/A goto out;
2N/A if (scf_transaction_property_new(tran, entry, propname,
2N/A SCF_TYPE_FMRI) != 0 &&
2N/A scf_transaction_property_change(tran, entry, propname,
2N/A SCF_TYPE_FMRI) != 0)
2N/A goto out;
2N/A if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0)
2N/A goto out;
2N/A if (scf_entry_add_value(entry, value) == 0)
2N/A return (B_TRUE);
2N/A
2N/Aout:
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A
2N/A scf_entry_destroy_children(entry);
2N/A scf_entry_destroy(entry);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * Set private bridge parameters.
2N/A */
2N/Astatic void
2N/Adladm_bridge_set_privprop(const char *bridge, boolean_t debug,
2N/A uint32_t tablemax)
2N/A{
2N/A scf_state_t sstate;
2N/A scf_transaction_t *tran = NULL;
2N/A int rv = 0;
2N/A char *fmri;
2N/A
2N/A if (exact_instance(BRIDGE_SVC_NAME, &sstate) != DLADM_STATUS_OK)
2N/A return;
2N/A if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst)
2N/A != 0)
2N/A goto out;
2N/A if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A if (scf_instance_get_pg(sstate.ss_inst, BRIDGE_PROP_PG_CONFIG,
2N/A sstate.ss_pg) != 0)
2N/A goto out;
2N/A
2N/A do {
2N/A if (scf_transaction_start(tran, sstate.ss_pg) != 0)
2N/A goto out;
2N/A if (!set_count_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_TABLE_MAX, tablemax))
2N/A goto out;
2N/A if (!set_boolean_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_DEBUG, debug))
2N/A goto out;
2N/A rv = scf_transaction_commit(tran);
2N/A scf_transaction_reset(tran);
2N/A if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
2N/A goto out;
2N/A } while (rv == 0);
2N/A
2N/Aout:
2N/A if (tran != NULL) {
2N/A scf_transaction_destroy_children(tran);
2N/A scf_transaction_destroy(tran);
2N/A }
2N/A
2N/A drop_composed(&sstate);
2N/A shut_down_scf(&sstate);
2N/A if (rv == 1 && (fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) != NULL) {
2N/A (void) smf_refresh_instance(fmri);
2N/A free(fmri);
2N/A }
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Adladm_bridge_persist_conf(dladm_handle_t handle, const char *link,
2N/A datalink_id_t linkid)
2N/A{
2N/A dladm_conf_t conf;
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE,
2N/A DL_ETHER, &conf);
2N/A if (status == DLADM_STATUS_OK) {
2N/A /*
2N/A * Create the datalink entry for the bridge. Note that all of
2N/A * the real configuration information is in SMF.
2N/A */
2N/A status = dladm_write_conf(handle, conf, linkid);
2N/A dladm_destroy_conf(handle, conf);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/* Convert bridge protection option string to dladm_bridge_prot_t */
2N/Adladm_status_t
2N/Adladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp)
2N/A{
2N/A if (strcmp(str, "stp") == 0)
2N/A *brprotp = DLADM_BRIDGE_PROT_STP;
2N/A else if (strcmp(str, "trill") == 0)
2N/A *brprotp = DLADM_BRIDGE_PROT_TRILL;
2N/A else
2N/A return (DLADM_STATUS_BADARG);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/A/* Convert bridge protection option from dladm_bridge_prot_t to string */
2N/Aconst char *
2N/Adladm_bridge_prot2str(dladm_bridge_prot_t brprot)
2N/A{
2N/A switch (brprot) {
2N/A case DLADM_BRIDGE_PROT_STP:
2N/A return ("stp");
2N/A case DLADM_BRIDGE_PROT_TRILL:
2N/A return ("trill");
2N/A default:
2N/A return ("unknown");
2N/A }
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Aenable_instance(const char *service_name, const char *instance)
2N/A{
2N/A dladm_status_t status;
2N/A char *fmri = alloc_fmri(service_name, instance);
2N/A
2N/A if (fmri == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A status = smf_enable_instance(fmri, 0) == 0 ?
2N/A DLADM_STATUS_OK : DLADM_STATUS_FAILED;
2N/A free(fmri);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Shut down a possibly-running service instance. If this is a permanent
2N/A * change, then delete it from the system.
2N/A */
2N/Astatic dladm_status_t
2N/Ashut_down_instance(const char *service_name, const char *instance,
2N/A uint32_t flags)
2N/A{
2N/A dladm_status_t status;
2N/A char *fmri = alloc_fmri(service_name, instance);
2N/A char *state;
2N/A scf_state_t sstate;
2N/A
2N/A if (fmri == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A if (smf_disable_instance(fmri,
2N/A flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) {
2N/A useconds_t usecs, umax;
2N/A
2N/A /* If we can disable, then wait for it to happen. */
2N/A umax = DEFAULT_TIMEOUT;
2N/A for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) {
2N/A state = smf_get_state(fmri);
2N/A if (state != NULL &&
2N/A strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
2N/A break;
2N/A free(state);
2N/A usecs *= 2;
2N/A if (usecs > umax)
2N/A usecs = umax;
2N/A (void) usleep(usecs);
2N/A }
2N/A if (umax == 0) {
2N/A state = smf_get_state(fmri);
2N/A if (state != NULL &&
2N/A strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
2N/A umax = 1;
2N/A }
2N/A free(state);
2N/A status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED;
2N/A } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
2N/A free(fmri);
2N/A return (DLADM_STATUS_OK);
2N/A } else {
2N/A status = DLADM_STATUS_FAILED;
2N/A }
2N/A
2N/A free(fmri);
2N/A if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) &&
2N/A bind_instance(service_name, instance, &sstate) == 0) {
2N/A (void) scf_instance_delete(sstate.ss_inst);
2N/A shut_down_scf(&sstate);
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Adisable_trill(const char *instance, uint32_t flags)
2N/A{
2N/A return (shut_down_instance(TRILL_SVC_NAME, instance, flags));
2N/A}
2N/A
2N/A/*
2N/A * To enable TRILL, we must create a new instance of the TRILL service, then
2N/A * add proper dependencies to it, and finally mark it as enabled. The
2N/A * dependencies will keep it from going on-line until the bridge is running.
2N/A */
2N/Astatic dladm_status_t
2N/Aenable_trill(const char *instance)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A char *fmri = NULL;
2N/A scf_state_t sstate;
2N/A scf_transaction_t *tran = NULL;
2N/A boolean_t new_instance = B_FALSE;
2N/A boolean_t new_pg = B_FALSE;
2N/A int rv;
2N/A
2N/A /*
2N/A * This check is here in case the user has installed and then removed
2N/A * the package. SMF should remove the manifest, but currently does
2N/A * not.
2N/A */
2N/A if (access("/usr/sbin/trilld", F_OK) != 0)
2N/A return (DLADM_STATUS_OPTMISSING);
2N/A
2N/A if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) !=
2N/A DLADM_STATUS_OK)
2N/A goto out;
2N/A
2N/A status = DLADM_STATUS_FAILED;
2N/A if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) !=
2N/A 0) {
2N/A if (scf_service_add_instance(sstate.ss_svc, instance,
2N/A sstate.ss_inst) != 0)
2N/A goto out;
2N/A new_instance = B_TRUE;
2N/A }
2N/A
2N/A if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A
2N/A if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A
2N/A if (scf_instance_get_pg(sstate.ss_inst, "bridging",
2N/A sstate.ss_pg) == 0) {
2N/A status = DLADM_STATUS_OK;
2N/A goto out;
2N/A }
2N/A
2N/A if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL)
2N/A goto out;
2N/A
2N/A if (scf_instance_add_pg(sstate.ss_inst, "bridging",
2N/A SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0)
2N/A goto out;
2N/A
2N/A new_pg = B_TRUE;
2N/A do {
2N/A if (scf_transaction_start(tran, sstate.ss_pg) != 0)
2N/A goto out;
2N/A
2N/A if (!set_string_property(sstate.ss_handle, tran,
2N/A SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL))
2N/A goto out;
2N/A if (!set_string_property(sstate.ss_handle, tran,
2N/A SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART))
2N/A goto out;
2N/A if (!set_string_property(sstate.ss_handle, tran,
2N/A SCF_PROPERTY_TYPE, "service"))
2N/A goto out;
2N/A if (!set_fmri_property(sstate.ss_handle, tran,
2N/A SCF_PROPERTY_ENTITIES, fmri))
2N/A goto out;
2N/A
2N/A rv = scf_transaction_commit(tran);
2N/A scf_transaction_reset(tran);
2N/A if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
2N/A goto out;
2N/A } while (rv == 0);
2N/A if (rv != 1)
2N/A goto out;
2N/A
2N/A status = DLADM_STATUS_OK;
2N/A
2N/Aout:
2N/A free(fmri);
2N/A if (tran != NULL) {
2N/A scf_transaction_destroy_children(tran);
2N/A scf_transaction_destroy(tran);
2N/A }
2N/A
2N/A if (status != DLADM_STATUS_OK && new_pg)
2N/A (void) scf_pg_delete(sstate.ss_pg);
2N/A
2N/A drop_composed(&sstate);
2N/A
2N/A /*
2N/A * If we created an instance and then failed, then remove the instance
2N/A * from the system.
2N/A */
2N/A if (status != DLADM_STATUS_OK && new_instance)
2N/A (void) scf_instance_delete(sstate.ss_inst);
2N/A
2N/A shut_down_scf(&sstate);
2N/A
2N/A if (status == DLADM_STATUS_OK)
2N/A status = enable_instance(TRILL_SVC_NAME, instance);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Create a new bridge or modify an existing one. Update the SMF configuration
2N/A * and add links.
2N/A *
2N/A * Input timer values are in IEEE scaled (* 256) format.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_configure(dladm_handle_t handle, const char *name,
2N/A const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags)
2N/A{
2N/A dladm_status_t status;
2N/A scf_state_t sstate;
2N/A scf_transaction_t *tran = NULL;
2N/A boolean_t new_instance = B_FALSE;
2N/A boolean_t new_pg = B_FALSE;
2N/A datalink_id_t linkid = DATALINK_INVALID_LINKID;
2N/A char linkname[MAXLINKNAMELEN];
2N/A int rv;
2N/A
2N/A if (!dladm_valid_bridgename(name))
2N/A return (DLADM_STATUS_FAILED);
2N/A
2N/A if (flags & DLADM_OPT_CREATE) {
2N/A /*
2N/A * This check is here in case the user has installed and then
2N/A * removed the package. SMF should remove the manifest, but
2N/A * currently does not.
2N/A */
2N/A if (access("/usr/lib/bridged", F_OK) != 0)
2N/A return (DLADM_STATUS_OPTMISSING);
2N/A
2N/A (void) snprintf(linkname, sizeof (linkname), "%s0", name);
2N/A status = dladm_create_datalink_id(handle, linkname,
2N/A DATALINK_CLASS_BRIDGE, DL_ETHER,
2N/A flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A if ((flags & DLADM_OPT_PERSIST) &&
2N/A (status = dladm_bridge_persist_conf(handle, linkname,
2N/A linkid) != DLADM_STATUS_OK))
2N/A goto dladm_fail;
2N/A }
2N/A
2N/A if (brprot == DLADM_BRIDGE_PROT_TRILL)
2N/A status = enable_trill(name);
2N/A else
2N/A status = disable_trill(name, flags);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto dladm_fail;
2N/A
2N/A if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) !=
2N/A DLADM_STATUS_OK)
2N/A goto out;
2N/A
2N/A /* set up for a series of scf calls */
2N/A status = DLADM_STATUS_FAILED;
2N/A
2N/A if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) ==
2N/A 0) {
2N/A if (flags & DLADM_OPT_CREATE) {
2N/A status = DLADM_STATUS_EXIST;
2N/A goto out;
2N/A }
2N/A } else {
2N/A if (!(flags & DLADM_OPT_CREATE)) {
2N/A status = DLADM_STATUS_NOTFOUND;
2N/A goto out;
2N/A }
2N/A if (scf_service_add_instance(sstate.ss_svc, name,
2N/A sstate.ss_inst) != 0)
2N/A goto out;
2N/A new_instance = B_TRUE;
2N/A }
2N/A
2N/A if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A
2N/A if (cfg->field_mask & BR_CFG_ALL) {
2N/A if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A if (scf_instance_add_pg(sstate.ss_inst, BRIDGE_PROP_PG_CONFIG,
2N/A SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
2N/A new_pg = B_TRUE;
2N/A } else if (scf_instance_get_pg(sstate.ss_inst,
2N/A BRIDGE_PROP_PG_CONFIG, sstate.ss_pg) != 0) {
2N/A goto out;
2N/A }
2N/A do {
2N/A if (scf_transaction_start(tran, sstate.ss_pg) != 0)
2N/A goto out;
2N/A
2N/A if ((cfg->field_mask & BR_CFG_PRIO) &&
2N/A !set_count_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_PRIORITY, cfg->bridge_priority))
2N/A goto out;
2N/A if ((cfg->field_mask & BR_CFG_AGE) &&
2N/A !set_count_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_MAX_AGE,
2N/A cfg->max_age * IEEE_TIMER_SCALE))
2N/A goto out;
2N/A if ((cfg->field_mask & BR_CFG_HELLO) &&
2N/A !set_count_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_HELLO_TIME,
2N/A cfg->hello_time * IEEE_TIMER_SCALE))
2N/A goto out;
2N/A if ((cfg->field_mask & BR_CFG_DELAY) &&
2N/A !set_count_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_FWD_DELAY,
2N/A cfg->forward_delay * IEEE_TIMER_SCALE))
2N/A goto out;
2N/A if ((cfg->field_mask & BR_CFG_FORCE_VER) &&
2N/A !set_count_property(sstate.ss_handle, tran,
2N/A BRIDGE_PROP_FORCE_PROTOCOL, cfg->force_version))
2N/A goto out;
2N/A
2N/A rv = scf_transaction_commit(tran);
2N/A scf_transaction_reset(tran);
2N/A if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
2N/A goto out;
2N/A } while (rv == 0);
2N/A if (rv != 1)
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * If we're modifying an existing and running bridge, then tell the
2N/A * daemon to update the requested values.
2N/A */
2N/A if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE))
2N/A status = bridge_refresh(name);
2N/A else
2N/A status = DLADM_STATUS_OK;
2N/A
2N/Aout:
2N/A if (tran != NULL) {
2N/A scf_transaction_destroy_children(tran);
2N/A scf_transaction_destroy(tran);
2N/A }
2N/A
2N/A if (status != DLADM_STATUS_OK && new_pg)
2N/A (void) scf_pg_delete(sstate.ss_pg);
2N/A
2N/A drop_composed(&sstate);
2N/A
2N/A /*
2N/A * If we created an instance and then failed, then remove the instance
2N/A * from the system.
2N/A */
2N/A if (status != DLADM_STATUS_OK && new_instance)
2N/A (void) scf_instance_delete(sstate.ss_inst);
2N/A
2N/A shut_down_scf(&sstate);
2N/A
2N/A /*
2N/A * Remove the bridge linkid if we've allocated one in this function but
2N/A * we've failed to set up the SMF properties.
2N/A */
2N/Adladm_fail:
2N/A if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) {
2N/A (void) dladm_remove_conf(handle, linkid);
2N/A (void) dladm_destroy_datalink_id(handle, linkid, flags);
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Enable a newly-created bridge in SMF by creating "general/enabled" and
2N/A * deleting any "general_ovr/enabled" (used for temporary services).
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_enable(const char *name)
2N/A{
2N/A return (enable_instance(BRIDGE_SVC_NAME, name));
2N/A}
2N/A
2N/A/*
2N/A * Set a link as a member of a bridge, or remove bridge membership. If the
2N/A * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running.
2N/A * In all other cases, we must tell the daemon to add or delete the link in
2N/A * order to stay in sync.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid,
2N/A const char *bridge)
2N/A{
2N/A dladm_status_t status;
2N/A dladm_conf_t conf;
2N/A char oldbridge[MAXLINKNAMELEN];
2N/A boolean_t has_oldbridge;
2N/A boolean_t changed = B_FALSE;
2N/A
2N/A if (*bridge != '\0' && !dladm_valid_bridgename(bridge))
2N/A return (DLADM_STATUS_FAILED);
2N/A
2N/A status = dladm_open_conf(handle, linkid, &conf);
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A has_oldbridge = B_FALSE;
2N/A status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge,
2N/A sizeof (oldbridge));
2N/A if (status == DLADM_STATUS_OK) {
2N/A /*
2N/A * Don't allow a link to be reassigned directly from one bridge
2N/A * to another. It must be removed first.
2N/A */
2N/A if (*oldbridge != '\0' && *bridge != '\0') {
2N/A status = DLADM_STATUS_EXIST;
2N/A goto out;
2N/A }
2N/A has_oldbridge = B_TRUE;
2N/A } else if (status != DLADM_STATUS_NOTFOUND) {
2N/A goto out;
2N/A }
2N/A
2N/A if (*bridge != '\0') {
2N/A status = dladm_set_conf_field(handle, conf, FBRIDGE,
2N/A DLADM_TYPE_STR, bridge);
2N/A changed = B_TRUE;
2N/A } else if (has_oldbridge) {
2N/A status = dladm_unset_conf_field(handle, conf, FBRIDGE);
2N/A changed = B_TRUE;
2N/A } else {
2N/A status = DLADM_STATUS_OK;
2N/A goto out;
2N/A }
2N/A if (status == DLADM_STATUS_OK)
2N/A status = dladm_write_conf(handle, conf, linkid);
2N/A
2N/Aout:
2N/A dladm_destroy_conf(handle, conf);
2N/A if (changed && status == DLADM_STATUS_OK) {
2N/A if (bridge[0] == '\0')
2N/A bridge = oldbridge;
2N/A status = bridge_refresh(bridge);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Get the name of the bridge of which the given linkid is a member.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge,
2N/A size_t bridgelen)
2N/A{
2N/A dladm_status_t status;
2N/A dladm_conf_t conf;
2N/A
2N/A if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
2N/A DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A *bridge = '\0';
2N/A status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen);
2N/A if (status == DLADM_STATUS_OK && *bridge == '\0')
2N/A status = DLADM_STATUS_NOTFOUND;
2N/A
2N/A dladm_destroy_conf(handle, conf);
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A char bridge[MAXLINKNAMELEN];
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
2N/A if (status == DLADM_STATUS_NOTFOUND)
2N/A return (DLADM_STATUS_OK);
2N/A if (status == DLADM_STATUS_OK)
2N/A status = bridge_refresh(bridge);
2N/A return (status);
2N/A}
2N/A
2N/Atypedef struct bridge_held_arg_s {
2N/A const char *bha_bridge;
2N/A boolean_t bha_isheld;
2N/A} bridge_held_arg_t;
2N/A
2N/Astatic int
2N/Ai_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A dladm_conf_t conf;
2N/A char bridge[MAXLINKNAMELEN];
2N/A bridge_held_arg_t *bha = arg;
2N/A
2N/A if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
2N/A DLADM_STATUS_OK)
2N/A return (DLADM_WALK_CONTINUE);
2N/A status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge,
2N/A sizeof (bridge));
2N/A if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) {
2N/A bha->bha_isheld = B_TRUE;
2N/A dladm_destroy_conf(handle, conf);
2N/A return (DLADM_WALK_TERMINATE);
2N/A } else {
2N/A dladm_destroy_conf(handle, conf);
2N/A return (DLADM_WALK_CONTINUE);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Delete a previously created bridge.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags)
2N/A{
2N/A datalink_id_t linkid;
2N/A datalink_class_t class;
2N/A dladm_status_t status;
2N/A char linkname[MAXLINKNAMELEN];
2N/A
2N/A if (!dladm_valid_bridgename(bridge))
2N/A return (DLADM_STATUS_LINKINVAL);
2N/A
2N/A /* Get the datalink ID for this bridge */
2N/A (void) snprintf(linkname, sizeof (linkname), "%s0", bridge);
2N/A if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) !=
2N/A DLADM_STATUS_OK)
2N/A linkid = DATALINK_INVALID_LINKID;
2N/A else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
2N/A NULL, 0) != DLADM_STATUS_OK)
2N/A linkid = DATALINK_INVALID_LINKID;
2N/A else if (class != DATALINK_CLASS_BRIDGE)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (flags & DLADM_OPT_PERSIST) {
2N/A bridge_held_arg_t arg;
2N/A
2N/A arg.bha_bridge = bridge;
2N/A arg.bha_isheld = B_FALSE;
2N/A
2N/A /*
2N/A * See whether there are any persistent links using this
2N/A * bridge. If so, we fail the operation.
2N/A */
2N/A (void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle,
2N/A &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR |
2N/A DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET,
2N/A DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2N/A if (arg.bha_isheld)
2N/A return (DLADM_STATUS_LINKBUSY);
2N/A }
2N/A
2N/A if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK)
2N/A goto out;
2N/A
2N/A /* Disable or remove the SMF instance */
2N/A status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto out;
2N/A
2N/A if (flags & DLADM_OPT_ACTIVE) {
2N/A /*
2N/A * Delete ACTIVE linkprop now that daemon is gone.
2N/A */
2N/A (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
2N/A DLADM_OPT_ACTIVE);
2N/A (void) dladm_destroy_datalink_id(handle, linkid,
2N/A DLADM_OPT_ACTIVE);
2N/A }
2N/A
2N/A if (flags & DLADM_OPT_PERSIST) {
2N/A (void) dladm_remove_conf(handle, linkid);
2N/A (void) dladm_destroy_datalink_id(handle, linkid,
2N/A DLADM_OPT_PERSIST);
2N/A }
2N/A
2N/Aout:
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/* Check if given name is valid for bridges */
2N/Aboolean_t
2N/Adladm_valid_bridgename(const char *bridge)
2N/A{
2N/A size_t len = strnlen(bridge, MAXLINKNAMELEN);
2N/A const char *cp;
2N/A
2N/A if (len == MAXLINKNAMELEN)
2N/A return (B_FALSE);
2N/A
2N/A /*
2N/A * The bridge name cannot start or end with a digit.
2N/A */
2N/A if (isdigit(bridge[0]) || isdigit(bridge[len - 1]))
2N/A return (B_FALSE);
2N/A
2N/A /*
2N/A * The legal characters within a bridge name are:
2N/A * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_').
2N/A */
2N/A for (cp = bridge; *cp != '\0'; cp++) {
2N/A if (!isalnum(*cp) && *cp != '_')
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A return (B_TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Convert a bridge-related observability node name back into the name of the
2N/A * bridge. Returns B_FALSE without making changes if the input name is not in
2N/A * a legal format.
2N/A */
2N/Aboolean_t
2N/Adladm_observe_to_bridge(char *link)
2N/A{
2N/A int llen;
2N/A
2N/A llen = strnlen(link, MAXLINKNAMELEN);
2N/A if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2]))
2N/A return (B_FALSE);
2N/A link[llen - 1] = '\0';
2N/A return (B_TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Get bridge property values from the running daemon and return them in a
2N/A * common structure.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg,
2N/A dladm_bridge_prot_t *brprotp)
2N/A{
2N/A dladm_status_t status;
2N/A bridge_door_cfg_t bdcf;
2N/A bridge_door_cfg_t *bdcfp = &bdcf;
2N/A size_t buflen = sizeof (bdcf);
2N/A
2N/A status = bridge_door_call(instname, bdcBridgeGetConfig,
2N/A DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE);
2N/A if (status == DLADM_STATUS_OK) {
2N/A *smcfg = bdcfp->bdcf_cfg;
2N/A *brprotp = bdcfp->bdcf_prot;
2N/A } else {
2N/A smcfg->field_mask = 0;
2N/A *brprotp = DLADM_BRIDGE_PROT_STP;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Get bridge state from the running daemon and return in structure borrowed
2N/A * from librstp.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_state(const char *instname, UID_STP_STATE_T *statep)
2N/A{
2N/A size_t buflen = sizeof (*statep);
2N/A
2N/A return (bridge_door_call(instname, bdcBridgeGetState,
2N/A DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE));
2N/A}
2N/A
2N/A/* Returns list of ports (datalink_id_t values) assigned to a bridge instance */
2N/Adatalink_id_t *
2N/Adladm_bridge_get_portlist(const char *instname, uint_t *nports)
2N/A{
2N/A size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t);
2N/A int *rbuf;
2N/A
2N/A if ((rbuf = malloc(buflen)) == NULL)
2N/A return (NULL);
2N/A if (bridge_door_call(instname, bdcBridgeGetPorts,
2N/A DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) !=
2N/A DLADM_STATUS_OK) {
2N/A free(rbuf);
2N/A return (NULL);
2N/A } else {
2N/A /*
2N/A * Returns an array of datalink_id_t values for all the ports
2N/A * part of the bridge instance. First entry in the array is the
2N/A * number of ports.
2N/A */
2N/A *nports = *rbuf;
2N/A return ((datalink_id_t *)(rbuf + 1));
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Adladm_bridge_free_portlist(datalink_id_t *dlp)
2N/A{
2N/A free((int *)dlp - 1);
2N/A}
2N/A
2N/A/* Retrieve Bridge port configuration values */
2N/Adladm_status_t
2N/Adladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid,
2N/A int field, int *valuep)
2N/A{
2N/A UID_STP_PORT_CFG_T portcfg;
2N/A dladm_status_t status;
2N/A
2N/A status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg,
2N/A 0, sizeof (portcfg));
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A switch (field) {
2N/A case PT_CFG_COST:
2N/A *valuep = portcfg.admin_port_path_cost;
2N/A break;
2N/A case PT_CFG_PRIO:
2N/A *valuep = portcfg.port_priority;
2N/A break;
2N/A case PT_CFG_P2P:
2N/A *valuep = portcfg.admin_point2point;
2N/A break;
2N/A case PT_CFG_EDGE:
2N/A *valuep = portcfg.admin_edge;
2N/A break;
2N/A case PT_CFG_NON_STP:
2N/A *valuep = !portcfg.admin_non_stp;
2N/A break;
2N/A case PT_CFG_MCHECK:
2N/A *valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0;
2N/A break;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/* Retreive Bridge port status (disabled, bad SDU etc.) */
2N/Adladm_status_t
2N/Adladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid,
2N/A UID_STP_PORT_STATE_T *spsp)
2N/A{
2N/A return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0,
2N/A sizeof (*spsp)));
2N/A}
2N/A
2N/A/* Retrieve Bridge forwarding status of the given link */
2N/Adladm_status_t
2N/Adladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint_t *valuep)
2N/A{
2N/A int twoints[2];
2N/A dladm_status_t status;
2N/A
2N/A status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints,
2N/A 0, sizeof (twoints));
2N/A if (status == DLADM_STATUS_OK)
2N/A *valuep = twoints[0];
2N/A return (status);
2N/A}
2N/A
2N/A/* Retrieve Bridge forwarding table entries */
2N/Abridge_listfwd_t *
2N/Adladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge,
2N/A uint_t *nfwd)
2N/A{
2N/A bridge_listfwd_t *blf = NULL, *newblf, blfread;
2N/A uint_t nblf = 0, maxblf = 0;
2N/A static uint8_t zero_addr[ETHERADDRL];
2N/A int rc;
2N/A
2N/A (void) memset(&blfread, 0, sizeof (blfread));
2N/A (void) snprintf(blfread.blf_name, sizeof (blfread.blf_name),
2N/A "%s0", bridge);
2N/A for (;;) {
2N/A if (nblf >= maxblf) {
2N/A maxblf = maxblf == 0 ? 64 : (maxblf << 1);
2N/A newblf = realloc(blf, maxblf * sizeof (*blf));
2N/A if (newblf == NULL) {
2N/A free(blf);
2N/A blf = NULL;
2N/A break;
2N/A }
2N/A blf = newblf;
2N/A }
2N/A rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread);
2N/A if (rc != 0) {
2N/A free(blf);
2N/A blf = NULL;
2N/A break;
2N/A }
2N/A if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0)
2N/A break;
2N/A blf[nblf++] = blfread;
2N/A }
2N/A if (blf != NULL)
2N/A *nfwd = nblf;
2N/A return (blf);
2N/A}
2N/A
2N/Avoid
2N/Adladm_bridge_free_fwdtable(bridge_listfwd_t *blf)
2N/A{
2N/A free(blf);
2N/A}
2N/A
2N/A/* Retrieve list of TRILL nicknames from the TRILL module */
2N/Atrill_listnick_t *
2N/Adladm_bridge_get_trillnick(const char *bridge, uint_t *nnick)
2N/A{
2N/A int fd;
2N/A char brcopy[MAXLINKNAMELEN];
2N/A trill_listnick_t *tln = NULL, *newtln, tlnread;
2N/A uint_t ntln = 0, maxtln = 0;
2N/A
2N/A if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1)
2N/A return (NULL);
2N/A (void) strlcpy(brcopy, bridge, sizeof (brcopy));
2N/A if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) {
2N/A (void) close(fd);
2N/A return (NULL);
2N/A }
2N/A (void) memset(&tlnread, 0, sizeof (tlnread));
2N/A for (;;) {
2N/A if (ntln >= maxtln) {
2N/A maxtln = maxtln == 0 ? 64 : (maxtln << 1);
2N/A newtln = realloc(tln, maxtln * sizeof (*tln));
2N/A if (newtln == NULL) {
2N/A free(tln);
2N/A tln = NULL;
2N/A break;
2N/A }
2N/A tln = newtln;
2N/A }
2N/A if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) {
2N/A free(tln);
2N/A tln = NULL;
2N/A break;
2N/A }
2N/A if (tlnread.tln_nick == 0)
2N/A break;
2N/A tln[ntln++] = tlnread;
2N/A }
2N/A (void) close(fd);
2N/A if (tln != NULL)
2N/A *nnick = ntln;
2N/A return (tln);
2N/A}
2N/A
2N/Avoid
2N/Adladm_bridge_free_trillnick(trill_listnick_t *tln)
2N/A{
2N/A free(tln);
2N/A}
2N/A
2N/A/* Retrieve any stored TRILL nickname from TRILL SMF service */
2N/Auint16_t
2N/Adladm_bridge_get_nick(const char *bridge)
2N/A{
2N/A scf_state_t sstate;
2N/A uint64_t value;
2N/A uint16_t nickname = RBRIDGE_NICKNAME_NONE;
2N/A
2N/A if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0)
2N/A return (nickname);
2N/A
2N/A if (get_composed_properties(TRILL_PROP_PG_CONFIG, B_TRUE, &sstate)
2N/A == 0 &&
2N/A get_count(TRILL_PROP_NICK, &sstate, &value) == 0)
2N/A nickname = value;
2N/A shut_down_scf(&sstate);
2N/A return (nickname);
2N/A}
2N/A
2N/A/* Stores TRILL nickname in SMF configuraiton for the TRILL service */
2N/Avoid
2N/Adladm_bridge_set_nick(const char *bridge, uint16_t nick)
2N/A{
2N/A scf_state_t sstate;
2N/A scf_transaction_t *tran = NULL;
2N/A boolean_t new_pg = B_FALSE;
2N/A int rv = 0;
2N/A char *fmri;
2N/A
2N/A if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK)
2N/A return;
2N/A
2N/A if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) !=
2N/A 0)
2N/A goto out;
2N/A if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
2N/A goto out;
2N/A if (scf_instance_add_pg(sstate.ss_inst, TRILL_PROP_PG_CONFIG,
2N/A SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
2N/A new_pg = B_TRUE;
2N/A } else if (scf_instance_get_pg(sstate.ss_inst, TRILL_PROP_PG_CONFIG,
2N/A sstate.ss_pg) != 0) {
2N/A goto out;
2N/A }
2N/A do {
2N/A if (scf_transaction_start(tran, sstate.ss_pg) != 0)
2N/A goto out;
2N/A if (!set_count_property(sstate.ss_handle, tran, TRILL_PROP_NICK,
2N/A nick))
2N/A goto out;
2N/A rv = scf_transaction_commit(tran);
2N/A scf_transaction_reset(tran);
2N/A if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
2N/A goto out;
2N/A } while (rv == 0);
2N/A
2N/Aout:
2N/A if (tran != NULL) {
2N/A scf_transaction_destroy_children(tran);
2N/A scf_transaction_destroy(tran);
2N/A }
2N/A
2N/A if (rv != 1 && new_pg)
2N/A (void) scf_pg_delete(sstate.ss_pg);
2N/A
2N/A drop_composed(&sstate);
2N/A shut_down_scf(&sstate);
2N/A if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) {
2N/A (void) smf_refresh_instance(fmri);
2N/A free(fmri);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Get the bridge name from the given linkid. Replace the final 0 in the link
2N/A * name with \0.
2N/A */
2N/Astatic dladm_status_t
2N/Ai_dladm_bridge_name_from_linkid(dladm_handle_t handle, datalink_id_t linkid,
2N/A char *bridge, size_t len)
2N/A{
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
2N/A bridge, len);
2N/A if (status == DLADM_STATUS_OK)
2N/A bridge[strlen(bridge) - 1] = '\0';
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Bring up a persistent bridge. The bridge's SMF instance is created and
2N/A * enabled and its properties from datalink-<profile>.conf are applied to that
2N/A * SMF instance. This allows the bridge to be profile-specific.
2N/A */
2N/Astatic int
2N/Ai_dladm_bridge_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2N/A{
2N/A dladm_status_t *statusp = arg;
2N/A dladm_status_t status;
2N/A char bridge[MAXLINKNAMELEN];
2N/A dladm_conf_t conf;
2N/A UID_STP_CFG_T cfg;
2N/A dladm_bridge_prot_t bprot;
2N/A boolean_t debug;
2N/A uint32_t tablemax;
2N/A uint16_t trillnick;
2N/A uint64_t u64;
2N/A scf_state_t sstate;
2N/A
2N/A if ((status = i_dladm_bridge_name_from_linkid(handle, linkid, bridge,
2N/A sizeof (bridge))) != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A /* Retrieve the properties from datalink.conf */
2N/A if ((status = dladm_open_conf(handle, linkid, &conf))
2N/A != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A /*
2N/A * Read back all the properties written out in i_dladm_bridge_down()
2N/A * and remove them from datalink.conf.
2N/A */
2N/A if ((status = dladm_get_conf_field(handle, conf,
2N/A BRIDGE_PROP_PROTECT, &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_PROTECT)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A bprot = (dladm_bridge_prot_t)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf,
2N/A BRIDGE_PROP_FIELD_MASK, &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_FIELD_MASK)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A cfg.field_mask = (unsigned long)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf, BRIDGE_PROP_PRIORITY,
2N/A &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_PRIORITY)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A cfg.bridge_priority = (int)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf, BRIDGE_PROP_MAX_AGE,
2N/A &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf, BRIDGE_PROP_MAX_AGE))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A cfg.max_age = (int)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf, BRIDGE_PROP_HELLO_TIME,
2N/A &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_HELLO_TIME)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A cfg.hello_time = (int)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf, BRIDGE_PROP_FWD_DELAY,
2N/A &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_FWD_DELAY)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A cfg.forward_delay = (int)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf,
2N/A BRIDGE_PROP_FORCE_PROTOCOL, &u64, sizeof (u64)))
2N/A != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_FORCE_PROTOCOL)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A cfg.force_version = (int)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf, BRIDGE_PROP_DEBUG,
2N/A &debug, sizeof (debug))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf, BRIDGE_PROP_DEBUG))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A if ((status = dladm_get_conf_field(handle, conf, BRIDGE_PROP_TABLE_MAX,
2N/A &u64, sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf,
2N/A BRIDGE_PROP_TABLE_MAX)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A tablemax = (uint32_t)u64;
2N/A if ((status = dladm_get_conf_field(handle, conf, TRILL_PROP_NICK, &u64,
2N/A sizeof (u64))) != DLADM_STATUS_OK ||
2N/A (status = dladm_unset_conf_field(handle, conf, TRILL_PROP_NICK))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A trillnick = (uint16_t)u64;
2N/A
2N/A /*
2N/A * Add the SMF instance for this bridge. dladm_configure_bridge()
2N/A * will add the instance only if DLADM_OPT_CREATE flag is passed, but
2N/A * passing that flag also tries to create a new linkid. Since we
2N/A * don't want that, we'll create the instance first and then configure
2N/A * the bridge.
2N/A */
2N/A if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A if (scf_service_add_instance(sstate.ss_svc, bridge, sstate.ss_inst)
2N/A != 0) {
2N/A drop_composed(&sstate);
2N/A shut_down_scf(&sstate);
2N/A status = DLADM_STATUS_FAILED;
2N/A goto done;
2N/A }
2N/A drop_composed(&sstate);
2N/A shut_down_scf(&sstate);
2N/A
2N/A /* Configure bridge, set TRILL nickname and private bridge parameters */
2N/A status = dladm_bridge_configure(handle, bridge, &cfg, bprot,
2N/A DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A dladm_bridge_set_nick(bridge, trillnick);
2N/A dladm_bridge_set_privprop(bridge, debug, tablemax);
2N/A
2N/A /* Finally, enable the bridge */
2N/A status = dladm_bridge_enable(bridge);
2N/A
2N/A /*
2N/A * Write the updated datalink.conf file, the properties written to
2N/A * datalink.conf in i_dladm_bridge_up() have been removed.
2N/A */
2N/A if ((status = dladm_write_conf(handle, conf, linkid))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/Adone:
2N/A dladm_destroy_conf(handle, conf);
2N/A if (statusp != NULL)
2N/A *statusp = status;
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Bring up a previously created persistent bridge or all persistent bridges.
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_up(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A
2N/A if (linkid == DATALINK_ALL_LINKID) {
2N/A (void) dladm_walk_datalink_id(i_dladm_bridge_up, handle, NULL,
2N/A DATALINK_CLASS_BRIDGE, DATALINK_ANY_MEDIATYPE,
2N/A DLADM_OPT_PERSIST);
2N/A } else {
2N/A (void) i_dladm_bridge_up(handle, linkid, &status);
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Bring down an active bridge. The bridge's configuration is stored in
2N/A * datalink-<profile>.conf from the SMF instance, which is then removed. This
2N/A * allows bridges to be profile-specific.
2N/A */
2N/Astatic int
2N/Ai_dladm_bridge_down(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2N/A{
2N/A dladm_status_t *statusp = arg;
2N/A dladm_status_t status;
2N/A char bridge[MAXLINKNAMELEN];
2N/A dladm_conf_t conf;
2N/A UID_STP_CFG_T cfg;
2N/A dladm_bridge_prot_t bprot;
2N/A uint64_t u64;
2N/A boolean_t debug, conf_opened = B_FALSE;
2N/A uint32_t tablemax;
2N/A uint16_t trillnick;
2N/A
2N/A if ((status = i_dladm_bridge_name_from_linkid(handle, linkid, bridge,
2N/A sizeof (bridge))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A /*
2N/A * Retrieve the bridge properties from the bridge and trill SMF
2N/A * services and write the protection and the values of these properties
2N/A * to datalink.conf.
2N/A */
2N/A if ((status = dladm_bridge_get_properties(bridge, &cfg, &bprot))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A if ((status = dladm_bridge_get_privprop(bridge, &debug, &tablemax))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A trillnick = dladm_bridge_get_nick(bridge);
2N/A
2N/A if ((status = dladm_open_conf(handle, linkid, &conf))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A conf_opened = B_TRUE;
2N/A
2N/A u64 = bprot;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_PROTECT,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = cfg.field_mask;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_FIELD_MASK,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = cfg.bridge_priority;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_PRIORITY,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = cfg.max_age;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_MAX_AGE,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = cfg.hello_time;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_HELLO_TIME,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = cfg.forward_delay;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_FWD_DELAY,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = cfg.force_version;
2N/A if ((status = dladm_set_conf_field(handle, conf,
2N/A BRIDGE_PROP_FORCE_PROTOCOL, DLADM_TYPE_UINT64, &u64))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A /* The following are private bridge parameters */
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_DEBUG,
2N/A DLADM_TYPE_BOOLEAN, &debug)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = tablemax;
2N/A if ((status = dladm_set_conf_field(handle, conf, BRIDGE_PROP_TABLE_MAX,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A u64 = trillnick;
2N/A /* The following is the TRILL nickname */
2N/A if ((status = dladm_set_conf_field(handle, conf, TRILL_PROP_NICK,
2N/A DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if ((status = dladm_write_conf(handle, conf, linkid))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A /*
2N/A * Disable and remove the instances of this bridge from
2N/A * network/routing/trill and network/bridge SMF services.
2N/A */
2N/A (void) disable_trill(bridge, DLADM_OPT_PERSIST);
2N/A (void) shut_down_instance(BRIDGE_SVC_NAME, bridge, DLADM_OPT_PERSIST);
2N/A
2N/Adone:
2N/A (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_ACTIVE);
2N/A if (conf_opened)
2N/A dladm_destroy_conf(handle, conf);
2N/A
2N/A if (statusp != NULL)
2N/A *statusp = status;
2N/A return (DLADM_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Bring down one bridge or all active bridges. Persistent configuration and
2N/A * linkid mapping in dlmgmtd is not removed. Downed bridge(s) can be brought
2N/A * up with dladm_bridge_up().
2N/A */
2N/Adladm_status_t
2N/Adladm_bridge_down(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A
2N/A if (linkid == DATALINK_ALL_LINKID) {
2N/A (void) dladm_walk_datalink_id(i_dladm_bridge_down, handle, NULL,
2N/A DATALINK_CLASS_BRIDGE, DATALINK_ANY_MEDIATYPE,
2N/A DLADM_OPT_ACTIVE);
2N/A } else {
2N/A (void) i_dladm_bridge_down(handle, linkid, &status);
2N/A }
2N/A return (status);
2N/A}