1*4eaa4710SRishi Srivatsavai /* 2*4eaa4710SRishi Srivatsavai * CDDL HEADER START 3*4eaa4710SRishi Srivatsavai * 4*4eaa4710SRishi Srivatsavai * The contents of this file are subject to the terms of the 5*4eaa4710SRishi Srivatsavai * Common Development and Distribution License (the "License"). 6*4eaa4710SRishi Srivatsavai * You may not use this file except in compliance with the License. 7*4eaa4710SRishi Srivatsavai * 8*4eaa4710SRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4eaa4710SRishi Srivatsavai * or http://www.opensolaris.org/os/licensing. 10*4eaa4710SRishi Srivatsavai * See the License for the specific language governing permissions 11*4eaa4710SRishi Srivatsavai * and limitations under the License. 12*4eaa4710SRishi Srivatsavai * 13*4eaa4710SRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each 14*4eaa4710SRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4eaa4710SRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the 16*4eaa4710SRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying 17*4eaa4710SRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner] 18*4eaa4710SRishi Srivatsavai * 19*4eaa4710SRishi Srivatsavai * CDDL HEADER END 20*4eaa4710SRishi Srivatsavai */ 21*4eaa4710SRishi Srivatsavai /* 22*4eaa4710SRishi Srivatsavai * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*4eaa4710SRishi Srivatsavai * Use is subject to license terms. 24*4eaa4710SRishi Srivatsavai */ 25*4eaa4710SRishi Srivatsavai 26*4eaa4710SRishi Srivatsavai #include <stdio.h> 27*4eaa4710SRishi Srivatsavai #include <sys/types.h> 28*4eaa4710SRishi Srivatsavai #include <string.h> 29*4eaa4710SRishi Srivatsavai #include <fcntl.h> 30*4eaa4710SRishi Srivatsavai #include <unistd.h> 31*4eaa4710SRishi Srivatsavai #include <stropts.h> 32*4eaa4710SRishi Srivatsavai #include <ctype.h> 33*4eaa4710SRishi Srivatsavai #include <errno.h> 34*4eaa4710SRishi Srivatsavai #include <stdlib.h> 35*4eaa4710SRishi Srivatsavai #include <door.h> 36*4eaa4710SRishi Srivatsavai #include <sys/mman.h> 37*4eaa4710SRishi Srivatsavai #include <libscf.h> 38*4eaa4710SRishi Srivatsavai #include <libscf_priv.h> 39*4eaa4710SRishi Srivatsavai #include <libdllink.h> 40*4eaa4710SRishi Srivatsavai #include <libdlbridge.h> 41*4eaa4710SRishi Srivatsavai #include <libdladm_impl.h> 42*4eaa4710SRishi Srivatsavai #include <stp_in.h> 43*4eaa4710SRishi Srivatsavai #include <net/bridge.h> 44*4eaa4710SRishi Srivatsavai #include <net/trill.h> 45*4eaa4710SRishi Srivatsavai #include <sys/socket.h> 46*4eaa4710SRishi Srivatsavai 47*4eaa4710SRishi Srivatsavai /* 48*4eaa4710SRishi Srivatsavai * Bridge Administration Library. 49*4eaa4710SRishi Srivatsavai * 50*4eaa4710SRishi Srivatsavai * This library is used by administration tools such as dladm(1M) to configure 51*4eaa4710SRishi Srivatsavai * bridges, and by the bridge daemon to retrieve configuration information. 52*4eaa4710SRishi Srivatsavai */ 53*4eaa4710SRishi Srivatsavai 54*4eaa4710SRishi Srivatsavai #define BRIDGE_SVC_NAME "network/bridge" 55*4eaa4710SRishi Srivatsavai #define TRILL_SVC_NAME "network/routing/trill" 56*4eaa4710SRishi Srivatsavai 57*4eaa4710SRishi Srivatsavai #define DEFAULT_TIMEOUT 60000000 58*4eaa4710SRishi Srivatsavai #define INIT_WAIT_USECS 50000 59*4eaa4710SRishi Srivatsavai #define MAXPORTS 256 60*4eaa4710SRishi Srivatsavai 61*4eaa4710SRishi Srivatsavai typedef struct scf_state { 62*4eaa4710SRishi Srivatsavai scf_handle_t *ss_handle; 63*4eaa4710SRishi Srivatsavai scf_instance_t *ss_inst; 64*4eaa4710SRishi Srivatsavai scf_service_t *ss_svc; 65*4eaa4710SRishi Srivatsavai scf_snapshot_t *ss_snap; 66*4eaa4710SRishi Srivatsavai scf_propertygroup_t *ss_pg; 67*4eaa4710SRishi Srivatsavai scf_property_t *ss_prop; 68*4eaa4710SRishi Srivatsavai } scf_state_t; 69*4eaa4710SRishi Srivatsavai 70*4eaa4710SRishi Srivatsavai static void 71*4eaa4710SRishi Srivatsavai shut_down_scf(scf_state_t *sstate) 72*4eaa4710SRishi Srivatsavai { 73*4eaa4710SRishi Srivatsavai scf_instance_destroy(sstate->ss_inst); 74*4eaa4710SRishi Srivatsavai (void) scf_handle_unbind(sstate->ss_handle); 75*4eaa4710SRishi Srivatsavai scf_handle_destroy(sstate->ss_handle); 76*4eaa4710SRishi Srivatsavai } 77*4eaa4710SRishi Srivatsavai 78*4eaa4710SRishi Srivatsavai static char * 79*4eaa4710SRishi Srivatsavai alloc_fmri(const char *service, const char *instance_name) 80*4eaa4710SRishi Srivatsavai { 81*4eaa4710SRishi Srivatsavai ssize_t max_fmri; 82*4eaa4710SRishi Srivatsavai char *fmri; 83*4eaa4710SRishi Srivatsavai 84*4eaa4710SRishi Srivatsavai /* If the limit is unknown, then use an arbitrary value */ 85*4eaa4710SRishi Srivatsavai if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1) 86*4eaa4710SRishi Srivatsavai max_fmri = 1024; 87*4eaa4710SRishi Srivatsavai if ((fmri = malloc(max_fmri)) != NULL) { 88*4eaa4710SRishi Srivatsavai (void) snprintf(fmri, max_fmri, "svc:/%s:%s", service, 89*4eaa4710SRishi Srivatsavai instance_name); 90*4eaa4710SRishi Srivatsavai } 91*4eaa4710SRishi Srivatsavai return (fmri); 92*4eaa4710SRishi Srivatsavai } 93*4eaa4710SRishi Srivatsavai 94*4eaa4710SRishi Srivatsavai /* 95*4eaa4710SRishi Srivatsavai * Start up SCF and bind the requested instance alone. 96*4eaa4710SRishi Srivatsavai */ 97*4eaa4710SRishi Srivatsavai static int 98*4eaa4710SRishi Srivatsavai bind_instance(const char *service, const char *instance_name, 99*4eaa4710SRishi Srivatsavai scf_state_t *sstate) 100*4eaa4710SRishi Srivatsavai { 101*4eaa4710SRishi Srivatsavai char *fmri = NULL; 102*4eaa4710SRishi Srivatsavai 103*4eaa4710SRishi Srivatsavai (void) memset(sstate, 0, sizeof (*sstate)); 104*4eaa4710SRishi Srivatsavai 105*4eaa4710SRishi Srivatsavai if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 106*4eaa4710SRishi Srivatsavai return (-1); 107*4eaa4710SRishi Srivatsavai 108*4eaa4710SRishi Srivatsavai if (scf_handle_bind(sstate->ss_handle) != 0) 109*4eaa4710SRishi Srivatsavai goto failure; 110*4eaa4710SRishi Srivatsavai sstate->ss_inst = scf_instance_create(sstate->ss_handle); 111*4eaa4710SRishi Srivatsavai if (sstate->ss_inst == NULL) 112*4eaa4710SRishi Srivatsavai goto failure; 113*4eaa4710SRishi Srivatsavai 114*4eaa4710SRishi Srivatsavai fmri = alloc_fmri(service, instance_name); 115*4eaa4710SRishi Srivatsavai 116*4eaa4710SRishi Srivatsavai if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL, 117*4eaa4710SRishi Srivatsavai sstate->ss_inst, NULL, NULL, 118*4eaa4710SRishi Srivatsavai SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) 119*4eaa4710SRishi Srivatsavai goto failure; 120*4eaa4710SRishi Srivatsavai free(fmri); 121*4eaa4710SRishi Srivatsavai return (0); 122*4eaa4710SRishi Srivatsavai 123*4eaa4710SRishi Srivatsavai failure: 124*4eaa4710SRishi Srivatsavai free(fmri); 125*4eaa4710SRishi Srivatsavai shut_down_scf(sstate); 126*4eaa4710SRishi Srivatsavai return (-1); 127*4eaa4710SRishi Srivatsavai } 128*4eaa4710SRishi Srivatsavai 129*4eaa4710SRishi Srivatsavai /* 130*4eaa4710SRishi Srivatsavai * Start up SCF and an exact FMRI. This is used for creating new instances and 131*4eaa4710SRishi Srivatsavai * enable/disable actions. 132*4eaa4710SRishi Srivatsavai */ 133*4eaa4710SRishi Srivatsavai static dladm_status_t 134*4eaa4710SRishi Srivatsavai exact_instance(const char *fmri, scf_state_t *sstate) 135*4eaa4710SRishi Srivatsavai { 136*4eaa4710SRishi Srivatsavai dladm_status_t status; 137*4eaa4710SRishi Srivatsavai 138*4eaa4710SRishi Srivatsavai (void) memset(sstate, 0, sizeof (*sstate)); 139*4eaa4710SRishi Srivatsavai 140*4eaa4710SRishi Srivatsavai if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 141*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 142*4eaa4710SRishi Srivatsavai 143*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 144*4eaa4710SRishi Srivatsavai if (scf_handle_bind(sstate->ss_handle) != 0) 145*4eaa4710SRishi Srivatsavai goto failure; 146*4eaa4710SRishi Srivatsavai sstate->ss_svc = scf_service_create(sstate->ss_handle); 147*4eaa4710SRishi Srivatsavai if (sstate->ss_svc == NULL) 148*4eaa4710SRishi Srivatsavai goto failure; 149*4eaa4710SRishi Srivatsavai if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, 150*4eaa4710SRishi Srivatsavai sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 151*4eaa4710SRishi Srivatsavai if (scf_error() == SCF_ERROR_NOT_FOUND) 152*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_OPTMISSING; 153*4eaa4710SRishi Srivatsavai goto failure; 154*4eaa4710SRishi Srivatsavai } 155*4eaa4710SRishi Srivatsavai sstate->ss_inst = scf_instance_create(sstate->ss_handle); 156*4eaa4710SRishi Srivatsavai if (sstate->ss_inst == NULL) 157*4eaa4710SRishi Srivatsavai goto failure; 158*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 159*4eaa4710SRishi Srivatsavai 160*4eaa4710SRishi Srivatsavai failure: 161*4eaa4710SRishi Srivatsavai shut_down_scf(sstate); 162*4eaa4710SRishi Srivatsavai return (status); 163*4eaa4710SRishi Srivatsavai } 164*4eaa4710SRishi Srivatsavai 165*4eaa4710SRishi Srivatsavai static void 166*4eaa4710SRishi Srivatsavai drop_composed(scf_state_t *sstate) 167*4eaa4710SRishi Srivatsavai { 168*4eaa4710SRishi Srivatsavai scf_property_destroy(sstate->ss_prop); 169*4eaa4710SRishi Srivatsavai scf_pg_destroy(sstate->ss_pg); 170*4eaa4710SRishi Srivatsavai scf_snapshot_destroy(sstate->ss_snap); 171*4eaa4710SRishi Srivatsavai } 172*4eaa4710SRishi Srivatsavai 173*4eaa4710SRishi Srivatsavai /* 174*4eaa4710SRishi Srivatsavai * This function sets up a composed view of the configuration information for 175*4eaa4710SRishi Srivatsavai * the specified instance. When this is done, the get_property() function 176*4eaa4710SRishi Srivatsavai * should be able to return individual parameters. 177*4eaa4710SRishi Srivatsavai */ 178*4eaa4710SRishi Srivatsavai static int 179*4eaa4710SRishi Srivatsavai get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate) 180*4eaa4710SRishi Srivatsavai { 181*4eaa4710SRishi Srivatsavai sstate->ss_snap = NULL; 182*4eaa4710SRishi Srivatsavai sstate->ss_pg = NULL; 183*4eaa4710SRishi Srivatsavai sstate->ss_prop = NULL; 184*4eaa4710SRishi Srivatsavai 185*4eaa4710SRishi Srivatsavai if (snap) { 186*4eaa4710SRishi Srivatsavai sstate->ss_snap = scf_snapshot_create(sstate->ss_handle); 187*4eaa4710SRishi Srivatsavai if (sstate->ss_snap == NULL) 188*4eaa4710SRishi Srivatsavai goto failure; 189*4eaa4710SRishi Srivatsavai if (scf_instance_get_snapshot(sstate->ss_inst, "running", 190*4eaa4710SRishi Srivatsavai sstate->ss_snap) != 0) 191*4eaa4710SRishi Srivatsavai goto failure; 192*4eaa4710SRishi Srivatsavai } 193*4eaa4710SRishi Srivatsavai if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL) 194*4eaa4710SRishi Srivatsavai goto failure; 195*4eaa4710SRishi Srivatsavai if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg, 196*4eaa4710SRishi Srivatsavai sstate->ss_pg) != 0) 197*4eaa4710SRishi Srivatsavai goto failure; 198*4eaa4710SRishi Srivatsavai if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) == 199*4eaa4710SRishi Srivatsavai NULL) 200*4eaa4710SRishi Srivatsavai goto failure; 201*4eaa4710SRishi Srivatsavai return (0); 202*4eaa4710SRishi Srivatsavai 203*4eaa4710SRishi Srivatsavai failure: 204*4eaa4710SRishi Srivatsavai drop_composed(sstate); 205*4eaa4710SRishi Srivatsavai return (-1); 206*4eaa4710SRishi Srivatsavai } 207*4eaa4710SRishi Srivatsavai 208*4eaa4710SRishi Srivatsavai static int 209*4eaa4710SRishi Srivatsavai get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer) 210*4eaa4710SRishi Srivatsavai { 211*4eaa4710SRishi Srivatsavai scf_value_t *val; 212*4eaa4710SRishi Srivatsavai int retv; 213*4eaa4710SRishi Srivatsavai 214*4eaa4710SRishi Srivatsavai if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 215*4eaa4710SRishi Srivatsavai return (-1); 216*4eaa4710SRishi Srivatsavai if ((val = scf_value_create(sstate->ss_handle)) == NULL) 217*4eaa4710SRishi Srivatsavai return (-1); 218*4eaa4710SRishi Srivatsavai 219*4eaa4710SRishi Srivatsavai if (scf_property_get_value(sstate->ss_prop, val) == 0 && 220*4eaa4710SRishi Srivatsavai scf_value_get_count(val, answer) == 0) 221*4eaa4710SRishi Srivatsavai retv = 0; 222*4eaa4710SRishi Srivatsavai else 223*4eaa4710SRishi Srivatsavai retv = -1; 224*4eaa4710SRishi Srivatsavai scf_value_destroy(val); 225*4eaa4710SRishi Srivatsavai return (retv); 226*4eaa4710SRishi Srivatsavai } 227*4eaa4710SRishi Srivatsavai 228*4eaa4710SRishi Srivatsavai static int 229*4eaa4710SRishi Srivatsavai get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer) 230*4eaa4710SRishi Srivatsavai { 231*4eaa4710SRishi Srivatsavai scf_value_t *val; 232*4eaa4710SRishi Srivatsavai int retv; 233*4eaa4710SRishi Srivatsavai uint8_t bval; 234*4eaa4710SRishi Srivatsavai 235*4eaa4710SRishi Srivatsavai if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 236*4eaa4710SRishi Srivatsavai return (-1); 237*4eaa4710SRishi Srivatsavai if ((val = scf_value_create(sstate->ss_handle)) == NULL) 238*4eaa4710SRishi Srivatsavai return (-1); 239*4eaa4710SRishi Srivatsavai 240*4eaa4710SRishi Srivatsavai if (scf_property_get_value(sstate->ss_prop, val) == 0 && 241*4eaa4710SRishi Srivatsavai scf_value_get_boolean(val, &bval) == 0) { 242*4eaa4710SRishi Srivatsavai retv = 0; 243*4eaa4710SRishi Srivatsavai *answer = bval != 0; 244*4eaa4710SRishi Srivatsavai } else { 245*4eaa4710SRishi Srivatsavai retv = -1; 246*4eaa4710SRishi Srivatsavai } 247*4eaa4710SRishi Srivatsavai scf_value_destroy(val); 248*4eaa4710SRishi Srivatsavai return (retv); 249*4eaa4710SRishi Srivatsavai } 250*4eaa4710SRishi Srivatsavai 251*4eaa4710SRishi Srivatsavai static dladm_status_t 252*4eaa4710SRishi Srivatsavai bridge_door_call(const char *instname, bridge_door_type_t dtype, 253*4eaa4710SRishi Srivatsavai datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp, 254*4eaa4710SRishi Srivatsavai boolean_t is_list) 255*4eaa4710SRishi Srivatsavai { 256*4eaa4710SRishi Srivatsavai char doorname[MAXPATHLEN]; 257*4eaa4710SRishi Srivatsavai int did, retv, etmp; 258*4eaa4710SRishi Srivatsavai bridge_door_cmd_t *bdc; 259*4eaa4710SRishi Srivatsavai door_arg_t arg; 260*4eaa4710SRishi Srivatsavai 261*4eaa4710SRishi Srivatsavai (void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME, 262*4eaa4710SRishi Srivatsavai instname); 263*4eaa4710SRishi Srivatsavai 264*4eaa4710SRishi Srivatsavai /* Knock on the door */ 265*4eaa4710SRishi Srivatsavai did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK); 266*4eaa4710SRishi Srivatsavai if (did == -1) 267*4eaa4710SRishi Srivatsavai return (dladm_errno2status(errno)); 268*4eaa4710SRishi Srivatsavai 269*4eaa4710SRishi Srivatsavai if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) { 270*4eaa4710SRishi Srivatsavai (void) close(did); 271*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 272*4eaa4710SRishi Srivatsavai } 273*4eaa4710SRishi Srivatsavai bdc->bdc_type = dtype; 274*4eaa4710SRishi Srivatsavai bdc->bdc_linkid = linkid; 275*4eaa4710SRishi Srivatsavai if (inlen != 0) 276*4eaa4710SRishi Srivatsavai (void) memcpy(bdc + 1, *bufp, inlen); 277*4eaa4710SRishi Srivatsavai 278*4eaa4710SRishi Srivatsavai (void) memset(&arg, 0, sizeof (arg)); 279*4eaa4710SRishi Srivatsavai arg.data_ptr = (char *)bdc; 280*4eaa4710SRishi Srivatsavai arg.data_size = sizeof (*bdc) + inlen; 281*4eaa4710SRishi Srivatsavai arg.rbuf = *bufp; 282*4eaa4710SRishi Srivatsavai arg.rsize = *buflenp; 283*4eaa4710SRishi Srivatsavai 284*4eaa4710SRishi Srivatsavai /* The door_call function doesn't restart, so take care of that */ 285*4eaa4710SRishi Srivatsavai do { 286*4eaa4710SRishi Srivatsavai errno = 0; 287*4eaa4710SRishi Srivatsavai if ((retv = door_call(did, &arg)) == 0) 288*4eaa4710SRishi Srivatsavai break; 289*4eaa4710SRishi Srivatsavai } while (errno == EINTR); 290*4eaa4710SRishi Srivatsavai 291*4eaa4710SRishi Srivatsavai /* If we get an unexpected response, then return an error */ 292*4eaa4710SRishi Srivatsavai if (retv == 0) { 293*4eaa4710SRishi Srivatsavai /* The daemon returns a single int for errors */ 294*4eaa4710SRishi Srivatsavai /* LINTED: pointer alignment */ 295*4eaa4710SRishi Srivatsavai if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) { 296*4eaa4710SRishi Srivatsavai retv = -1; 297*4eaa4710SRishi Srivatsavai /* LINTED: pointer alignment */ 298*4eaa4710SRishi Srivatsavai errno = *(int *)arg.rbuf; 299*4eaa4710SRishi Srivatsavai } 300*4eaa4710SRishi Srivatsavai /* Terminated daemon returns with zero data */ 301*4eaa4710SRishi Srivatsavai if (arg.data_size == 0) { 302*4eaa4710SRishi Srivatsavai retv = -1; 303*4eaa4710SRishi Srivatsavai errno = EBADF; 304*4eaa4710SRishi Srivatsavai } 305*4eaa4710SRishi Srivatsavai } 306*4eaa4710SRishi Srivatsavai 307*4eaa4710SRishi Srivatsavai if (retv == 0) { 308*4eaa4710SRishi Srivatsavai if (arg.rbuf != *bufp) { 309*4eaa4710SRishi Srivatsavai if (is_list) { 310*4eaa4710SRishi Srivatsavai void *newp; 311*4eaa4710SRishi Srivatsavai 312*4eaa4710SRishi Srivatsavai newp = realloc(*bufp, arg.data_size); 313*4eaa4710SRishi Srivatsavai if (newp == NULL) { 314*4eaa4710SRishi Srivatsavai retv = -1; 315*4eaa4710SRishi Srivatsavai } else { 316*4eaa4710SRishi Srivatsavai *bufp = newp; 317*4eaa4710SRishi Srivatsavai (void) memcpy(*bufp, arg.rbuf, 318*4eaa4710SRishi Srivatsavai arg.data_size); 319*4eaa4710SRishi Srivatsavai } 320*4eaa4710SRishi Srivatsavai } 321*4eaa4710SRishi Srivatsavai (void) munmap(arg.rbuf, arg.rsize); 322*4eaa4710SRishi Srivatsavai } 323*4eaa4710SRishi Srivatsavai if (is_list) { 324*4eaa4710SRishi Srivatsavai *buflenp = arg.data_size; 325*4eaa4710SRishi Srivatsavai } else if (arg.data_size != *buflenp || arg.rbuf != *bufp) { 326*4eaa4710SRishi Srivatsavai errno = EINVAL; 327*4eaa4710SRishi Srivatsavai retv = -1; 328*4eaa4710SRishi Srivatsavai } 329*4eaa4710SRishi Srivatsavai } 330*4eaa4710SRishi Srivatsavai 331*4eaa4710SRishi Srivatsavai etmp = errno; 332*4eaa4710SRishi Srivatsavai (void) close(did); 333*4eaa4710SRishi Srivatsavai 334*4eaa4710SRishi Srivatsavai /* Revoked door is the same as no door at all */ 335*4eaa4710SRishi Srivatsavai if (etmp == EBADF) 336*4eaa4710SRishi Srivatsavai etmp = ENOENT; 337*4eaa4710SRishi Srivatsavai 338*4eaa4710SRishi Srivatsavai return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp)); 339*4eaa4710SRishi Srivatsavai } 340*4eaa4710SRishi Srivatsavai 341*4eaa4710SRishi Srivatsavai /* 342*4eaa4710SRishi Srivatsavai * Wrapper function for making per-port calls. 343*4eaa4710SRishi Srivatsavai */ 344*4eaa4710SRishi Srivatsavai static dladm_status_t 345*4eaa4710SRishi Srivatsavai port_door_call(dladm_handle_t handle, datalink_id_t linkid, 346*4eaa4710SRishi Srivatsavai bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen) 347*4eaa4710SRishi Srivatsavai { 348*4eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 349*4eaa4710SRishi Srivatsavai dladm_status_t status; 350*4eaa4710SRishi Srivatsavai 351*4eaa4710SRishi Srivatsavai status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 352*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 353*4eaa4710SRishi Srivatsavai return (status); 354*4eaa4710SRishi Srivatsavai return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen, 355*4eaa4710SRishi Srivatsavai B_FALSE)); 356*4eaa4710SRishi Srivatsavai } 357*4eaa4710SRishi Srivatsavai 358*4eaa4710SRishi Srivatsavai static dladm_status_t 359*4eaa4710SRishi Srivatsavai bridge_refresh(const char *bridge) 360*4eaa4710SRishi Srivatsavai { 361*4eaa4710SRishi Srivatsavai dladm_status_t status; 362*4eaa4710SRishi Srivatsavai int twoints[2]; 363*4eaa4710SRishi Srivatsavai void *bdptr; 364*4eaa4710SRishi Srivatsavai size_t buflen; 365*4eaa4710SRishi Srivatsavai char *fmri; 366*4eaa4710SRishi Srivatsavai int refresh_count; 367*4eaa4710SRishi Srivatsavai 368*4eaa4710SRishi Srivatsavai buflen = sizeof (twoints); 369*4eaa4710SRishi Srivatsavai bdptr = twoints; 370*4eaa4710SRishi Srivatsavai status = bridge_door_call(bridge, bdcBridgeGetRefreshCount, 371*4eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE); 372*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_NOTFOUND) 373*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 374*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 375*4eaa4710SRishi Srivatsavai return (status); 376*4eaa4710SRishi Srivatsavai refresh_count = twoints[0]; 377*4eaa4710SRishi Srivatsavai if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL) 378*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 379*4eaa4710SRishi Srivatsavai status = smf_refresh_instance(fmri) == 0 ? 380*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK : DLADM_STATUS_FAILED; 381*4eaa4710SRishi Srivatsavai free(fmri); 382*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 383*4eaa4710SRishi Srivatsavai int i = 0; 384*4eaa4710SRishi Srivatsavai 385*4eaa4710SRishi Srivatsavai /* 386*4eaa4710SRishi Srivatsavai * SMF doesn't give any synchronous behavior or dependency 387*4eaa4710SRishi Srivatsavai * ordering for refresh operations, so we have to invent our 388*4eaa4710SRishi Srivatsavai * own mechanism here. Get the refresh counter from the 389*4eaa4710SRishi Srivatsavai * daemon, and wait for it to change. It's not pretty, but 390*4eaa4710SRishi Srivatsavai * it's sufficient. 391*4eaa4710SRishi Srivatsavai */ 392*4eaa4710SRishi Srivatsavai while (++i <= 10) { 393*4eaa4710SRishi Srivatsavai buflen = sizeof (twoints); 394*4eaa4710SRishi Srivatsavai bdptr = twoints; 395*4eaa4710SRishi Srivatsavai status = bridge_door_call(bridge, 396*4eaa4710SRishi Srivatsavai bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID, 397*4eaa4710SRishi Srivatsavai &bdptr, 0, &buflen, B_FALSE); 398*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 399*4eaa4710SRishi Srivatsavai break; 400*4eaa4710SRishi Srivatsavai if (twoints[0] != refresh_count) 401*4eaa4710SRishi Srivatsavai break; 402*4eaa4710SRishi Srivatsavai (void) usleep(100000); 403*4eaa4710SRishi Srivatsavai } 404*4eaa4710SRishi Srivatsavai fmri = alloc_fmri(TRILL_SVC_NAME, bridge); 405*4eaa4710SRishi Srivatsavai if (fmri == NULL) 406*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 407*4eaa4710SRishi Srivatsavai status = smf_refresh_instance(fmri) == 0 || 408*4eaa4710SRishi Srivatsavai scf_error() == SCF_ERROR_NOT_FOUND ? 409*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK : DLADM_STATUS_FAILED; 410*4eaa4710SRishi Srivatsavai free(fmri); 411*4eaa4710SRishi Srivatsavai } 412*4eaa4710SRishi Srivatsavai return (status); 413*4eaa4710SRishi Srivatsavai } 414*4eaa4710SRishi Srivatsavai 415*4eaa4710SRishi Srivatsavai /* 416*4eaa4710SRishi Srivatsavai * Look up bridge property values from SCF and return them. 417*4eaa4710SRishi Srivatsavai */ 418*4eaa4710SRishi Srivatsavai dladm_status_t 419*4eaa4710SRishi Srivatsavai dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg, 420*4eaa4710SRishi Srivatsavai dladm_bridge_prot_t *brprotp) 421*4eaa4710SRishi Srivatsavai { 422*4eaa4710SRishi Srivatsavai scf_state_t sstate; 423*4eaa4710SRishi Srivatsavai uint64_t value; 424*4eaa4710SRishi Srivatsavai boolean_t trill_enabled; 425*4eaa4710SRishi Srivatsavai 426*4eaa4710SRishi Srivatsavai cfg->field_mask = 0; 427*4eaa4710SRishi Srivatsavai cfg->bridge_priority = DEF_BR_PRIO; 428*4eaa4710SRishi Srivatsavai cfg->max_age = DEF_BR_MAXAGE; 429*4eaa4710SRishi Srivatsavai cfg->hello_time = DEF_BR_HELLOT; 430*4eaa4710SRishi Srivatsavai cfg->forward_delay = DEF_BR_FWDELAY; 431*4eaa4710SRishi Srivatsavai cfg->force_version = DEF_FORCE_VERS; 432*4eaa4710SRishi Srivatsavai 433*4eaa4710SRishi Srivatsavai (void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name)); 434*4eaa4710SRishi Srivatsavai 435*4eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_STP; 436*4eaa4710SRishi Srivatsavai 437*4eaa4710SRishi Srivatsavai /* It's ok for this to be missing; it's installed separately */ 438*4eaa4710SRishi Srivatsavai if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) { 439*4eaa4710SRishi Srivatsavai trill_enabled = B_FALSE; 440*4eaa4710SRishi Srivatsavai if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) == 441*4eaa4710SRishi Srivatsavai 0) { 442*4eaa4710SRishi Srivatsavai (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 443*4eaa4710SRishi Srivatsavai &trill_enabled); 444*4eaa4710SRishi Srivatsavai if (trill_enabled) 445*4eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_TRILL; 446*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 447*4eaa4710SRishi Srivatsavai } 448*4eaa4710SRishi Srivatsavai if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE, 449*4eaa4710SRishi Srivatsavai &sstate) == 0) { 450*4eaa4710SRishi Srivatsavai (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 451*4eaa4710SRishi Srivatsavai &trill_enabled); 452*4eaa4710SRishi Srivatsavai if (trill_enabled) 453*4eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_TRILL; 454*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 455*4eaa4710SRishi Srivatsavai } 456*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 457*4eaa4710SRishi Srivatsavai } 458*4eaa4710SRishi Srivatsavai 459*4eaa4710SRishi Srivatsavai cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ? 460*4eaa4710SRishi Srivatsavai STP_ENABLED : STP_DISABLED; 461*4eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_STATE; 462*4eaa4710SRishi Srivatsavai 463*4eaa4710SRishi Srivatsavai if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 464*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 465*4eaa4710SRishi Srivatsavai 466*4eaa4710SRishi Srivatsavai if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 467*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 468*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 469*4eaa4710SRishi Srivatsavai } 470*4eaa4710SRishi Srivatsavai 471*4eaa4710SRishi Srivatsavai if (get_count("priority", &sstate, &value) == 0) { 472*4eaa4710SRishi Srivatsavai cfg->bridge_priority = value; 473*4eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_PRIO; 474*4eaa4710SRishi Srivatsavai } 475*4eaa4710SRishi Srivatsavai if (get_count("max-age", &sstate, &value) == 0) { 476*4eaa4710SRishi Srivatsavai cfg->max_age = value / IEEE_TIMER_SCALE; 477*4eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_AGE; 478*4eaa4710SRishi Srivatsavai } 479*4eaa4710SRishi Srivatsavai if (get_count("hello-time", &sstate, &value) == 0) { 480*4eaa4710SRishi Srivatsavai cfg->hello_time = value / IEEE_TIMER_SCALE; 481*4eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_HELLO; 482*4eaa4710SRishi Srivatsavai } 483*4eaa4710SRishi Srivatsavai if (get_count("forward-delay", &sstate, &value) == 0) { 484*4eaa4710SRishi Srivatsavai cfg->forward_delay = value / IEEE_TIMER_SCALE; 485*4eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_DELAY; 486*4eaa4710SRishi Srivatsavai } 487*4eaa4710SRishi Srivatsavai if (get_count("force-protocol", &sstate, &value) == 0) { 488*4eaa4710SRishi Srivatsavai cfg->force_version = value; 489*4eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_FORCE_VER; 490*4eaa4710SRishi Srivatsavai } 491*4eaa4710SRishi Srivatsavai 492*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 493*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 494*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 495*4eaa4710SRishi Srivatsavai } 496*4eaa4710SRishi Srivatsavai 497*4eaa4710SRishi Srivatsavai /* 498*4eaa4710SRishi Srivatsavai * Retrieve special non-settable and undocumented parameters. 499*4eaa4710SRishi Srivatsavai */ 500*4eaa4710SRishi Srivatsavai dladm_status_t 501*4eaa4710SRishi Srivatsavai dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp, 502*4eaa4710SRishi Srivatsavai uint32_t *tablemaxp) 503*4eaa4710SRishi Srivatsavai { 504*4eaa4710SRishi Srivatsavai scf_state_t sstate; 505*4eaa4710SRishi Srivatsavai uint64_t value; 506*4eaa4710SRishi Srivatsavai 507*4eaa4710SRishi Srivatsavai *debugp = B_FALSE; 508*4eaa4710SRishi Srivatsavai *tablemaxp = 10000; 509*4eaa4710SRishi Srivatsavai 510*4eaa4710SRishi Srivatsavai if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 511*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 512*4eaa4710SRishi Srivatsavai 513*4eaa4710SRishi Srivatsavai if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 514*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 515*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 516*4eaa4710SRishi Srivatsavai } 517*4eaa4710SRishi Srivatsavai 518*4eaa4710SRishi Srivatsavai (void) get_boolean("debug", &sstate, debugp); 519*4eaa4710SRishi Srivatsavai if (get_count("table-maximum", &sstate, &value) == 0) 520*4eaa4710SRishi Srivatsavai *tablemaxp = (uint32_t)value; 521*4eaa4710SRishi Srivatsavai 522*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 523*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 524*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 525*4eaa4710SRishi Srivatsavai } 526*4eaa4710SRishi Srivatsavai 527*4eaa4710SRishi Srivatsavai static boolean_t 528*4eaa4710SRishi Srivatsavai set_count_property(scf_handle_t *handle, scf_transaction_t *tran, 529*4eaa4710SRishi Srivatsavai const char *propname, uint64_t propval) 530*4eaa4710SRishi Srivatsavai { 531*4eaa4710SRishi Srivatsavai scf_transaction_entry_t *entry; 532*4eaa4710SRishi Srivatsavai scf_value_t *value = NULL; 533*4eaa4710SRishi Srivatsavai 534*4eaa4710SRishi Srivatsavai if ((entry = scf_entry_create(handle)) == NULL) 535*4eaa4710SRishi Srivatsavai return (B_FALSE); 536*4eaa4710SRishi Srivatsavai 537*4eaa4710SRishi Srivatsavai if ((value = scf_value_create(handle)) == NULL) 538*4eaa4710SRishi Srivatsavai goto out; 539*4eaa4710SRishi Srivatsavai if (scf_transaction_property_new(tran, entry, propname, 540*4eaa4710SRishi Srivatsavai SCF_TYPE_COUNT) != 0 && 541*4eaa4710SRishi Srivatsavai scf_transaction_property_change(tran, entry, propname, 542*4eaa4710SRishi Srivatsavai SCF_TYPE_COUNT) != 0) 543*4eaa4710SRishi Srivatsavai goto out; 544*4eaa4710SRishi Srivatsavai scf_value_set_count(value, propval); 545*4eaa4710SRishi Srivatsavai if (scf_entry_add_value(entry, value) == 0) 546*4eaa4710SRishi Srivatsavai return (B_TRUE); 547*4eaa4710SRishi Srivatsavai 548*4eaa4710SRishi Srivatsavai out: 549*4eaa4710SRishi Srivatsavai if (value != NULL) 550*4eaa4710SRishi Srivatsavai scf_value_destroy(value); 551*4eaa4710SRishi Srivatsavai 552*4eaa4710SRishi Srivatsavai scf_entry_destroy_children(entry); 553*4eaa4710SRishi Srivatsavai scf_entry_destroy(entry); 554*4eaa4710SRishi Srivatsavai 555*4eaa4710SRishi Srivatsavai return (B_FALSE); 556*4eaa4710SRishi Srivatsavai } 557*4eaa4710SRishi Srivatsavai 558*4eaa4710SRishi Srivatsavai static boolean_t 559*4eaa4710SRishi Srivatsavai set_string_property(scf_handle_t *handle, scf_transaction_t *tran, 560*4eaa4710SRishi Srivatsavai const char *propname, const char *propval) 561*4eaa4710SRishi Srivatsavai { 562*4eaa4710SRishi Srivatsavai scf_transaction_entry_t *entry; 563*4eaa4710SRishi Srivatsavai scf_value_t *value = NULL; 564*4eaa4710SRishi Srivatsavai 565*4eaa4710SRishi Srivatsavai if ((entry = scf_entry_create(handle)) == NULL) 566*4eaa4710SRishi Srivatsavai return (B_FALSE); 567*4eaa4710SRishi Srivatsavai 568*4eaa4710SRishi Srivatsavai if ((value = scf_value_create(handle)) == NULL) 569*4eaa4710SRishi Srivatsavai goto out; 570*4eaa4710SRishi Srivatsavai if (scf_transaction_property_new(tran, entry, propname, 571*4eaa4710SRishi Srivatsavai SCF_TYPE_ASTRING) != 0 && 572*4eaa4710SRishi Srivatsavai scf_transaction_property_change(tran, entry, propname, 573*4eaa4710SRishi Srivatsavai SCF_TYPE_ASTRING) != 0) 574*4eaa4710SRishi Srivatsavai goto out; 575*4eaa4710SRishi Srivatsavai if (scf_value_set_astring(value, propval) != 0) 576*4eaa4710SRishi Srivatsavai goto out; 577*4eaa4710SRishi Srivatsavai if (scf_entry_add_value(entry, value) == 0) 578*4eaa4710SRishi Srivatsavai return (B_TRUE); 579*4eaa4710SRishi Srivatsavai 580*4eaa4710SRishi Srivatsavai out: 581*4eaa4710SRishi Srivatsavai if (value != NULL) 582*4eaa4710SRishi Srivatsavai scf_value_destroy(value); 583*4eaa4710SRishi Srivatsavai 584*4eaa4710SRishi Srivatsavai scf_entry_destroy_children(entry); 585*4eaa4710SRishi Srivatsavai scf_entry_destroy(entry); 586*4eaa4710SRishi Srivatsavai 587*4eaa4710SRishi Srivatsavai return (B_FALSE); 588*4eaa4710SRishi Srivatsavai } 589*4eaa4710SRishi Srivatsavai 590*4eaa4710SRishi Srivatsavai static boolean_t 591*4eaa4710SRishi Srivatsavai set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran, 592*4eaa4710SRishi Srivatsavai const char *propname, const char *propval) 593*4eaa4710SRishi Srivatsavai { 594*4eaa4710SRishi Srivatsavai scf_transaction_entry_t *entry; 595*4eaa4710SRishi Srivatsavai scf_value_t *value = NULL; 596*4eaa4710SRishi Srivatsavai 597*4eaa4710SRishi Srivatsavai if ((entry = scf_entry_create(handle)) == NULL) 598*4eaa4710SRishi Srivatsavai return (B_FALSE); 599*4eaa4710SRishi Srivatsavai 600*4eaa4710SRishi Srivatsavai if ((value = scf_value_create(handle)) == NULL) 601*4eaa4710SRishi Srivatsavai goto out; 602*4eaa4710SRishi Srivatsavai if (scf_transaction_property_new(tran, entry, propname, 603*4eaa4710SRishi Srivatsavai SCF_TYPE_FMRI) != 0 && 604*4eaa4710SRishi Srivatsavai scf_transaction_property_change(tran, entry, propname, 605*4eaa4710SRishi Srivatsavai SCF_TYPE_FMRI) != 0) 606*4eaa4710SRishi Srivatsavai goto out; 607*4eaa4710SRishi Srivatsavai if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0) 608*4eaa4710SRishi Srivatsavai goto out; 609*4eaa4710SRishi Srivatsavai if (scf_entry_add_value(entry, value) == 0) 610*4eaa4710SRishi Srivatsavai return (B_TRUE); 611*4eaa4710SRishi Srivatsavai 612*4eaa4710SRishi Srivatsavai out: 613*4eaa4710SRishi Srivatsavai if (value != NULL) 614*4eaa4710SRishi Srivatsavai scf_value_destroy(value); 615*4eaa4710SRishi Srivatsavai 616*4eaa4710SRishi Srivatsavai scf_entry_destroy_children(entry); 617*4eaa4710SRishi Srivatsavai scf_entry_destroy(entry); 618*4eaa4710SRishi Srivatsavai 619*4eaa4710SRishi Srivatsavai return (B_FALSE); 620*4eaa4710SRishi Srivatsavai } 621*4eaa4710SRishi Srivatsavai 622*4eaa4710SRishi Srivatsavai static dladm_status_t 623*4eaa4710SRishi Srivatsavai dladm_bridge_persist_conf(dladm_handle_t handle, const char *link, 624*4eaa4710SRishi Srivatsavai datalink_id_t linkid) 625*4eaa4710SRishi Srivatsavai { 626*4eaa4710SRishi Srivatsavai dladm_conf_t conf = DLADM_INVALID_CONF; 627*4eaa4710SRishi Srivatsavai dladm_status_t status; 628*4eaa4710SRishi Srivatsavai 629*4eaa4710SRishi Srivatsavai status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE, 630*4eaa4710SRishi Srivatsavai DL_ETHER, &conf); 631*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 632*4eaa4710SRishi Srivatsavai /* 633*4eaa4710SRishi Srivatsavai * Create the datalink entry for the bridge. Note that all of 634*4eaa4710SRishi Srivatsavai * the real configuration information is in SMF. 635*4eaa4710SRishi Srivatsavai */ 636*4eaa4710SRishi Srivatsavai status = dladm_write_conf(handle, conf); 637*4eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 638*4eaa4710SRishi Srivatsavai } 639*4eaa4710SRishi Srivatsavai return (status); 640*4eaa4710SRishi Srivatsavai } 641*4eaa4710SRishi Srivatsavai 642*4eaa4710SRishi Srivatsavai /* Convert bridge protection option string to dladm_bridge_prot_t */ 643*4eaa4710SRishi Srivatsavai dladm_status_t 644*4eaa4710SRishi Srivatsavai dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp) 645*4eaa4710SRishi Srivatsavai { 646*4eaa4710SRishi Srivatsavai if (strcmp(str, "stp") == 0) 647*4eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_STP; 648*4eaa4710SRishi Srivatsavai else if (strcmp(str, "trill") == 0) 649*4eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_TRILL; 650*4eaa4710SRishi Srivatsavai else 651*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_BADARG); 652*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 653*4eaa4710SRishi Srivatsavai } 654*4eaa4710SRishi Srivatsavai 655*4eaa4710SRishi Srivatsavai /* Convert bridge protection option from dladm_bridge_prot_t to string */ 656*4eaa4710SRishi Srivatsavai const char * 657*4eaa4710SRishi Srivatsavai dladm_bridge_prot2str(dladm_bridge_prot_t brprot) 658*4eaa4710SRishi Srivatsavai { 659*4eaa4710SRishi Srivatsavai switch (brprot) { 660*4eaa4710SRishi Srivatsavai case DLADM_BRIDGE_PROT_STP: 661*4eaa4710SRishi Srivatsavai return ("stp"); 662*4eaa4710SRishi Srivatsavai case DLADM_BRIDGE_PROT_TRILL: 663*4eaa4710SRishi Srivatsavai return ("trill"); 664*4eaa4710SRishi Srivatsavai default: 665*4eaa4710SRishi Srivatsavai return ("unknown"); 666*4eaa4710SRishi Srivatsavai } 667*4eaa4710SRishi Srivatsavai } 668*4eaa4710SRishi Srivatsavai 669*4eaa4710SRishi Srivatsavai static dladm_status_t 670*4eaa4710SRishi Srivatsavai enable_instance(const char *service_name, const char *instance) 671*4eaa4710SRishi Srivatsavai { 672*4eaa4710SRishi Srivatsavai dladm_status_t status; 673*4eaa4710SRishi Srivatsavai char *fmri = alloc_fmri(service_name, instance); 674*4eaa4710SRishi Srivatsavai 675*4eaa4710SRishi Srivatsavai if (fmri == NULL) 676*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 677*4eaa4710SRishi Srivatsavai status = smf_enable_instance(fmri, 0) == 0 ? 678*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK : DLADM_STATUS_FAILED; 679*4eaa4710SRishi Srivatsavai free(fmri); 680*4eaa4710SRishi Srivatsavai return (status); 681*4eaa4710SRishi Srivatsavai } 682*4eaa4710SRishi Srivatsavai 683*4eaa4710SRishi Srivatsavai /* 684*4eaa4710SRishi Srivatsavai * Shut down a possibly-running service instance. If this is a permanent 685*4eaa4710SRishi Srivatsavai * change, then delete it from the system. 686*4eaa4710SRishi Srivatsavai */ 687*4eaa4710SRishi Srivatsavai static dladm_status_t 688*4eaa4710SRishi Srivatsavai shut_down_instance(const char *service_name, const char *instance, 689*4eaa4710SRishi Srivatsavai uint32_t flags) 690*4eaa4710SRishi Srivatsavai { 691*4eaa4710SRishi Srivatsavai dladm_status_t status; 692*4eaa4710SRishi Srivatsavai char *fmri = alloc_fmri(service_name, instance); 693*4eaa4710SRishi Srivatsavai char *state; 694*4eaa4710SRishi Srivatsavai scf_state_t sstate; 695*4eaa4710SRishi Srivatsavai 696*4eaa4710SRishi Srivatsavai if (fmri == NULL) 697*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 698*4eaa4710SRishi Srivatsavai 699*4eaa4710SRishi Srivatsavai if (smf_disable_instance(fmri, 700*4eaa4710SRishi Srivatsavai flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) { 701*4eaa4710SRishi Srivatsavai useconds_t usecs, umax; 702*4eaa4710SRishi Srivatsavai 703*4eaa4710SRishi Srivatsavai /* If we can disable, then wait for it to happen. */ 704*4eaa4710SRishi Srivatsavai umax = DEFAULT_TIMEOUT; 705*4eaa4710SRishi Srivatsavai for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) { 706*4eaa4710SRishi Srivatsavai state = smf_get_state(fmri); 707*4eaa4710SRishi Srivatsavai if (state != NULL && 708*4eaa4710SRishi Srivatsavai strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 709*4eaa4710SRishi Srivatsavai break; 710*4eaa4710SRishi Srivatsavai free(state); 711*4eaa4710SRishi Srivatsavai usecs *= 2; 712*4eaa4710SRishi Srivatsavai if (usecs > umax) 713*4eaa4710SRishi Srivatsavai usecs = umax; 714*4eaa4710SRishi Srivatsavai (void) usleep(usecs); 715*4eaa4710SRishi Srivatsavai } 716*4eaa4710SRishi Srivatsavai if (umax == 0) { 717*4eaa4710SRishi Srivatsavai state = smf_get_state(fmri); 718*4eaa4710SRishi Srivatsavai if (state != NULL && 719*4eaa4710SRishi Srivatsavai strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 720*4eaa4710SRishi Srivatsavai umax = 1; 721*4eaa4710SRishi Srivatsavai } 722*4eaa4710SRishi Srivatsavai free(state); 723*4eaa4710SRishi Srivatsavai status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED; 724*4eaa4710SRishi Srivatsavai } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 725*4eaa4710SRishi Srivatsavai free(fmri); 726*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 727*4eaa4710SRishi Srivatsavai } else { 728*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 729*4eaa4710SRishi Srivatsavai } 730*4eaa4710SRishi Srivatsavai 731*4eaa4710SRishi Srivatsavai free(fmri); 732*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) && 733*4eaa4710SRishi Srivatsavai bind_instance(service_name, instance, &sstate) == 0) { 734*4eaa4710SRishi Srivatsavai (void) scf_instance_delete(sstate.ss_inst); 735*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 736*4eaa4710SRishi Srivatsavai } 737*4eaa4710SRishi Srivatsavai 738*4eaa4710SRishi Srivatsavai return (status); 739*4eaa4710SRishi Srivatsavai } 740*4eaa4710SRishi Srivatsavai 741*4eaa4710SRishi Srivatsavai static dladm_status_t 742*4eaa4710SRishi Srivatsavai disable_trill(const char *instance, uint32_t flags) 743*4eaa4710SRishi Srivatsavai { 744*4eaa4710SRishi Srivatsavai return (shut_down_instance(TRILL_SVC_NAME, instance, flags)); 745*4eaa4710SRishi Srivatsavai } 746*4eaa4710SRishi Srivatsavai 747*4eaa4710SRishi Srivatsavai /* 748*4eaa4710SRishi Srivatsavai * To enable TRILL, we must create a new instance of the TRILL service, then 749*4eaa4710SRishi Srivatsavai * add proper dependencies to it, and finally mark it as enabled. The 750*4eaa4710SRishi Srivatsavai * dependencies will keep it from going on-line until the bridge is running. 751*4eaa4710SRishi Srivatsavai */ 752*4eaa4710SRishi Srivatsavai static dladm_status_t 753*4eaa4710SRishi Srivatsavai enable_trill(const char *instance) 754*4eaa4710SRishi Srivatsavai { 755*4eaa4710SRishi Srivatsavai dladm_status_t status = DLADM_STATUS_FAILED; 756*4eaa4710SRishi Srivatsavai char *fmri = NULL; 757*4eaa4710SRishi Srivatsavai scf_state_t sstate; 758*4eaa4710SRishi Srivatsavai scf_transaction_t *tran = NULL; 759*4eaa4710SRishi Srivatsavai boolean_t new_instance = B_FALSE; 760*4eaa4710SRishi Srivatsavai boolean_t new_pg = B_FALSE; 761*4eaa4710SRishi Srivatsavai int rv; 762*4eaa4710SRishi Srivatsavai 763*4eaa4710SRishi Srivatsavai /* 764*4eaa4710SRishi Srivatsavai * This check is here in case the user has installed and then removed 765*4eaa4710SRishi Srivatsavai * the package. SMF should remove the manifest, but currently does 766*4eaa4710SRishi Srivatsavai * not. 767*4eaa4710SRishi Srivatsavai */ 768*4eaa4710SRishi Srivatsavai if (access("/usr/sbin/trilld", F_OK) != 0) 769*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OPTMISSING); 770*4eaa4710SRishi Srivatsavai 771*4eaa4710SRishi Srivatsavai if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) != 772*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 773*4eaa4710SRishi Srivatsavai goto out; 774*4eaa4710SRishi Srivatsavai 775*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 776*4eaa4710SRishi Srivatsavai if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) != 777*4eaa4710SRishi Srivatsavai 0) { 778*4eaa4710SRishi Srivatsavai if (scf_service_add_instance(sstate.ss_svc, instance, 779*4eaa4710SRishi Srivatsavai sstate.ss_inst) != 0) 780*4eaa4710SRishi Srivatsavai goto out; 781*4eaa4710SRishi Srivatsavai new_instance = B_TRUE; 782*4eaa4710SRishi Srivatsavai } 783*4eaa4710SRishi Srivatsavai 784*4eaa4710SRishi Srivatsavai if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 785*4eaa4710SRishi Srivatsavai goto out; 786*4eaa4710SRishi Srivatsavai 787*4eaa4710SRishi Srivatsavai if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 788*4eaa4710SRishi Srivatsavai goto out; 789*4eaa4710SRishi Srivatsavai 790*4eaa4710SRishi Srivatsavai if (scf_instance_get_pg(sstate.ss_inst, "bridging", 791*4eaa4710SRishi Srivatsavai sstate.ss_pg) == 0) { 792*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 793*4eaa4710SRishi Srivatsavai goto out; 794*4eaa4710SRishi Srivatsavai } 795*4eaa4710SRishi Srivatsavai 796*4eaa4710SRishi Srivatsavai if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL) 797*4eaa4710SRishi Srivatsavai goto out; 798*4eaa4710SRishi Srivatsavai 799*4eaa4710SRishi Srivatsavai if (scf_instance_add_pg(sstate.ss_inst, "bridging", 800*4eaa4710SRishi Srivatsavai SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0) 801*4eaa4710SRishi Srivatsavai goto out; 802*4eaa4710SRishi Srivatsavai 803*4eaa4710SRishi Srivatsavai new_pg = B_TRUE; 804*4eaa4710SRishi Srivatsavai do { 805*4eaa4710SRishi Srivatsavai if (scf_transaction_start(tran, sstate.ss_pg) != 0) 806*4eaa4710SRishi Srivatsavai goto out; 807*4eaa4710SRishi Srivatsavai 808*4eaa4710SRishi Srivatsavai if (!set_string_property(sstate.ss_handle, tran, 809*4eaa4710SRishi Srivatsavai SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL)) 810*4eaa4710SRishi Srivatsavai goto out; 811*4eaa4710SRishi Srivatsavai if (!set_string_property(sstate.ss_handle, tran, 812*4eaa4710SRishi Srivatsavai SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART)) 813*4eaa4710SRishi Srivatsavai goto out; 814*4eaa4710SRishi Srivatsavai if (!set_string_property(sstate.ss_handle, tran, 815*4eaa4710SRishi Srivatsavai SCF_PROPERTY_TYPE, "service")) 816*4eaa4710SRishi Srivatsavai goto out; 817*4eaa4710SRishi Srivatsavai if (!set_fmri_property(sstate.ss_handle, tran, 818*4eaa4710SRishi Srivatsavai SCF_PROPERTY_ENTITIES, fmri)) 819*4eaa4710SRishi Srivatsavai goto out; 820*4eaa4710SRishi Srivatsavai 821*4eaa4710SRishi Srivatsavai rv = scf_transaction_commit(tran); 822*4eaa4710SRishi Srivatsavai scf_transaction_reset(tran); 823*4eaa4710SRishi Srivatsavai if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 824*4eaa4710SRishi Srivatsavai goto out; 825*4eaa4710SRishi Srivatsavai } while (rv == 0); 826*4eaa4710SRishi Srivatsavai if (rv != 1) 827*4eaa4710SRishi Srivatsavai goto out; 828*4eaa4710SRishi Srivatsavai 829*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 830*4eaa4710SRishi Srivatsavai 831*4eaa4710SRishi Srivatsavai out: 832*4eaa4710SRishi Srivatsavai free(fmri); 833*4eaa4710SRishi Srivatsavai if (tran != NULL) { 834*4eaa4710SRishi Srivatsavai scf_transaction_destroy_children(tran); 835*4eaa4710SRishi Srivatsavai scf_transaction_destroy(tran); 836*4eaa4710SRishi Srivatsavai } 837*4eaa4710SRishi Srivatsavai 838*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_pg) 839*4eaa4710SRishi Srivatsavai (void) scf_pg_delete(sstate.ss_pg); 840*4eaa4710SRishi Srivatsavai 841*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 842*4eaa4710SRishi Srivatsavai 843*4eaa4710SRishi Srivatsavai /* 844*4eaa4710SRishi Srivatsavai * If we created an instance and then failed, then remove the instance 845*4eaa4710SRishi Srivatsavai * from the system. 846*4eaa4710SRishi Srivatsavai */ 847*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_instance) 848*4eaa4710SRishi Srivatsavai (void) scf_instance_delete(sstate.ss_inst); 849*4eaa4710SRishi Srivatsavai 850*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 851*4eaa4710SRishi Srivatsavai 852*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 853*4eaa4710SRishi Srivatsavai status = enable_instance(TRILL_SVC_NAME, instance); 854*4eaa4710SRishi Srivatsavai 855*4eaa4710SRishi Srivatsavai return (status); 856*4eaa4710SRishi Srivatsavai } 857*4eaa4710SRishi Srivatsavai 858*4eaa4710SRishi Srivatsavai /* 859*4eaa4710SRishi Srivatsavai * Create a new bridge or modify an existing one. Update the SMF configuration 860*4eaa4710SRishi Srivatsavai * and add links. 861*4eaa4710SRishi Srivatsavai * 862*4eaa4710SRishi Srivatsavai * Input timer values are in IEEE scaled (* 256) format. 863*4eaa4710SRishi Srivatsavai */ 864*4eaa4710SRishi Srivatsavai dladm_status_t 865*4eaa4710SRishi Srivatsavai dladm_bridge_configure(dladm_handle_t handle, const char *name, 866*4eaa4710SRishi Srivatsavai const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags) 867*4eaa4710SRishi Srivatsavai { 868*4eaa4710SRishi Srivatsavai dladm_status_t status; 869*4eaa4710SRishi Srivatsavai scf_state_t sstate; 870*4eaa4710SRishi Srivatsavai scf_transaction_t *tran = NULL; 871*4eaa4710SRishi Srivatsavai boolean_t new_instance = B_FALSE; 872*4eaa4710SRishi Srivatsavai boolean_t new_pg = B_FALSE; 873*4eaa4710SRishi Srivatsavai datalink_id_t linkid = DATALINK_INVALID_LINKID; 874*4eaa4710SRishi Srivatsavai char linkname[MAXLINKNAMELEN]; 875*4eaa4710SRishi Srivatsavai int rv; 876*4eaa4710SRishi Srivatsavai 877*4eaa4710SRishi Srivatsavai if (!dladm_valid_bridgename(name)) 878*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_FAILED); 879*4eaa4710SRishi Srivatsavai 880*4eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_CREATE) { 881*4eaa4710SRishi Srivatsavai /* 882*4eaa4710SRishi Srivatsavai * This check is here in case the user has installed and then 883*4eaa4710SRishi Srivatsavai * removed the package. SMF should remove the manifest, but 884*4eaa4710SRishi Srivatsavai * currently does not. 885*4eaa4710SRishi Srivatsavai */ 886*4eaa4710SRishi Srivatsavai if (access("/usr/lib/bridged", F_OK) != 0) 887*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OPTMISSING); 888*4eaa4710SRishi Srivatsavai 889*4eaa4710SRishi Srivatsavai (void) snprintf(linkname, sizeof (linkname), "%s0", name); 890*4eaa4710SRishi Srivatsavai status = dladm_create_datalink_id(handle, linkname, 891*4eaa4710SRishi Srivatsavai DATALINK_CLASS_BRIDGE, DL_ETHER, 892*4eaa4710SRishi Srivatsavai flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid); 893*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 894*4eaa4710SRishi Srivatsavai return (status); 895*4eaa4710SRishi Srivatsavai 896*4eaa4710SRishi Srivatsavai if ((flags & DLADM_OPT_PERSIST) && 897*4eaa4710SRishi Srivatsavai (status = dladm_bridge_persist_conf(handle, linkname, 898*4eaa4710SRishi Srivatsavai linkid) != DLADM_STATUS_OK)) 899*4eaa4710SRishi Srivatsavai goto dladm_fail; 900*4eaa4710SRishi Srivatsavai } 901*4eaa4710SRishi Srivatsavai 902*4eaa4710SRishi Srivatsavai if (brprot == DLADM_BRIDGE_PROT_TRILL) 903*4eaa4710SRishi Srivatsavai status = enable_trill(name); 904*4eaa4710SRishi Srivatsavai else 905*4eaa4710SRishi Srivatsavai status = disable_trill(name, flags); 906*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 907*4eaa4710SRishi Srivatsavai goto dladm_fail; 908*4eaa4710SRishi Srivatsavai 909*4eaa4710SRishi Srivatsavai if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) != 910*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 911*4eaa4710SRishi Srivatsavai goto out; 912*4eaa4710SRishi Srivatsavai 913*4eaa4710SRishi Srivatsavai /* set up for a series of scf calls */ 914*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 915*4eaa4710SRishi Srivatsavai 916*4eaa4710SRishi Srivatsavai if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) == 917*4eaa4710SRishi Srivatsavai 0) { 918*4eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_CREATE) { 919*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_EXIST; 920*4eaa4710SRishi Srivatsavai goto out; 921*4eaa4710SRishi Srivatsavai } 922*4eaa4710SRishi Srivatsavai } else { 923*4eaa4710SRishi Srivatsavai if (!(flags & DLADM_OPT_CREATE)) { 924*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_NOTFOUND; 925*4eaa4710SRishi Srivatsavai goto out; 926*4eaa4710SRishi Srivatsavai } 927*4eaa4710SRishi Srivatsavai if (scf_service_add_instance(sstate.ss_svc, name, 928*4eaa4710SRishi Srivatsavai sstate.ss_inst) != 0) 929*4eaa4710SRishi Srivatsavai goto out; 930*4eaa4710SRishi Srivatsavai new_instance = B_TRUE; 931*4eaa4710SRishi Srivatsavai } 932*4eaa4710SRishi Srivatsavai 933*4eaa4710SRishi Srivatsavai if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 934*4eaa4710SRishi Srivatsavai goto out; 935*4eaa4710SRishi Srivatsavai 936*4eaa4710SRishi Srivatsavai if (cfg->field_mask & BR_CFG_ALL) { 937*4eaa4710SRishi Srivatsavai if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 938*4eaa4710SRishi Srivatsavai goto out; 939*4eaa4710SRishi Srivatsavai if (scf_instance_add_pg(sstate.ss_inst, "config", 940*4eaa4710SRishi Srivatsavai SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 941*4eaa4710SRishi Srivatsavai new_pg = B_TRUE; 942*4eaa4710SRishi Srivatsavai } else if (scf_instance_get_pg(sstate.ss_inst, "config", 943*4eaa4710SRishi Srivatsavai sstate.ss_pg) != 0) { 944*4eaa4710SRishi Srivatsavai goto out; 945*4eaa4710SRishi Srivatsavai } 946*4eaa4710SRishi Srivatsavai do { 947*4eaa4710SRishi Srivatsavai if (scf_transaction_start(tran, sstate.ss_pg) != 0) 948*4eaa4710SRishi Srivatsavai goto out; 949*4eaa4710SRishi Srivatsavai 950*4eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_PRIO) && 951*4eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 952*4eaa4710SRishi Srivatsavai "priority", cfg->bridge_priority)) 953*4eaa4710SRishi Srivatsavai goto out; 954*4eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_AGE) && 955*4eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 956*4eaa4710SRishi Srivatsavai "max-age", cfg->max_age * IEEE_TIMER_SCALE)) 957*4eaa4710SRishi Srivatsavai goto out; 958*4eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_HELLO) && 959*4eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 960*4eaa4710SRishi Srivatsavai "hello-time", cfg->hello_time * IEEE_TIMER_SCALE)) 961*4eaa4710SRishi Srivatsavai goto out; 962*4eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_DELAY) && 963*4eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 964*4eaa4710SRishi Srivatsavai "forward-delay", 965*4eaa4710SRishi Srivatsavai cfg->forward_delay * IEEE_TIMER_SCALE)) 966*4eaa4710SRishi Srivatsavai goto out; 967*4eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_FORCE_VER) && 968*4eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 969*4eaa4710SRishi Srivatsavai "force-protocol", cfg->force_version)) 970*4eaa4710SRishi Srivatsavai goto out; 971*4eaa4710SRishi Srivatsavai 972*4eaa4710SRishi Srivatsavai rv = scf_transaction_commit(tran); 973*4eaa4710SRishi Srivatsavai scf_transaction_reset(tran); 974*4eaa4710SRishi Srivatsavai if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 975*4eaa4710SRishi Srivatsavai goto out; 976*4eaa4710SRishi Srivatsavai } while (rv == 0); 977*4eaa4710SRishi Srivatsavai if (rv != 1) 978*4eaa4710SRishi Srivatsavai goto out; 979*4eaa4710SRishi Srivatsavai } 980*4eaa4710SRishi Srivatsavai 981*4eaa4710SRishi Srivatsavai /* 982*4eaa4710SRishi Srivatsavai * If we're modifying an existing and running bridge, then tell the 983*4eaa4710SRishi Srivatsavai * daemon to update the requested values. 984*4eaa4710SRishi Srivatsavai */ 985*4eaa4710SRishi Srivatsavai if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE)) 986*4eaa4710SRishi Srivatsavai status = bridge_refresh(name); 987*4eaa4710SRishi Srivatsavai else 988*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 989*4eaa4710SRishi Srivatsavai 990*4eaa4710SRishi Srivatsavai out: 991*4eaa4710SRishi Srivatsavai if (tran != NULL) { 992*4eaa4710SRishi Srivatsavai scf_transaction_destroy_children(tran); 993*4eaa4710SRishi Srivatsavai scf_transaction_destroy(tran); 994*4eaa4710SRishi Srivatsavai } 995*4eaa4710SRishi Srivatsavai 996*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_pg) 997*4eaa4710SRishi Srivatsavai (void) scf_pg_delete(sstate.ss_pg); 998*4eaa4710SRishi Srivatsavai 999*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 1000*4eaa4710SRishi Srivatsavai 1001*4eaa4710SRishi Srivatsavai /* 1002*4eaa4710SRishi Srivatsavai * If we created an instance and then failed, then remove the instance 1003*4eaa4710SRishi Srivatsavai * from the system. 1004*4eaa4710SRishi Srivatsavai */ 1005*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_instance) 1006*4eaa4710SRishi Srivatsavai (void) scf_instance_delete(sstate.ss_inst); 1007*4eaa4710SRishi Srivatsavai 1008*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 1009*4eaa4710SRishi Srivatsavai 1010*4eaa4710SRishi Srivatsavai /* 1011*4eaa4710SRishi Srivatsavai * Remove the bridge linkid if we've allocated one in this function but 1012*4eaa4710SRishi Srivatsavai * we've failed to set up the SMF properties. 1013*4eaa4710SRishi Srivatsavai */ 1014*4eaa4710SRishi Srivatsavai dladm_fail: 1015*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) { 1016*4eaa4710SRishi Srivatsavai (void) dladm_remove_conf(handle, linkid); 1017*4eaa4710SRishi Srivatsavai (void) dladm_destroy_datalink_id(handle, linkid, flags); 1018*4eaa4710SRishi Srivatsavai } 1019*4eaa4710SRishi Srivatsavai 1020*4eaa4710SRishi Srivatsavai return (status); 1021*4eaa4710SRishi Srivatsavai } 1022*4eaa4710SRishi Srivatsavai 1023*4eaa4710SRishi Srivatsavai /* 1024*4eaa4710SRishi Srivatsavai * Enable a newly-created bridge in SMF by creating "general/enabled" and 1025*4eaa4710SRishi Srivatsavai * deleting any "general_ovr/enabled" (used for temporary services). 1026*4eaa4710SRishi Srivatsavai */ 1027*4eaa4710SRishi Srivatsavai dladm_status_t 1028*4eaa4710SRishi Srivatsavai dladm_bridge_enable(const char *name) 1029*4eaa4710SRishi Srivatsavai { 1030*4eaa4710SRishi Srivatsavai return (enable_instance(BRIDGE_SVC_NAME, name)); 1031*4eaa4710SRishi Srivatsavai } 1032*4eaa4710SRishi Srivatsavai 1033*4eaa4710SRishi Srivatsavai /* 1034*4eaa4710SRishi Srivatsavai * Set a link as a member of a bridge, or remove bridge membership. If the 1035*4eaa4710SRishi Srivatsavai * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running. 1036*4eaa4710SRishi Srivatsavai * In all other cases, we must tell the daemon to add or delete the link in 1037*4eaa4710SRishi Srivatsavai * order to stay in sync. 1038*4eaa4710SRishi Srivatsavai */ 1039*4eaa4710SRishi Srivatsavai dladm_status_t 1040*4eaa4710SRishi Srivatsavai dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid, 1041*4eaa4710SRishi Srivatsavai const char *bridge) 1042*4eaa4710SRishi Srivatsavai { 1043*4eaa4710SRishi Srivatsavai dladm_status_t status; 1044*4eaa4710SRishi Srivatsavai dladm_conf_t conf; 1045*4eaa4710SRishi Srivatsavai char oldbridge[MAXLINKNAMELEN]; 1046*4eaa4710SRishi Srivatsavai boolean_t has_oldbridge; 1047*4eaa4710SRishi Srivatsavai boolean_t changed = B_FALSE; 1048*4eaa4710SRishi Srivatsavai 1049*4eaa4710SRishi Srivatsavai if (*bridge != '\0' && !dladm_valid_bridgename(bridge)) 1050*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_FAILED); 1051*4eaa4710SRishi Srivatsavai 1052*4eaa4710SRishi Srivatsavai if ((status = dladm_read_conf(handle, linkid, &conf)) != 1053*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 1054*4eaa4710SRishi Srivatsavai return (status); 1055*4eaa4710SRishi Srivatsavai 1056*4eaa4710SRishi Srivatsavai has_oldbridge = B_FALSE; 1057*4eaa4710SRishi Srivatsavai status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge, 1058*4eaa4710SRishi Srivatsavai sizeof (oldbridge)); 1059*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 1060*4eaa4710SRishi Srivatsavai /* 1061*4eaa4710SRishi Srivatsavai * Don't allow a link to be reassigned directly from one bridge 1062*4eaa4710SRishi Srivatsavai * to another. It must be removed first. 1063*4eaa4710SRishi Srivatsavai */ 1064*4eaa4710SRishi Srivatsavai if (*oldbridge != '\0' && *bridge != '\0') { 1065*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_EXIST; 1066*4eaa4710SRishi Srivatsavai goto out; 1067*4eaa4710SRishi Srivatsavai } 1068*4eaa4710SRishi Srivatsavai has_oldbridge = B_TRUE; 1069*4eaa4710SRishi Srivatsavai } else if (status != DLADM_STATUS_NOTFOUND) { 1070*4eaa4710SRishi Srivatsavai goto out; 1071*4eaa4710SRishi Srivatsavai } 1072*4eaa4710SRishi Srivatsavai 1073*4eaa4710SRishi Srivatsavai if (*bridge != '\0') { 1074*4eaa4710SRishi Srivatsavai status = dladm_set_conf_field(handle, conf, FBRIDGE, 1075*4eaa4710SRishi Srivatsavai DLADM_TYPE_STR, bridge); 1076*4eaa4710SRishi Srivatsavai changed = B_TRUE; 1077*4eaa4710SRishi Srivatsavai } else if (has_oldbridge) { 1078*4eaa4710SRishi Srivatsavai status = dladm_unset_conf_field(handle, conf, FBRIDGE); 1079*4eaa4710SRishi Srivatsavai changed = B_TRUE; 1080*4eaa4710SRishi Srivatsavai } else { 1081*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 1082*4eaa4710SRishi Srivatsavai goto out; 1083*4eaa4710SRishi Srivatsavai } 1084*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 1085*4eaa4710SRishi Srivatsavai status = dladm_write_conf(handle, conf); 1086*4eaa4710SRishi Srivatsavai 1087*4eaa4710SRishi Srivatsavai out: 1088*4eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 1089*4eaa4710SRishi Srivatsavai if (changed && status == DLADM_STATUS_OK) { 1090*4eaa4710SRishi Srivatsavai if (bridge[0] == '\0') 1091*4eaa4710SRishi Srivatsavai bridge = oldbridge; 1092*4eaa4710SRishi Srivatsavai status = bridge_refresh(bridge); 1093*4eaa4710SRishi Srivatsavai } 1094*4eaa4710SRishi Srivatsavai return (status); 1095*4eaa4710SRishi Srivatsavai } 1096*4eaa4710SRishi Srivatsavai 1097*4eaa4710SRishi Srivatsavai /* 1098*4eaa4710SRishi Srivatsavai * Get the name of the bridge of which the given linkid is a member. 1099*4eaa4710SRishi Srivatsavai */ 1100*4eaa4710SRishi Srivatsavai dladm_status_t 1101*4eaa4710SRishi Srivatsavai dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge, 1102*4eaa4710SRishi Srivatsavai size_t bridgelen) 1103*4eaa4710SRishi Srivatsavai { 1104*4eaa4710SRishi Srivatsavai dladm_status_t status; 1105*4eaa4710SRishi Srivatsavai dladm_conf_t conf; 1106*4eaa4710SRishi Srivatsavai 1107*4eaa4710SRishi Srivatsavai if ((status = dladm_read_conf(handle, linkid, &conf)) != 1108*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 1109*4eaa4710SRishi Srivatsavai return (status); 1110*4eaa4710SRishi Srivatsavai 1111*4eaa4710SRishi Srivatsavai *bridge = '\0'; 1112*4eaa4710SRishi Srivatsavai status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen); 1113*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK && *bridge == '\0') 1114*4eaa4710SRishi Srivatsavai status = DLADM_STATUS_NOTFOUND; 1115*4eaa4710SRishi Srivatsavai 1116*4eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 1117*4eaa4710SRishi Srivatsavai return (status); 1118*4eaa4710SRishi Srivatsavai } 1119*4eaa4710SRishi Srivatsavai 1120*4eaa4710SRishi Srivatsavai dladm_status_t 1121*4eaa4710SRishi Srivatsavai dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid) 1122*4eaa4710SRishi Srivatsavai { 1123*4eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 1124*4eaa4710SRishi Srivatsavai dladm_status_t status; 1125*4eaa4710SRishi Srivatsavai 1126*4eaa4710SRishi Srivatsavai status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 1127*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_NOTFOUND) 1128*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 1129*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 1130*4eaa4710SRishi Srivatsavai status = bridge_refresh(bridge); 1131*4eaa4710SRishi Srivatsavai return (status); 1132*4eaa4710SRishi Srivatsavai } 1133*4eaa4710SRishi Srivatsavai 1134*4eaa4710SRishi Srivatsavai typedef struct bridge_held_arg_s { 1135*4eaa4710SRishi Srivatsavai const char *bha_bridge; 1136*4eaa4710SRishi Srivatsavai boolean_t bha_isheld; 1137*4eaa4710SRishi Srivatsavai } bridge_held_arg_t; 1138*4eaa4710SRishi Srivatsavai 1139*4eaa4710SRishi Srivatsavai static int 1140*4eaa4710SRishi Srivatsavai i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1141*4eaa4710SRishi Srivatsavai { 1142*4eaa4710SRishi Srivatsavai dladm_status_t status = DLADM_STATUS_FAILED; 1143*4eaa4710SRishi Srivatsavai dladm_conf_t conf; 1144*4eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 1145*4eaa4710SRishi Srivatsavai bridge_held_arg_t *bha = arg; 1146*4eaa4710SRishi Srivatsavai 1147*4eaa4710SRishi Srivatsavai if ((status = dladm_read_conf(handle, linkid, &conf)) != 1148*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 1149*4eaa4710SRishi Srivatsavai return (DLADM_WALK_CONTINUE); 1150*4eaa4710SRishi Srivatsavai status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, 1151*4eaa4710SRishi Srivatsavai sizeof (bridge)); 1152*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) { 1153*4eaa4710SRishi Srivatsavai bha->bha_isheld = B_TRUE; 1154*4eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 1155*4eaa4710SRishi Srivatsavai return (DLADM_WALK_TERMINATE); 1156*4eaa4710SRishi Srivatsavai } else { 1157*4eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 1158*4eaa4710SRishi Srivatsavai return (DLADM_WALK_CONTINUE); 1159*4eaa4710SRishi Srivatsavai } 1160*4eaa4710SRishi Srivatsavai } 1161*4eaa4710SRishi Srivatsavai 1162*4eaa4710SRishi Srivatsavai /* 1163*4eaa4710SRishi Srivatsavai * Delete a previously created bridge. 1164*4eaa4710SRishi Srivatsavai */ 1165*4eaa4710SRishi Srivatsavai dladm_status_t 1166*4eaa4710SRishi Srivatsavai dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags) 1167*4eaa4710SRishi Srivatsavai { 1168*4eaa4710SRishi Srivatsavai datalink_id_t linkid; 1169*4eaa4710SRishi Srivatsavai datalink_class_t class; 1170*4eaa4710SRishi Srivatsavai dladm_status_t status; 1171*4eaa4710SRishi Srivatsavai char linkname[MAXLINKNAMELEN]; 1172*4eaa4710SRishi Srivatsavai 1173*4eaa4710SRishi Srivatsavai if (!dladm_valid_bridgename(bridge)) 1174*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_LINKINVAL); 1175*4eaa4710SRishi Srivatsavai 1176*4eaa4710SRishi Srivatsavai /* Get the datalink ID for this bridge */ 1177*4eaa4710SRishi Srivatsavai (void) snprintf(linkname, sizeof (linkname), "%s0", bridge); 1178*4eaa4710SRishi Srivatsavai if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) != 1179*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 1180*4eaa4710SRishi Srivatsavai linkid = DATALINK_INVALID_LINKID; 1181*4eaa4710SRishi Srivatsavai else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 1182*4eaa4710SRishi Srivatsavai NULL, 0) != DLADM_STATUS_OK) 1183*4eaa4710SRishi Srivatsavai linkid = DATALINK_INVALID_LINKID; 1184*4eaa4710SRishi Srivatsavai else if (class != DATALINK_CLASS_BRIDGE) 1185*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_BADARG); 1186*4eaa4710SRishi Srivatsavai 1187*4eaa4710SRishi Srivatsavai if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID) 1188*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_BADARG); 1189*4eaa4710SRishi Srivatsavai 1190*4eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_PERSIST) { 1191*4eaa4710SRishi Srivatsavai bridge_held_arg_t arg; 1192*4eaa4710SRishi Srivatsavai 1193*4eaa4710SRishi Srivatsavai arg.bha_bridge = bridge; 1194*4eaa4710SRishi Srivatsavai arg.bha_isheld = B_FALSE; 1195*4eaa4710SRishi Srivatsavai 1196*4eaa4710SRishi Srivatsavai /* 1197*4eaa4710SRishi Srivatsavai * See whether there are any persistent links using this 1198*4eaa4710SRishi Srivatsavai * bridge. If so, we fail the operation. 1199*4eaa4710SRishi Srivatsavai */ 1200*4eaa4710SRishi Srivatsavai (void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle, 1201*4eaa4710SRishi Srivatsavai &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 1202*4eaa4710SRishi Srivatsavai DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET, 1203*4eaa4710SRishi Srivatsavai DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1204*4eaa4710SRishi Srivatsavai if (arg.bha_isheld) 1205*4eaa4710SRishi Srivatsavai return (DLADM_STATUS_LINKBUSY); 1206*4eaa4710SRishi Srivatsavai } 1207*4eaa4710SRishi Srivatsavai 1208*4eaa4710SRishi Srivatsavai if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK) 1209*4eaa4710SRishi Srivatsavai goto out; 1210*4eaa4710SRishi Srivatsavai 1211*4eaa4710SRishi Srivatsavai /* Disable or remove the SMF instance */ 1212*4eaa4710SRishi Srivatsavai status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags); 1213*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 1214*4eaa4710SRishi Srivatsavai goto out; 1215*4eaa4710SRishi Srivatsavai 1216*4eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_ACTIVE) { 1217*4eaa4710SRishi Srivatsavai /* 1218*4eaa4710SRishi Srivatsavai * Delete ACTIVE linkprop now that daemon is gone. 1219*4eaa4710SRishi Srivatsavai */ 1220*4eaa4710SRishi Srivatsavai (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 1221*4eaa4710SRishi Srivatsavai DLADM_OPT_ACTIVE); 1222*4eaa4710SRishi Srivatsavai (void) dladm_destroy_datalink_id(handle, linkid, 1223*4eaa4710SRishi Srivatsavai DLADM_OPT_ACTIVE); 1224*4eaa4710SRishi Srivatsavai } 1225*4eaa4710SRishi Srivatsavai 1226*4eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_PERSIST) { 1227*4eaa4710SRishi Srivatsavai (void) dladm_remove_conf(handle, linkid); 1228*4eaa4710SRishi Srivatsavai (void) dladm_destroy_datalink_id(handle, linkid, 1229*4eaa4710SRishi Srivatsavai DLADM_OPT_PERSIST); 1230*4eaa4710SRishi Srivatsavai } 1231*4eaa4710SRishi Srivatsavai 1232*4eaa4710SRishi Srivatsavai out: 1233*4eaa4710SRishi Srivatsavai 1234*4eaa4710SRishi Srivatsavai return (status); 1235*4eaa4710SRishi Srivatsavai } 1236*4eaa4710SRishi Srivatsavai 1237*4eaa4710SRishi Srivatsavai /* Check if given name is valid for bridges */ 1238*4eaa4710SRishi Srivatsavai boolean_t 1239*4eaa4710SRishi Srivatsavai dladm_valid_bridgename(const char *bridge) 1240*4eaa4710SRishi Srivatsavai { 1241*4eaa4710SRishi Srivatsavai size_t len = strnlen(bridge, MAXLINKNAMELEN); 1242*4eaa4710SRishi Srivatsavai const char *cp; 1243*4eaa4710SRishi Srivatsavai 1244*4eaa4710SRishi Srivatsavai if (len == MAXLINKNAMELEN) 1245*4eaa4710SRishi Srivatsavai return (B_FALSE); 1246*4eaa4710SRishi Srivatsavai 1247*4eaa4710SRishi Srivatsavai /* 1248*4eaa4710SRishi Srivatsavai * The bridge name cannot start or end with a digit. 1249*4eaa4710SRishi Srivatsavai */ 1250*4eaa4710SRishi Srivatsavai if (isdigit(bridge[0]) || isdigit(bridge[len - 1])) 1251*4eaa4710SRishi Srivatsavai return (B_FALSE); 1252*4eaa4710SRishi Srivatsavai 1253*4eaa4710SRishi Srivatsavai /* 1254*4eaa4710SRishi Srivatsavai * The legal characters within a bridge name are: 1255*4eaa4710SRishi Srivatsavai * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 1256*4eaa4710SRishi Srivatsavai */ 1257*4eaa4710SRishi Srivatsavai for (cp = bridge; *cp != '\0'; cp++) { 1258*4eaa4710SRishi Srivatsavai if (!isalnum(*cp) && *cp != '_') 1259*4eaa4710SRishi Srivatsavai return (B_FALSE); 1260*4eaa4710SRishi Srivatsavai } 1261*4eaa4710SRishi Srivatsavai 1262*4eaa4710SRishi Srivatsavai return (B_TRUE); 1263*4eaa4710SRishi Srivatsavai } 1264*4eaa4710SRishi Srivatsavai 1265*4eaa4710SRishi Srivatsavai /* 1266*4eaa4710SRishi Srivatsavai * Convert a bridge-related observability node name back into the name of the 1267*4eaa4710SRishi Srivatsavai * bridge. Returns B_FALSE without making changes if the input name is not in 1268*4eaa4710SRishi Srivatsavai * a legal format. 1269*4eaa4710SRishi Srivatsavai */ 1270*4eaa4710SRishi Srivatsavai boolean_t 1271*4eaa4710SRishi Srivatsavai dladm_observe_to_bridge(char *link) 1272*4eaa4710SRishi Srivatsavai { 1273*4eaa4710SRishi Srivatsavai int llen; 1274*4eaa4710SRishi Srivatsavai 1275*4eaa4710SRishi Srivatsavai llen = strnlen(link, MAXLINKNAMELEN); 1276*4eaa4710SRishi Srivatsavai if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2])) 1277*4eaa4710SRishi Srivatsavai return (B_FALSE); 1278*4eaa4710SRishi Srivatsavai link[llen - 1] = '\0'; 1279*4eaa4710SRishi Srivatsavai return (B_TRUE); 1280*4eaa4710SRishi Srivatsavai } 1281*4eaa4710SRishi Srivatsavai 1282*4eaa4710SRishi Srivatsavai /* 1283*4eaa4710SRishi Srivatsavai * Get bridge property values from the running daemon and return them in a 1284*4eaa4710SRishi Srivatsavai * common structure. 1285*4eaa4710SRishi Srivatsavai */ 1286*4eaa4710SRishi Srivatsavai dladm_status_t 1287*4eaa4710SRishi Srivatsavai dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg, 1288*4eaa4710SRishi Srivatsavai dladm_bridge_prot_t *brprotp) 1289*4eaa4710SRishi Srivatsavai { 1290*4eaa4710SRishi Srivatsavai dladm_status_t status; 1291*4eaa4710SRishi Srivatsavai bridge_door_cfg_t bdcf; 1292*4eaa4710SRishi Srivatsavai bridge_door_cfg_t *bdcfp = &bdcf; 1293*4eaa4710SRishi Srivatsavai size_t buflen = sizeof (bdcf); 1294*4eaa4710SRishi Srivatsavai 1295*4eaa4710SRishi Srivatsavai status = bridge_door_call(instname, bdcBridgeGetConfig, 1296*4eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE); 1297*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 1298*4eaa4710SRishi Srivatsavai *smcfg = bdcfp->bdcf_cfg; 1299*4eaa4710SRishi Srivatsavai *brprotp = bdcfp->bdcf_prot; 1300*4eaa4710SRishi Srivatsavai } else { 1301*4eaa4710SRishi Srivatsavai smcfg->field_mask = 0; 1302*4eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_STP; 1303*4eaa4710SRishi Srivatsavai } 1304*4eaa4710SRishi Srivatsavai return (status); 1305*4eaa4710SRishi Srivatsavai } 1306*4eaa4710SRishi Srivatsavai 1307*4eaa4710SRishi Srivatsavai /* 1308*4eaa4710SRishi Srivatsavai * Get bridge state from the running daemon and return in structure borrowed 1309*4eaa4710SRishi Srivatsavai * from librstp. 1310*4eaa4710SRishi Srivatsavai */ 1311*4eaa4710SRishi Srivatsavai dladm_status_t 1312*4eaa4710SRishi Srivatsavai dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep) 1313*4eaa4710SRishi Srivatsavai { 1314*4eaa4710SRishi Srivatsavai size_t buflen = sizeof (*statep); 1315*4eaa4710SRishi Srivatsavai 1316*4eaa4710SRishi Srivatsavai return (bridge_door_call(instname, bdcBridgeGetState, 1317*4eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE)); 1318*4eaa4710SRishi Srivatsavai } 1319*4eaa4710SRishi Srivatsavai 1320*4eaa4710SRishi Srivatsavai /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */ 1321*4eaa4710SRishi Srivatsavai datalink_id_t * 1322*4eaa4710SRishi Srivatsavai dladm_bridge_get_portlist(const char *instname, uint_t *nports) 1323*4eaa4710SRishi Srivatsavai { 1324*4eaa4710SRishi Srivatsavai size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t); 1325*4eaa4710SRishi Srivatsavai int *rbuf; 1326*4eaa4710SRishi Srivatsavai 1327*4eaa4710SRishi Srivatsavai if ((rbuf = malloc(buflen)) == NULL) 1328*4eaa4710SRishi Srivatsavai return (NULL); 1329*4eaa4710SRishi Srivatsavai if (bridge_door_call(instname, bdcBridgeGetPorts, 1330*4eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) != 1331*4eaa4710SRishi Srivatsavai DLADM_STATUS_OK) { 1332*4eaa4710SRishi Srivatsavai free(rbuf); 1333*4eaa4710SRishi Srivatsavai return (NULL); 1334*4eaa4710SRishi Srivatsavai } else { 1335*4eaa4710SRishi Srivatsavai /* 1336*4eaa4710SRishi Srivatsavai * Returns an array of datalink_id_t values for all the ports 1337*4eaa4710SRishi Srivatsavai * part of the bridge instance. First entry in the array is the 1338*4eaa4710SRishi Srivatsavai * number of ports. 1339*4eaa4710SRishi Srivatsavai */ 1340*4eaa4710SRishi Srivatsavai *nports = *rbuf; 1341*4eaa4710SRishi Srivatsavai return ((datalink_id_t *)(rbuf + 1)); 1342*4eaa4710SRishi Srivatsavai } 1343*4eaa4710SRishi Srivatsavai } 1344*4eaa4710SRishi Srivatsavai 1345*4eaa4710SRishi Srivatsavai void 1346*4eaa4710SRishi Srivatsavai dladm_bridge_free_portlist(datalink_id_t *dlp) 1347*4eaa4710SRishi Srivatsavai { 1348*4eaa4710SRishi Srivatsavai free((int *)dlp - 1); 1349*4eaa4710SRishi Srivatsavai } 1350*4eaa4710SRishi Srivatsavai 1351*4eaa4710SRishi Srivatsavai /* Retrieve Bridge port configuration values */ 1352*4eaa4710SRishi Srivatsavai dladm_status_t 1353*4eaa4710SRishi Srivatsavai dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid, 1354*4eaa4710SRishi Srivatsavai int field, int *valuep) 1355*4eaa4710SRishi Srivatsavai { 1356*4eaa4710SRishi Srivatsavai UID_STP_PORT_CFG_T portcfg; 1357*4eaa4710SRishi Srivatsavai dladm_status_t status; 1358*4eaa4710SRishi Srivatsavai 1359*4eaa4710SRishi Srivatsavai status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg, 1360*4eaa4710SRishi Srivatsavai 0, sizeof (portcfg)); 1361*4eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 1362*4eaa4710SRishi Srivatsavai return (status); 1363*4eaa4710SRishi Srivatsavai 1364*4eaa4710SRishi Srivatsavai switch (field) { 1365*4eaa4710SRishi Srivatsavai case PT_CFG_COST: 1366*4eaa4710SRishi Srivatsavai *valuep = portcfg.admin_port_path_cost; 1367*4eaa4710SRishi Srivatsavai break; 1368*4eaa4710SRishi Srivatsavai case PT_CFG_PRIO: 1369*4eaa4710SRishi Srivatsavai *valuep = portcfg.port_priority; 1370*4eaa4710SRishi Srivatsavai break; 1371*4eaa4710SRishi Srivatsavai case PT_CFG_P2P: 1372*4eaa4710SRishi Srivatsavai *valuep = portcfg.admin_point2point; 1373*4eaa4710SRishi Srivatsavai break; 1374*4eaa4710SRishi Srivatsavai case PT_CFG_EDGE: 1375*4eaa4710SRishi Srivatsavai *valuep = portcfg.admin_edge; 1376*4eaa4710SRishi Srivatsavai break; 1377*4eaa4710SRishi Srivatsavai case PT_CFG_NON_STP: 1378*4eaa4710SRishi Srivatsavai *valuep = !portcfg.admin_non_stp; 1379*4eaa4710SRishi Srivatsavai break; 1380*4eaa4710SRishi Srivatsavai case PT_CFG_MCHECK: 1381*4eaa4710SRishi Srivatsavai *valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0; 1382*4eaa4710SRishi Srivatsavai break; 1383*4eaa4710SRishi Srivatsavai } 1384*4eaa4710SRishi Srivatsavai return (status); 1385*4eaa4710SRishi Srivatsavai } 1386*4eaa4710SRishi Srivatsavai 1387*4eaa4710SRishi Srivatsavai /* Retreive Bridge port status (disabled, bad SDU etc.) */ 1388*4eaa4710SRishi Srivatsavai dladm_status_t 1389*4eaa4710SRishi Srivatsavai dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid, 1390*4eaa4710SRishi Srivatsavai UID_STP_PORT_STATE_T *spsp) 1391*4eaa4710SRishi Srivatsavai { 1392*4eaa4710SRishi Srivatsavai return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0, 1393*4eaa4710SRishi Srivatsavai sizeof (*spsp))); 1394*4eaa4710SRishi Srivatsavai } 1395*4eaa4710SRishi Srivatsavai 1396*4eaa4710SRishi Srivatsavai /* Retrieve Bridge forwarding status of the given link */ 1397*4eaa4710SRishi Srivatsavai dladm_status_t 1398*4eaa4710SRishi Srivatsavai dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid, 1399*4eaa4710SRishi Srivatsavai uint_t *valuep) 1400*4eaa4710SRishi Srivatsavai { 1401*4eaa4710SRishi Srivatsavai int twoints[2]; 1402*4eaa4710SRishi Srivatsavai dladm_status_t status; 1403*4eaa4710SRishi Srivatsavai 1404*4eaa4710SRishi Srivatsavai status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints, 1405*4eaa4710SRishi Srivatsavai 0, sizeof (twoints)); 1406*4eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 1407*4eaa4710SRishi Srivatsavai *valuep = twoints[0]; 1408*4eaa4710SRishi Srivatsavai return (status); 1409*4eaa4710SRishi Srivatsavai } 1410*4eaa4710SRishi Srivatsavai 1411*4eaa4710SRishi Srivatsavai /* Retrieve Bridge forwarding table entries */ 1412*4eaa4710SRishi Srivatsavai bridge_listfwd_t * 1413*4eaa4710SRishi Srivatsavai dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge, 1414*4eaa4710SRishi Srivatsavai uint_t *nfwd) 1415*4eaa4710SRishi Srivatsavai { 1416*4eaa4710SRishi Srivatsavai bridge_listfwd_t *blf = NULL, *newblf, blfread; 1417*4eaa4710SRishi Srivatsavai uint_t nblf = 0, maxblf = 0; 1418*4eaa4710SRishi Srivatsavai static uint8_t zero_addr[ETHERADDRL]; 1419*4eaa4710SRishi Srivatsavai int rc; 1420*4eaa4710SRishi Srivatsavai 1421*4eaa4710SRishi Srivatsavai (void) memset(&blfread, 0, sizeof (blfread)); 1422*4eaa4710SRishi Srivatsavai (void) snprintf(blfread.blf_name, sizeof (blfread.blf_name), 1423*4eaa4710SRishi Srivatsavai "%s0", bridge); 1424*4eaa4710SRishi Srivatsavai for (;;) { 1425*4eaa4710SRishi Srivatsavai if (nblf >= maxblf) { 1426*4eaa4710SRishi Srivatsavai maxblf = maxblf == 0 ? 64 : (maxblf << 1); 1427*4eaa4710SRishi Srivatsavai newblf = realloc(blf, maxblf * sizeof (*blf)); 1428*4eaa4710SRishi Srivatsavai if (newblf == NULL) { 1429*4eaa4710SRishi Srivatsavai free(blf); 1430*4eaa4710SRishi Srivatsavai blf = NULL; 1431*4eaa4710SRishi Srivatsavai break; 1432*4eaa4710SRishi Srivatsavai } 1433*4eaa4710SRishi Srivatsavai blf = newblf; 1434*4eaa4710SRishi Srivatsavai } 1435*4eaa4710SRishi Srivatsavai rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread); 1436*4eaa4710SRishi Srivatsavai if (rc != 0) { 1437*4eaa4710SRishi Srivatsavai free(blf); 1438*4eaa4710SRishi Srivatsavai blf = NULL; 1439*4eaa4710SRishi Srivatsavai break; 1440*4eaa4710SRishi Srivatsavai } 1441*4eaa4710SRishi Srivatsavai if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0) 1442*4eaa4710SRishi Srivatsavai break; 1443*4eaa4710SRishi Srivatsavai blf[nblf++] = blfread; 1444*4eaa4710SRishi Srivatsavai } 1445*4eaa4710SRishi Srivatsavai if (blf != NULL) 1446*4eaa4710SRishi Srivatsavai *nfwd = nblf; 1447*4eaa4710SRishi Srivatsavai return (blf); 1448*4eaa4710SRishi Srivatsavai } 1449*4eaa4710SRishi Srivatsavai 1450*4eaa4710SRishi Srivatsavai void 1451*4eaa4710SRishi Srivatsavai dladm_bridge_free_fwdtable(bridge_listfwd_t *blf) 1452*4eaa4710SRishi Srivatsavai { 1453*4eaa4710SRishi Srivatsavai free(blf); 1454*4eaa4710SRishi Srivatsavai } 1455*4eaa4710SRishi Srivatsavai 1456*4eaa4710SRishi Srivatsavai /* Retrieve list of TRILL nicknames from the TRILL module */ 1457*4eaa4710SRishi Srivatsavai trill_listnick_t * 1458*4eaa4710SRishi Srivatsavai dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick) 1459*4eaa4710SRishi Srivatsavai { 1460*4eaa4710SRishi Srivatsavai int fd; 1461*4eaa4710SRishi Srivatsavai char brcopy[MAXLINKNAMELEN]; 1462*4eaa4710SRishi Srivatsavai trill_listnick_t *tln = NULL, *newtln, tlnread; 1463*4eaa4710SRishi Srivatsavai uint_t ntln = 0, maxtln = 0; 1464*4eaa4710SRishi Srivatsavai 1465*4eaa4710SRishi Srivatsavai if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1) 1466*4eaa4710SRishi Srivatsavai return (NULL); 1467*4eaa4710SRishi Srivatsavai (void) strlcpy(brcopy, bridge, sizeof (brcopy)); 1468*4eaa4710SRishi Srivatsavai if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) { 1469*4eaa4710SRishi Srivatsavai (void) close(fd); 1470*4eaa4710SRishi Srivatsavai return (NULL); 1471*4eaa4710SRishi Srivatsavai } 1472*4eaa4710SRishi Srivatsavai (void) memset(&tlnread, 0, sizeof (tlnread)); 1473*4eaa4710SRishi Srivatsavai for (;;) { 1474*4eaa4710SRishi Srivatsavai if (ntln >= maxtln) { 1475*4eaa4710SRishi Srivatsavai maxtln = maxtln == 0 ? 64 : (maxtln << 1); 1476*4eaa4710SRishi Srivatsavai newtln = realloc(tln, maxtln * sizeof (*tln)); 1477*4eaa4710SRishi Srivatsavai if (newtln == NULL) { 1478*4eaa4710SRishi Srivatsavai free(tln); 1479*4eaa4710SRishi Srivatsavai tln = NULL; 1480*4eaa4710SRishi Srivatsavai break; 1481*4eaa4710SRishi Srivatsavai } 1482*4eaa4710SRishi Srivatsavai tln = newtln; 1483*4eaa4710SRishi Srivatsavai } 1484*4eaa4710SRishi Srivatsavai if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) { 1485*4eaa4710SRishi Srivatsavai free(tln); 1486*4eaa4710SRishi Srivatsavai tln = NULL; 1487*4eaa4710SRishi Srivatsavai break; 1488*4eaa4710SRishi Srivatsavai } 1489*4eaa4710SRishi Srivatsavai if (tlnread.tln_nick == 0) 1490*4eaa4710SRishi Srivatsavai break; 1491*4eaa4710SRishi Srivatsavai tln[ntln++] = tlnread; 1492*4eaa4710SRishi Srivatsavai } 1493*4eaa4710SRishi Srivatsavai (void) close(fd); 1494*4eaa4710SRishi Srivatsavai if (tln != NULL) 1495*4eaa4710SRishi Srivatsavai *nnick = ntln; 1496*4eaa4710SRishi Srivatsavai return (tln); 1497*4eaa4710SRishi Srivatsavai } 1498*4eaa4710SRishi Srivatsavai 1499*4eaa4710SRishi Srivatsavai void 1500*4eaa4710SRishi Srivatsavai dladm_bridge_free_trillnick(trill_listnick_t *tln) 1501*4eaa4710SRishi Srivatsavai { 1502*4eaa4710SRishi Srivatsavai free(tln); 1503*4eaa4710SRishi Srivatsavai } 1504*4eaa4710SRishi Srivatsavai 1505*4eaa4710SRishi Srivatsavai /* Retrieve any stored TRILL nickname from TRILL SMF service */ 1506*4eaa4710SRishi Srivatsavai uint16_t 1507*4eaa4710SRishi Srivatsavai dladm_bridge_get_nick(const char *bridge) 1508*4eaa4710SRishi Srivatsavai { 1509*4eaa4710SRishi Srivatsavai scf_state_t sstate; 1510*4eaa4710SRishi Srivatsavai uint64_t value; 1511*4eaa4710SRishi Srivatsavai uint16_t nickname = RBRIDGE_NICKNAME_NONE; 1512*4eaa4710SRishi Srivatsavai 1513*4eaa4710SRishi Srivatsavai if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0) 1514*4eaa4710SRishi Srivatsavai return (nickname); 1515*4eaa4710SRishi Srivatsavai 1516*4eaa4710SRishi Srivatsavai if (get_composed_properties("config", B_TRUE, &sstate) == 0 && 1517*4eaa4710SRishi Srivatsavai get_count("nickname", &sstate, &value) == 0) 1518*4eaa4710SRishi Srivatsavai nickname = value; 1519*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 1520*4eaa4710SRishi Srivatsavai return (nickname); 1521*4eaa4710SRishi Srivatsavai } 1522*4eaa4710SRishi Srivatsavai 1523*4eaa4710SRishi Srivatsavai /* Stores TRILL nickname in SMF configuraiton for the TRILL service */ 1524*4eaa4710SRishi Srivatsavai void 1525*4eaa4710SRishi Srivatsavai dladm_bridge_set_nick(const char *bridge, uint16_t nick) 1526*4eaa4710SRishi Srivatsavai { 1527*4eaa4710SRishi Srivatsavai scf_state_t sstate; 1528*4eaa4710SRishi Srivatsavai scf_transaction_t *tran = NULL; 1529*4eaa4710SRishi Srivatsavai boolean_t new_pg = B_FALSE; 1530*4eaa4710SRishi Srivatsavai int rv = 0; 1531*4eaa4710SRishi Srivatsavai char *fmri; 1532*4eaa4710SRishi Srivatsavai 1533*4eaa4710SRishi Srivatsavai if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK) 1534*4eaa4710SRishi Srivatsavai return; 1535*4eaa4710SRishi Srivatsavai 1536*4eaa4710SRishi Srivatsavai if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) != 1537*4eaa4710SRishi Srivatsavai 0) 1538*4eaa4710SRishi Srivatsavai goto out; 1539*4eaa4710SRishi Srivatsavai if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 1540*4eaa4710SRishi Srivatsavai goto out; 1541*4eaa4710SRishi Srivatsavai if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 1542*4eaa4710SRishi Srivatsavai goto out; 1543*4eaa4710SRishi Srivatsavai if (scf_instance_add_pg(sstate.ss_inst, "config", 1544*4eaa4710SRishi Srivatsavai SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 1545*4eaa4710SRishi Srivatsavai new_pg = B_TRUE; 1546*4eaa4710SRishi Srivatsavai } else if (scf_instance_get_pg(sstate.ss_inst, "config", 1547*4eaa4710SRishi Srivatsavai sstate.ss_pg) != 0) { 1548*4eaa4710SRishi Srivatsavai goto out; 1549*4eaa4710SRishi Srivatsavai } 1550*4eaa4710SRishi Srivatsavai do { 1551*4eaa4710SRishi Srivatsavai if (scf_transaction_start(tran, sstate.ss_pg) != 0) 1552*4eaa4710SRishi Srivatsavai goto out; 1553*4eaa4710SRishi Srivatsavai if (!set_count_property(sstate.ss_handle, tran, "nickname", 1554*4eaa4710SRishi Srivatsavai nick)) 1555*4eaa4710SRishi Srivatsavai goto out; 1556*4eaa4710SRishi Srivatsavai rv = scf_transaction_commit(tran); 1557*4eaa4710SRishi Srivatsavai scf_transaction_reset(tran); 1558*4eaa4710SRishi Srivatsavai if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 1559*4eaa4710SRishi Srivatsavai goto out; 1560*4eaa4710SRishi Srivatsavai } while (rv == 0); 1561*4eaa4710SRishi Srivatsavai 1562*4eaa4710SRishi Srivatsavai out: 1563*4eaa4710SRishi Srivatsavai if (tran != NULL) { 1564*4eaa4710SRishi Srivatsavai scf_transaction_destroy_children(tran); 1565*4eaa4710SRishi Srivatsavai scf_transaction_destroy(tran); 1566*4eaa4710SRishi Srivatsavai } 1567*4eaa4710SRishi Srivatsavai 1568*4eaa4710SRishi Srivatsavai if (rv != 1 && new_pg) 1569*4eaa4710SRishi Srivatsavai (void) scf_pg_delete(sstate.ss_pg); 1570*4eaa4710SRishi Srivatsavai 1571*4eaa4710SRishi Srivatsavai drop_composed(&sstate); 1572*4eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 1573*4eaa4710SRishi Srivatsavai if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) { 1574*4eaa4710SRishi Srivatsavai (void) smf_refresh_instance(fmri); 1575*4eaa4710SRishi Srivatsavai free(fmri); 1576*4eaa4710SRishi Srivatsavai } 1577*4eaa4710SRishi Srivatsavai } 1578