110491SRishi.Srivatsavai@Sun.COM /* 210491SRishi.Srivatsavai@Sun.COM * CDDL HEADER START 310491SRishi.Srivatsavai@Sun.COM * 410491SRishi.Srivatsavai@Sun.COM * The contents of this file are subject to the terms of the 510491SRishi.Srivatsavai@Sun.COM * Common Development and Distribution License (the "License"). 610491SRishi.Srivatsavai@Sun.COM * You may not use this file except in compliance with the License. 710491SRishi.Srivatsavai@Sun.COM * 810491SRishi.Srivatsavai@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910491SRishi.Srivatsavai@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010491SRishi.Srivatsavai@Sun.COM * See the License for the specific language governing permissions 1110491SRishi.Srivatsavai@Sun.COM * and limitations under the License. 1210491SRishi.Srivatsavai@Sun.COM * 1310491SRishi.Srivatsavai@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410491SRishi.Srivatsavai@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510491SRishi.Srivatsavai@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610491SRishi.Srivatsavai@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710491SRishi.Srivatsavai@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810491SRishi.Srivatsavai@Sun.COM * 1910491SRishi.Srivatsavai@Sun.COM * CDDL HEADER END 2010491SRishi.Srivatsavai@Sun.COM */ 2110491SRishi.Srivatsavai@Sun.COM /* 2210491SRishi.Srivatsavai@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2310491SRishi.Srivatsavai@Sun.COM * Use is subject to license terms. 2410491SRishi.Srivatsavai@Sun.COM */ 2510491SRishi.Srivatsavai@Sun.COM 2610491SRishi.Srivatsavai@Sun.COM #include <stdio.h> 2710491SRishi.Srivatsavai@Sun.COM #include <sys/types.h> 2810491SRishi.Srivatsavai@Sun.COM #include <string.h> 2910491SRishi.Srivatsavai@Sun.COM #include <fcntl.h> 3010491SRishi.Srivatsavai@Sun.COM #include <unistd.h> 3110491SRishi.Srivatsavai@Sun.COM #include <stropts.h> 3210491SRishi.Srivatsavai@Sun.COM #include <ctype.h> 3310491SRishi.Srivatsavai@Sun.COM #include <errno.h> 3410491SRishi.Srivatsavai@Sun.COM #include <stdlib.h> 3510491SRishi.Srivatsavai@Sun.COM #include <door.h> 3610491SRishi.Srivatsavai@Sun.COM #include <sys/mman.h> 3710491SRishi.Srivatsavai@Sun.COM #include <libscf.h> 3810491SRishi.Srivatsavai@Sun.COM #include <libscf_priv.h> 3910491SRishi.Srivatsavai@Sun.COM #include <libdllink.h> 4010491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h> 4110491SRishi.Srivatsavai@Sun.COM #include <libdladm_impl.h> 4210491SRishi.Srivatsavai@Sun.COM #include <stp_in.h> 4310491SRishi.Srivatsavai@Sun.COM #include <net/bridge.h> 4410491SRishi.Srivatsavai@Sun.COM #include <net/trill.h> 4510491SRishi.Srivatsavai@Sun.COM #include <sys/socket.h> 46*10530SRishi.Srivatsavai@Sun.COM #include <sys/dld_ioc.h> 4710491SRishi.Srivatsavai@Sun.COM 4810491SRishi.Srivatsavai@Sun.COM /* 4910491SRishi.Srivatsavai@Sun.COM * Bridge Administration Library. 5010491SRishi.Srivatsavai@Sun.COM * 5110491SRishi.Srivatsavai@Sun.COM * This library is used by administration tools such as dladm(1M) to configure 5210491SRishi.Srivatsavai@Sun.COM * bridges, and by the bridge daemon to retrieve configuration information. 5310491SRishi.Srivatsavai@Sun.COM */ 5410491SRishi.Srivatsavai@Sun.COM 5510491SRishi.Srivatsavai@Sun.COM #define BRIDGE_SVC_NAME "network/bridge" 5610491SRishi.Srivatsavai@Sun.COM #define TRILL_SVC_NAME "network/routing/trill" 5710491SRishi.Srivatsavai@Sun.COM 5810491SRishi.Srivatsavai@Sun.COM #define DEFAULT_TIMEOUT 60000000 5910491SRishi.Srivatsavai@Sun.COM #define INIT_WAIT_USECS 50000 6010491SRishi.Srivatsavai@Sun.COM #define MAXPORTS 256 6110491SRishi.Srivatsavai@Sun.COM 6210491SRishi.Srivatsavai@Sun.COM typedef struct scf_state { 6310491SRishi.Srivatsavai@Sun.COM scf_handle_t *ss_handle; 6410491SRishi.Srivatsavai@Sun.COM scf_instance_t *ss_inst; 6510491SRishi.Srivatsavai@Sun.COM scf_service_t *ss_svc; 6610491SRishi.Srivatsavai@Sun.COM scf_snapshot_t *ss_snap; 6710491SRishi.Srivatsavai@Sun.COM scf_propertygroup_t *ss_pg; 6810491SRishi.Srivatsavai@Sun.COM scf_property_t *ss_prop; 6910491SRishi.Srivatsavai@Sun.COM } scf_state_t; 7010491SRishi.Srivatsavai@Sun.COM 7110491SRishi.Srivatsavai@Sun.COM static void 7210491SRishi.Srivatsavai@Sun.COM shut_down_scf(scf_state_t *sstate) 7310491SRishi.Srivatsavai@Sun.COM { 7410491SRishi.Srivatsavai@Sun.COM scf_instance_destroy(sstate->ss_inst); 7510491SRishi.Srivatsavai@Sun.COM (void) scf_handle_unbind(sstate->ss_handle); 7610491SRishi.Srivatsavai@Sun.COM scf_handle_destroy(sstate->ss_handle); 7710491SRishi.Srivatsavai@Sun.COM } 7810491SRishi.Srivatsavai@Sun.COM 7910491SRishi.Srivatsavai@Sun.COM static char * 8010491SRishi.Srivatsavai@Sun.COM alloc_fmri(const char *service, const char *instance_name) 8110491SRishi.Srivatsavai@Sun.COM { 8210491SRishi.Srivatsavai@Sun.COM ssize_t max_fmri; 8310491SRishi.Srivatsavai@Sun.COM char *fmri; 8410491SRishi.Srivatsavai@Sun.COM 8510491SRishi.Srivatsavai@Sun.COM /* If the limit is unknown, then use an arbitrary value */ 8610491SRishi.Srivatsavai@Sun.COM if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1) 8710491SRishi.Srivatsavai@Sun.COM max_fmri = 1024; 8810491SRishi.Srivatsavai@Sun.COM if ((fmri = malloc(max_fmri)) != NULL) { 8910491SRishi.Srivatsavai@Sun.COM (void) snprintf(fmri, max_fmri, "svc:/%s:%s", service, 9010491SRishi.Srivatsavai@Sun.COM instance_name); 9110491SRishi.Srivatsavai@Sun.COM } 9210491SRishi.Srivatsavai@Sun.COM return (fmri); 9310491SRishi.Srivatsavai@Sun.COM } 9410491SRishi.Srivatsavai@Sun.COM 9510491SRishi.Srivatsavai@Sun.COM /* 9610491SRishi.Srivatsavai@Sun.COM * Start up SCF and bind the requested instance alone. 9710491SRishi.Srivatsavai@Sun.COM */ 9810491SRishi.Srivatsavai@Sun.COM static int 9910491SRishi.Srivatsavai@Sun.COM bind_instance(const char *service, const char *instance_name, 10010491SRishi.Srivatsavai@Sun.COM scf_state_t *sstate) 10110491SRishi.Srivatsavai@Sun.COM { 10210491SRishi.Srivatsavai@Sun.COM char *fmri = NULL; 10310491SRishi.Srivatsavai@Sun.COM 10410491SRishi.Srivatsavai@Sun.COM (void) memset(sstate, 0, sizeof (*sstate)); 10510491SRishi.Srivatsavai@Sun.COM 10610491SRishi.Srivatsavai@Sun.COM if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 10710491SRishi.Srivatsavai@Sun.COM return (-1); 10810491SRishi.Srivatsavai@Sun.COM 10910491SRishi.Srivatsavai@Sun.COM if (scf_handle_bind(sstate->ss_handle) != 0) 11010491SRishi.Srivatsavai@Sun.COM goto failure; 11110491SRishi.Srivatsavai@Sun.COM sstate->ss_inst = scf_instance_create(sstate->ss_handle); 11210491SRishi.Srivatsavai@Sun.COM if (sstate->ss_inst == NULL) 11310491SRishi.Srivatsavai@Sun.COM goto failure; 11410491SRishi.Srivatsavai@Sun.COM 11510491SRishi.Srivatsavai@Sun.COM fmri = alloc_fmri(service, instance_name); 11610491SRishi.Srivatsavai@Sun.COM 11710491SRishi.Srivatsavai@Sun.COM if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL, 11810491SRishi.Srivatsavai@Sun.COM sstate->ss_inst, NULL, NULL, 11910491SRishi.Srivatsavai@Sun.COM SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) 12010491SRishi.Srivatsavai@Sun.COM goto failure; 12110491SRishi.Srivatsavai@Sun.COM free(fmri); 12210491SRishi.Srivatsavai@Sun.COM return (0); 12310491SRishi.Srivatsavai@Sun.COM 12410491SRishi.Srivatsavai@Sun.COM failure: 12510491SRishi.Srivatsavai@Sun.COM free(fmri); 12610491SRishi.Srivatsavai@Sun.COM shut_down_scf(sstate); 12710491SRishi.Srivatsavai@Sun.COM return (-1); 12810491SRishi.Srivatsavai@Sun.COM } 12910491SRishi.Srivatsavai@Sun.COM 13010491SRishi.Srivatsavai@Sun.COM /* 13110491SRishi.Srivatsavai@Sun.COM * Start up SCF and an exact FMRI. This is used for creating new instances and 13210491SRishi.Srivatsavai@Sun.COM * enable/disable actions. 13310491SRishi.Srivatsavai@Sun.COM */ 13410491SRishi.Srivatsavai@Sun.COM static dladm_status_t 13510491SRishi.Srivatsavai@Sun.COM exact_instance(const char *fmri, scf_state_t *sstate) 13610491SRishi.Srivatsavai@Sun.COM { 13710491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 13810491SRishi.Srivatsavai@Sun.COM 13910491SRishi.Srivatsavai@Sun.COM (void) memset(sstate, 0, sizeof (*sstate)); 14010491SRishi.Srivatsavai@Sun.COM 14110491SRishi.Srivatsavai@Sun.COM if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 14210491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_NOMEM); 14310491SRishi.Srivatsavai@Sun.COM 14410491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_FAILED; 14510491SRishi.Srivatsavai@Sun.COM if (scf_handle_bind(sstate->ss_handle) != 0) 14610491SRishi.Srivatsavai@Sun.COM goto failure; 14710491SRishi.Srivatsavai@Sun.COM sstate->ss_svc = scf_service_create(sstate->ss_handle); 14810491SRishi.Srivatsavai@Sun.COM if (sstate->ss_svc == NULL) 14910491SRishi.Srivatsavai@Sun.COM goto failure; 15010491SRishi.Srivatsavai@Sun.COM if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, 15110491SRishi.Srivatsavai@Sun.COM sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 15210491SRishi.Srivatsavai@Sun.COM if (scf_error() == SCF_ERROR_NOT_FOUND) 15310491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_OPTMISSING; 15410491SRishi.Srivatsavai@Sun.COM goto failure; 15510491SRishi.Srivatsavai@Sun.COM } 15610491SRishi.Srivatsavai@Sun.COM sstate->ss_inst = scf_instance_create(sstate->ss_handle); 15710491SRishi.Srivatsavai@Sun.COM if (sstate->ss_inst == NULL) 15810491SRishi.Srivatsavai@Sun.COM goto failure; 15910491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 16010491SRishi.Srivatsavai@Sun.COM 16110491SRishi.Srivatsavai@Sun.COM failure: 16210491SRishi.Srivatsavai@Sun.COM shut_down_scf(sstate); 16310491SRishi.Srivatsavai@Sun.COM return (status); 16410491SRishi.Srivatsavai@Sun.COM } 16510491SRishi.Srivatsavai@Sun.COM 16610491SRishi.Srivatsavai@Sun.COM static void 16710491SRishi.Srivatsavai@Sun.COM drop_composed(scf_state_t *sstate) 16810491SRishi.Srivatsavai@Sun.COM { 16910491SRishi.Srivatsavai@Sun.COM scf_property_destroy(sstate->ss_prop); 17010491SRishi.Srivatsavai@Sun.COM scf_pg_destroy(sstate->ss_pg); 17110491SRishi.Srivatsavai@Sun.COM scf_snapshot_destroy(sstate->ss_snap); 17210491SRishi.Srivatsavai@Sun.COM } 17310491SRishi.Srivatsavai@Sun.COM 17410491SRishi.Srivatsavai@Sun.COM /* 17510491SRishi.Srivatsavai@Sun.COM * This function sets up a composed view of the configuration information for 17610491SRishi.Srivatsavai@Sun.COM * the specified instance. When this is done, the get_property() function 17710491SRishi.Srivatsavai@Sun.COM * should be able to return individual parameters. 17810491SRishi.Srivatsavai@Sun.COM */ 17910491SRishi.Srivatsavai@Sun.COM static int 18010491SRishi.Srivatsavai@Sun.COM get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate) 18110491SRishi.Srivatsavai@Sun.COM { 18210491SRishi.Srivatsavai@Sun.COM sstate->ss_snap = NULL; 18310491SRishi.Srivatsavai@Sun.COM sstate->ss_pg = NULL; 18410491SRishi.Srivatsavai@Sun.COM sstate->ss_prop = NULL; 18510491SRishi.Srivatsavai@Sun.COM 18610491SRishi.Srivatsavai@Sun.COM if (snap) { 18710491SRishi.Srivatsavai@Sun.COM sstate->ss_snap = scf_snapshot_create(sstate->ss_handle); 18810491SRishi.Srivatsavai@Sun.COM if (sstate->ss_snap == NULL) 18910491SRishi.Srivatsavai@Sun.COM goto failure; 19010491SRishi.Srivatsavai@Sun.COM if (scf_instance_get_snapshot(sstate->ss_inst, "running", 19110491SRishi.Srivatsavai@Sun.COM sstate->ss_snap) != 0) 19210491SRishi.Srivatsavai@Sun.COM goto failure; 19310491SRishi.Srivatsavai@Sun.COM } 19410491SRishi.Srivatsavai@Sun.COM if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL) 19510491SRishi.Srivatsavai@Sun.COM goto failure; 19610491SRishi.Srivatsavai@Sun.COM if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg, 19710491SRishi.Srivatsavai@Sun.COM sstate->ss_pg) != 0) 19810491SRishi.Srivatsavai@Sun.COM goto failure; 19910491SRishi.Srivatsavai@Sun.COM if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) == 20010491SRishi.Srivatsavai@Sun.COM NULL) 20110491SRishi.Srivatsavai@Sun.COM goto failure; 20210491SRishi.Srivatsavai@Sun.COM return (0); 20310491SRishi.Srivatsavai@Sun.COM 20410491SRishi.Srivatsavai@Sun.COM failure: 20510491SRishi.Srivatsavai@Sun.COM drop_composed(sstate); 20610491SRishi.Srivatsavai@Sun.COM return (-1); 20710491SRishi.Srivatsavai@Sun.COM } 20810491SRishi.Srivatsavai@Sun.COM 20910491SRishi.Srivatsavai@Sun.COM static int 21010491SRishi.Srivatsavai@Sun.COM get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer) 21110491SRishi.Srivatsavai@Sun.COM { 21210491SRishi.Srivatsavai@Sun.COM scf_value_t *val; 21310491SRishi.Srivatsavai@Sun.COM int retv; 21410491SRishi.Srivatsavai@Sun.COM 21510491SRishi.Srivatsavai@Sun.COM if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 21610491SRishi.Srivatsavai@Sun.COM return (-1); 21710491SRishi.Srivatsavai@Sun.COM if ((val = scf_value_create(sstate->ss_handle)) == NULL) 21810491SRishi.Srivatsavai@Sun.COM return (-1); 21910491SRishi.Srivatsavai@Sun.COM 22010491SRishi.Srivatsavai@Sun.COM if (scf_property_get_value(sstate->ss_prop, val) == 0 && 22110491SRishi.Srivatsavai@Sun.COM scf_value_get_count(val, answer) == 0) 22210491SRishi.Srivatsavai@Sun.COM retv = 0; 22310491SRishi.Srivatsavai@Sun.COM else 22410491SRishi.Srivatsavai@Sun.COM retv = -1; 22510491SRishi.Srivatsavai@Sun.COM scf_value_destroy(val); 22610491SRishi.Srivatsavai@Sun.COM return (retv); 22710491SRishi.Srivatsavai@Sun.COM } 22810491SRishi.Srivatsavai@Sun.COM 22910491SRishi.Srivatsavai@Sun.COM static int 23010491SRishi.Srivatsavai@Sun.COM get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer) 23110491SRishi.Srivatsavai@Sun.COM { 23210491SRishi.Srivatsavai@Sun.COM scf_value_t *val; 23310491SRishi.Srivatsavai@Sun.COM int retv; 23410491SRishi.Srivatsavai@Sun.COM uint8_t bval; 23510491SRishi.Srivatsavai@Sun.COM 23610491SRishi.Srivatsavai@Sun.COM if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 23710491SRishi.Srivatsavai@Sun.COM return (-1); 23810491SRishi.Srivatsavai@Sun.COM if ((val = scf_value_create(sstate->ss_handle)) == NULL) 23910491SRishi.Srivatsavai@Sun.COM return (-1); 24010491SRishi.Srivatsavai@Sun.COM 24110491SRishi.Srivatsavai@Sun.COM if (scf_property_get_value(sstate->ss_prop, val) == 0 && 24210491SRishi.Srivatsavai@Sun.COM scf_value_get_boolean(val, &bval) == 0) { 24310491SRishi.Srivatsavai@Sun.COM retv = 0; 24410491SRishi.Srivatsavai@Sun.COM *answer = bval != 0; 24510491SRishi.Srivatsavai@Sun.COM } else { 24610491SRishi.Srivatsavai@Sun.COM retv = -1; 24710491SRishi.Srivatsavai@Sun.COM } 24810491SRishi.Srivatsavai@Sun.COM scf_value_destroy(val); 24910491SRishi.Srivatsavai@Sun.COM return (retv); 25010491SRishi.Srivatsavai@Sun.COM } 25110491SRishi.Srivatsavai@Sun.COM 25210491SRishi.Srivatsavai@Sun.COM static dladm_status_t 25310491SRishi.Srivatsavai@Sun.COM bridge_door_call(const char *instname, bridge_door_type_t dtype, 25410491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp, 25510491SRishi.Srivatsavai@Sun.COM boolean_t is_list) 25610491SRishi.Srivatsavai@Sun.COM { 25710491SRishi.Srivatsavai@Sun.COM char doorname[MAXPATHLEN]; 25810491SRishi.Srivatsavai@Sun.COM int did, retv, etmp; 25910491SRishi.Srivatsavai@Sun.COM bridge_door_cmd_t *bdc; 26010491SRishi.Srivatsavai@Sun.COM door_arg_t arg; 26110491SRishi.Srivatsavai@Sun.COM 26210491SRishi.Srivatsavai@Sun.COM (void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME, 26310491SRishi.Srivatsavai@Sun.COM instname); 26410491SRishi.Srivatsavai@Sun.COM 26510491SRishi.Srivatsavai@Sun.COM /* Knock on the door */ 26610491SRishi.Srivatsavai@Sun.COM did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK); 26710491SRishi.Srivatsavai@Sun.COM if (did == -1) 26810491SRishi.Srivatsavai@Sun.COM return (dladm_errno2status(errno)); 26910491SRishi.Srivatsavai@Sun.COM 27010491SRishi.Srivatsavai@Sun.COM if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) { 27110491SRishi.Srivatsavai@Sun.COM (void) close(did); 27210491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_NOMEM); 27310491SRishi.Srivatsavai@Sun.COM } 27410491SRishi.Srivatsavai@Sun.COM bdc->bdc_type = dtype; 27510491SRishi.Srivatsavai@Sun.COM bdc->bdc_linkid = linkid; 27610491SRishi.Srivatsavai@Sun.COM if (inlen != 0) 27710491SRishi.Srivatsavai@Sun.COM (void) memcpy(bdc + 1, *bufp, inlen); 27810491SRishi.Srivatsavai@Sun.COM 27910491SRishi.Srivatsavai@Sun.COM (void) memset(&arg, 0, sizeof (arg)); 28010491SRishi.Srivatsavai@Sun.COM arg.data_ptr = (char *)bdc; 28110491SRishi.Srivatsavai@Sun.COM arg.data_size = sizeof (*bdc) + inlen; 28210491SRishi.Srivatsavai@Sun.COM arg.rbuf = *bufp; 28310491SRishi.Srivatsavai@Sun.COM arg.rsize = *buflenp; 28410491SRishi.Srivatsavai@Sun.COM 28510491SRishi.Srivatsavai@Sun.COM /* The door_call function doesn't restart, so take care of that */ 28610491SRishi.Srivatsavai@Sun.COM do { 28710491SRishi.Srivatsavai@Sun.COM errno = 0; 28810491SRishi.Srivatsavai@Sun.COM if ((retv = door_call(did, &arg)) == 0) 28910491SRishi.Srivatsavai@Sun.COM break; 29010491SRishi.Srivatsavai@Sun.COM } while (errno == EINTR); 29110491SRishi.Srivatsavai@Sun.COM 29210491SRishi.Srivatsavai@Sun.COM /* If we get an unexpected response, then return an error */ 29310491SRishi.Srivatsavai@Sun.COM if (retv == 0) { 29410491SRishi.Srivatsavai@Sun.COM /* The daemon returns a single int for errors */ 29510491SRishi.Srivatsavai@Sun.COM /* LINTED: pointer alignment */ 29610491SRishi.Srivatsavai@Sun.COM if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) { 29710491SRishi.Srivatsavai@Sun.COM retv = -1; 29810491SRishi.Srivatsavai@Sun.COM /* LINTED: pointer alignment */ 29910491SRishi.Srivatsavai@Sun.COM errno = *(int *)arg.rbuf; 30010491SRishi.Srivatsavai@Sun.COM } 30110491SRishi.Srivatsavai@Sun.COM /* Terminated daemon returns with zero data */ 30210491SRishi.Srivatsavai@Sun.COM if (arg.data_size == 0) { 30310491SRishi.Srivatsavai@Sun.COM retv = -1; 30410491SRishi.Srivatsavai@Sun.COM errno = EBADF; 30510491SRishi.Srivatsavai@Sun.COM } 30610491SRishi.Srivatsavai@Sun.COM } 30710491SRishi.Srivatsavai@Sun.COM 30810491SRishi.Srivatsavai@Sun.COM if (retv == 0) { 30910491SRishi.Srivatsavai@Sun.COM if (arg.rbuf != *bufp) { 31010491SRishi.Srivatsavai@Sun.COM if (is_list) { 31110491SRishi.Srivatsavai@Sun.COM void *newp; 31210491SRishi.Srivatsavai@Sun.COM 31310491SRishi.Srivatsavai@Sun.COM newp = realloc(*bufp, arg.data_size); 31410491SRishi.Srivatsavai@Sun.COM if (newp == NULL) { 31510491SRishi.Srivatsavai@Sun.COM retv = -1; 31610491SRishi.Srivatsavai@Sun.COM } else { 31710491SRishi.Srivatsavai@Sun.COM *bufp = newp; 31810491SRishi.Srivatsavai@Sun.COM (void) memcpy(*bufp, arg.rbuf, 31910491SRishi.Srivatsavai@Sun.COM arg.data_size); 32010491SRishi.Srivatsavai@Sun.COM } 32110491SRishi.Srivatsavai@Sun.COM } 32210491SRishi.Srivatsavai@Sun.COM (void) munmap(arg.rbuf, arg.rsize); 32310491SRishi.Srivatsavai@Sun.COM } 32410491SRishi.Srivatsavai@Sun.COM if (is_list) { 32510491SRishi.Srivatsavai@Sun.COM *buflenp = arg.data_size; 32610491SRishi.Srivatsavai@Sun.COM } else if (arg.data_size != *buflenp || arg.rbuf != *bufp) { 32710491SRishi.Srivatsavai@Sun.COM errno = EINVAL; 32810491SRishi.Srivatsavai@Sun.COM retv = -1; 32910491SRishi.Srivatsavai@Sun.COM } 33010491SRishi.Srivatsavai@Sun.COM } 33110491SRishi.Srivatsavai@Sun.COM 33210491SRishi.Srivatsavai@Sun.COM etmp = errno; 33310491SRishi.Srivatsavai@Sun.COM (void) close(did); 33410491SRishi.Srivatsavai@Sun.COM 33510491SRishi.Srivatsavai@Sun.COM /* Revoked door is the same as no door at all */ 33610491SRishi.Srivatsavai@Sun.COM if (etmp == EBADF) 33710491SRishi.Srivatsavai@Sun.COM etmp = ENOENT; 33810491SRishi.Srivatsavai@Sun.COM 33910491SRishi.Srivatsavai@Sun.COM return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp)); 34010491SRishi.Srivatsavai@Sun.COM } 34110491SRishi.Srivatsavai@Sun.COM 34210491SRishi.Srivatsavai@Sun.COM /* 34310491SRishi.Srivatsavai@Sun.COM * Wrapper function for making per-port calls. 34410491SRishi.Srivatsavai@Sun.COM */ 34510491SRishi.Srivatsavai@Sun.COM static dladm_status_t 34610491SRishi.Srivatsavai@Sun.COM port_door_call(dladm_handle_t handle, datalink_id_t linkid, 34710491SRishi.Srivatsavai@Sun.COM bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen) 34810491SRishi.Srivatsavai@Sun.COM { 34910491SRishi.Srivatsavai@Sun.COM char bridge[MAXLINKNAMELEN]; 35010491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 35110491SRishi.Srivatsavai@Sun.COM 35210491SRishi.Srivatsavai@Sun.COM status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 35310491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 35410491SRishi.Srivatsavai@Sun.COM return (status); 35510491SRishi.Srivatsavai@Sun.COM return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen, 35610491SRishi.Srivatsavai@Sun.COM B_FALSE)); 35710491SRishi.Srivatsavai@Sun.COM } 35810491SRishi.Srivatsavai@Sun.COM 35910491SRishi.Srivatsavai@Sun.COM static dladm_status_t 36010491SRishi.Srivatsavai@Sun.COM bridge_refresh(const char *bridge) 36110491SRishi.Srivatsavai@Sun.COM { 36210491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 36310491SRishi.Srivatsavai@Sun.COM int twoints[2]; 36410491SRishi.Srivatsavai@Sun.COM void *bdptr; 36510491SRishi.Srivatsavai@Sun.COM size_t buflen; 36610491SRishi.Srivatsavai@Sun.COM char *fmri; 36710491SRishi.Srivatsavai@Sun.COM int refresh_count; 36810491SRishi.Srivatsavai@Sun.COM 36910491SRishi.Srivatsavai@Sun.COM buflen = sizeof (twoints); 37010491SRishi.Srivatsavai@Sun.COM bdptr = twoints; 37110491SRishi.Srivatsavai@Sun.COM status = bridge_door_call(bridge, bdcBridgeGetRefreshCount, 37210491SRishi.Srivatsavai@Sun.COM DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE); 37310491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_NOTFOUND) 37410491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 37510491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 37610491SRishi.Srivatsavai@Sun.COM return (status); 37710491SRishi.Srivatsavai@Sun.COM refresh_count = twoints[0]; 37810491SRishi.Srivatsavai@Sun.COM if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL) 37910491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_NOMEM); 38010491SRishi.Srivatsavai@Sun.COM status = smf_refresh_instance(fmri) == 0 ? 38110491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK : DLADM_STATUS_FAILED; 38210491SRishi.Srivatsavai@Sun.COM free(fmri); 38310491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) { 38410491SRishi.Srivatsavai@Sun.COM int i = 0; 38510491SRishi.Srivatsavai@Sun.COM 38610491SRishi.Srivatsavai@Sun.COM /* 38710491SRishi.Srivatsavai@Sun.COM * SMF doesn't give any synchronous behavior or dependency 38810491SRishi.Srivatsavai@Sun.COM * ordering for refresh operations, so we have to invent our 38910491SRishi.Srivatsavai@Sun.COM * own mechanism here. Get the refresh counter from the 39010491SRishi.Srivatsavai@Sun.COM * daemon, and wait for it to change. It's not pretty, but 39110491SRishi.Srivatsavai@Sun.COM * it's sufficient. 39210491SRishi.Srivatsavai@Sun.COM */ 39310491SRishi.Srivatsavai@Sun.COM while (++i <= 10) { 39410491SRishi.Srivatsavai@Sun.COM buflen = sizeof (twoints); 39510491SRishi.Srivatsavai@Sun.COM bdptr = twoints; 39610491SRishi.Srivatsavai@Sun.COM status = bridge_door_call(bridge, 39710491SRishi.Srivatsavai@Sun.COM bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID, 39810491SRishi.Srivatsavai@Sun.COM &bdptr, 0, &buflen, B_FALSE); 39910491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 40010491SRishi.Srivatsavai@Sun.COM break; 40110491SRishi.Srivatsavai@Sun.COM if (twoints[0] != refresh_count) 40210491SRishi.Srivatsavai@Sun.COM break; 40310491SRishi.Srivatsavai@Sun.COM (void) usleep(100000); 40410491SRishi.Srivatsavai@Sun.COM } 40510491SRishi.Srivatsavai@Sun.COM fmri = alloc_fmri(TRILL_SVC_NAME, bridge); 40610491SRishi.Srivatsavai@Sun.COM if (fmri == NULL) 40710491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_NOMEM); 40810491SRishi.Srivatsavai@Sun.COM status = smf_refresh_instance(fmri) == 0 || 40910491SRishi.Srivatsavai@Sun.COM scf_error() == SCF_ERROR_NOT_FOUND ? 41010491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK : DLADM_STATUS_FAILED; 41110491SRishi.Srivatsavai@Sun.COM free(fmri); 41210491SRishi.Srivatsavai@Sun.COM } 41310491SRishi.Srivatsavai@Sun.COM return (status); 41410491SRishi.Srivatsavai@Sun.COM } 41510491SRishi.Srivatsavai@Sun.COM 41610491SRishi.Srivatsavai@Sun.COM /* 41710491SRishi.Srivatsavai@Sun.COM * Look up bridge property values from SCF and return them. 41810491SRishi.Srivatsavai@Sun.COM */ 41910491SRishi.Srivatsavai@Sun.COM dladm_status_t 42010491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg, 42110491SRishi.Srivatsavai@Sun.COM dladm_bridge_prot_t *brprotp) 42210491SRishi.Srivatsavai@Sun.COM { 42310491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 42410491SRishi.Srivatsavai@Sun.COM uint64_t value; 42510491SRishi.Srivatsavai@Sun.COM boolean_t trill_enabled; 42610491SRishi.Srivatsavai@Sun.COM 42710491SRishi.Srivatsavai@Sun.COM cfg->field_mask = 0; 42810491SRishi.Srivatsavai@Sun.COM cfg->bridge_priority = DEF_BR_PRIO; 42910491SRishi.Srivatsavai@Sun.COM cfg->max_age = DEF_BR_MAXAGE; 43010491SRishi.Srivatsavai@Sun.COM cfg->hello_time = DEF_BR_HELLOT; 43110491SRishi.Srivatsavai@Sun.COM cfg->forward_delay = DEF_BR_FWDELAY; 43210491SRishi.Srivatsavai@Sun.COM cfg->force_version = DEF_FORCE_VERS; 43310491SRishi.Srivatsavai@Sun.COM 43410491SRishi.Srivatsavai@Sun.COM (void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name)); 43510491SRishi.Srivatsavai@Sun.COM 43610491SRishi.Srivatsavai@Sun.COM *brprotp = DLADM_BRIDGE_PROT_STP; 43710491SRishi.Srivatsavai@Sun.COM 43810491SRishi.Srivatsavai@Sun.COM /* It's ok for this to be missing; it's installed separately */ 43910491SRishi.Srivatsavai@Sun.COM if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) { 44010491SRishi.Srivatsavai@Sun.COM trill_enabled = B_FALSE; 44110491SRishi.Srivatsavai@Sun.COM if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) == 44210491SRishi.Srivatsavai@Sun.COM 0) { 44310491SRishi.Srivatsavai@Sun.COM (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 44410491SRishi.Srivatsavai@Sun.COM &trill_enabled); 44510491SRishi.Srivatsavai@Sun.COM if (trill_enabled) 44610491SRishi.Srivatsavai@Sun.COM *brprotp = DLADM_BRIDGE_PROT_TRILL; 44710491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 44810491SRishi.Srivatsavai@Sun.COM } 44910491SRishi.Srivatsavai@Sun.COM if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE, 45010491SRishi.Srivatsavai@Sun.COM &sstate) == 0) { 45110491SRishi.Srivatsavai@Sun.COM (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 45210491SRishi.Srivatsavai@Sun.COM &trill_enabled); 45310491SRishi.Srivatsavai@Sun.COM if (trill_enabled) 45410491SRishi.Srivatsavai@Sun.COM *brprotp = DLADM_BRIDGE_PROT_TRILL; 45510491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 45610491SRishi.Srivatsavai@Sun.COM } 45710491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 45810491SRishi.Srivatsavai@Sun.COM } 45910491SRishi.Srivatsavai@Sun.COM 46010491SRishi.Srivatsavai@Sun.COM cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ? 46110491SRishi.Srivatsavai@Sun.COM STP_ENABLED : STP_DISABLED; 46210491SRishi.Srivatsavai@Sun.COM cfg->field_mask |= BR_CFG_STATE; 46310491SRishi.Srivatsavai@Sun.COM 46410491SRishi.Srivatsavai@Sun.COM if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 46510491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_REPOSITORYINVAL); 46610491SRishi.Srivatsavai@Sun.COM 46710491SRishi.Srivatsavai@Sun.COM if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 46810491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 46910491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_REPOSITORYINVAL); 47010491SRishi.Srivatsavai@Sun.COM } 47110491SRishi.Srivatsavai@Sun.COM 47210491SRishi.Srivatsavai@Sun.COM if (get_count("priority", &sstate, &value) == 0) { 47310491SRishi.Srivatsavai@Sun.COM cfg->bridge_priority = value; 47410491SRishi.Srivatsavai@Sun.COM cfg->field_mask |= BR_CFG_PRIO; 47510491SRishi.Srivatsavai@Sun.COM } 47610491SRishi.Srivatsavai@Sun.COM if (get_count("max-age", &sstate, &value) == 0) { 47710491SRishi.Srivatsavai@Sun.COM cfg->max_age = value / IEEE_TIMER_SCALE; 47810491SRishi.Srivatsavai@Sun.COM cfg->field_mask |= BR_CFG_AGE; 47910491SRishi.Srivatsavai@Sun.COM } 48010491SRishi.Srivatsavai@Sun.COM if (get_count("hello-time", &sstate, &value) == 0) { 48110491SRishi.Srivatsavai@Sun.COM cfg->hello_time = value / IEEE_TIMER_SCALE; 48210491SRishi.Srivatsavai@Sun.COM cfg->field_mask |= BR_CFG_HELLO; 48310491SRishi.Srivatsavai@Sun.COM } 48410491SRishi.Srivatsavai@Sun.COM if (get_count("forward-delay", &sstate, &value) == 0) { 48510491SRishi.Srivatsavai@Sun.COM cfg->forward_delay = value / IEEE_TIMER_SCALE; 48610491SRishi.Srivatsavai@Sun.COM cfg->field_mask |= BR_CFG_DELAY; 48710491SRishi.Srivatsavai@Sun.COM } 48810491SRishi.Srivatsavai@Sun.COM if (get_count("force-protocol", &sstate, &value) == 0) { 48910491SRishi.Srivatsavai@Sun.COM cfg->force_version = value; 49010491SRishi.Srivatsavai@Sun.COM cfg->field_mask |= BR_CFG_FORCE_VER; 49110491SRishi.Srivatsavai@Sun.COM } 49210491SRishi.Srivatsavai@Sun.COM 49310491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 49410491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 49510491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 49610491SRishi.Srivatsavai@Sun.COM } 49710491SRishi.Srivatsavai@Sun.COM 49810491SRishi.Srivatsavai@Sun.COM /* 49910491SRishi.Srivatsavai@Sun.COM * Retrieve special non-settable and undocumented parameters. 50010491SRishi.Srivatsavai@Sun.COM */ 50110491SRishi.Srivatsavai@Sun.COM dladm_status_t 50210491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp, 50310491SRishi.Srivatsavai@Sun.COM uint32_t *tablemaxp) 50410491SRishi.Srivatsavai@Sun.COM { 50510491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 50610491SRishi.Srivatsavai@Sun.COM uint64_t value; 50710491SRishi.Srivatsavai@Sun.COM 50810491SRishi.Srivatsavai@Sun.COM *debugp = B_FALSE; 50910491SRishi.Srivatsavai@Sun.COM *tablemaxp = 10000; 51010491SRishi.Srivatsavai@Sun.COM 51110491SRishi.Srivatsavai@Sun.COM if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 51210491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_REPOSITORYINVAL); 51310491SRishi.Srivatsavai@Sun.COM 51410491SRishi.Srivatsavai@Sun.COM if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 51510491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 51610491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_REPOSITORYINVAL); 51710491SRishi.Srivatsavai@Sun.COM } 51810491SRishi.Srivatsavai@Sun.COM 51910491SRishi.Srivatsavai@Sun.COM (void) get_boolean("debug", &sstate, debugp); 52010491SRishi.Srivatsavai@Sun.COM if (get_count("table-maximum", &sstate, &value) == 0) 52110491SRishi.Srivatsavai@Sun.COM *tablemaxp = (uint32_t)value; 52210491SRishi.Srivatsavai@Sun.COM 52310491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 52410491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 52510491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 52610491SRishi.Srivatsavai@Sun.COM } 52710491SRishi.Srivatsavai@Sun.COM 52810491SRishi.Srivatsavai@Sun.COM static boolean_t 52910491SRishi.Srivatsavai@Sun.COM set_count_property(scf_handle_t *handle, scf_transaction_t *tran, 53010491SRishi.Srivatsavai@Sun.COM const char *propname, uint64_t propval) 53110491SRishi.Srivatsavai@Sun.COM { 53210491SRishi.Srivatsavai@Sun.COM scf_transaction_entry_t *entry; 53310491SRishi.Srivatsavai@Sun.COM scf_value_t *value = NULL; 53410491SRishi.Srivatsavai@Sun.COM 53510491SRishi.Srivatsavai@Sun.COM if ((entry = scf_entry_create(handle)) == NULL) 53610491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 53710491SRishi.Srivatsavai@Sun.COM 53810491SRishi.Srivatsavai@Sun.COM if ((value = scf_value_create(handle)) == NULL) 53910491SRishi.Srivatsavai@Sun.COM goto out; 54010491SRishi.Srivatsavai@Sun.COM if (scf_transaction_property_new(tran, entry, propname, 54110491SRishi.Srivatsavai@Sun.COM SCF_TYPE_COUNT) != 0 && 54210491SRishi.Srivatsavai@Sun.COM scf_transaction_property_change(tran, entry, propname, 54310491SRishi.Srivatsavai@Sun.COM SCF_TYPE_COUNT) != 0) 54410491SRishi.Srivatsavai@Sun.COM goto out; 54510491SRishi.Srivatsavai@Sun.COM scf_value_set_count(value, propval); 54610491SRishi.Srivatsavai@Sun.COM if (scf_entry_add_value(entry, value) == 0) 54710491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 54810491SRishi.Srivatsavai@Sun.COM 54910491SRishi.Srivatsavai@Sun.COM out: 55010491SRishi.Srivatsavai@Sun.COM if (value != NULL) 55110491SRishi.Srivatsavai@Sun.COM scf_value_destroy(value); 55210491SRishi.Srivatsavai@Sun.COM 55310491SRishi.Srivatsavai@Sun.COM scf_entry_destroy_children(entry); 55410491SRishi.Srivatsavai@Sun.COM scf_entry_destroy(entry); 55510491SRishi.Srivatsavai@Sun.COM 55610491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 55710491SRishi.Srivatsavai@Sun.COM } 55810491SRishi.Srivatsavai@Sun.COM 55910491SRishi.Srivatsavai@Sun.COM static boolean_t 56010491SRishi.Srivatsavai@Sun.COM set_string_property(scf_handle_t *handle, scf_transaction_t *tran, 56110491SRishi.Srivatsavai@Sun.COM const char *propname, const char *propval) 56210491SRishi.Srivatsavai@Sun.COM { 56310491SRishi.Srivatsavai@Sun.COM scf_transaction_entry_t *entry; 56410491SRishi.Srivatsavai@Sun.COM scf_value_t *value = NULL; 56510491SRishi.Srivatsavai@Sun.COM 56610491SRishi.Srivatsavai@Sun.COM if ((entry = scf_entry_create(handle)) == NULL) 56710491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 56810491SRishi.Srivatsavai@Sun.COM 56910491SRishi.Srivatsavai@Sun.COM if ((value = scf_value_create(handle)) == NULL) 57010491SRishi.Srivatsavai@Sun.COM goto out; 57110491SRishi.Srivatsavai@Sun.COM if (scf_transaction_property_new(tran, entry, propname, 57210491SRishi.Srivatsavai@Sun.COM SCF_TYPE_ASTRING) != 0 && 57310491SRishi.Srivatsavai@Sun.COM scf_transaction_property_change(tran, entry, propname, 57410491SRishi.Srivatsavai@Sun.COM SCF_TYPE_ASTRING) != 0) 57510491SRishi.Srivatsavai@Sun.COM goto out; 57610491SRishi.Srivatsavai@Sun.COM if (scf_value_set_astring(value, propval) != 0) 57710491SRishi.Srivatsavai@Sun.COM goto out; 57810491SRishi.Srivatsavai@Sun.COM if (scf_entry_add_value(entry, value) == 0) 57910491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 58010491SRishi.Srivatsavai@Sun.COM 58110491SRishi.Srivatsavai@Sun.COM out: 58210491SRishi.Srivatsavai@Sun.COM if (value != NULL) 58310491SRishi.Srivatsavai@Sun.COM scf_value_destroy(value); 58410491SRishi.Srivatsavai@Sun.COM 58510491SRishi.Srivatsavai@Sun.COM scf_entry_destroy_children(entry); 58610491SRishi.Srivatsavai@Sun.COM scf_entry_destroy(entry); 58710491SRishi.Srivatsavai@Sun.COM 58810491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 58910491SRishi.Srivatsavai@Sun.COM } 59010491SRishi.Srivatsavai@Sun.COM 59110491SRishi.Srivatsavai@Sun.COM static boolean_t 59210491SRishi.Srivatsavai@Sun.COM set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran, 59310491SRishi.Srivatsavai@Sun.COM const char *propname, const char *propval) 59410491SRishi.Srivatsavai@Sun.COM { 59510491SRishi.Srivatsavai@Sun.COM scf_transaction_entry_t *entry; 59610491SRishi.Srivatsavai@Sun.COM scf_value_t *value = NULL; 59710491SRishi.Srivatsavai@Sun.COM 59810491SRishi.Srivatsavai@Sun.COM if ((entry = scf_entry_create(handle)) == NULL) 59910491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 60010491SRishi.Srivatsavai@Sun.COM 60110491SRishi.Srivatsavai@Sun.COM if ((value = scf_value_create(handle)) == NULL) 60210491SRishi.Srivatsavai@Sun.COM goto out; 60310491SRishi.Srivatsavai@Sun.COM if (scf_transaction_property_new(tran, entry, propname, 60410491SRishi.Srivatsavai@Sun.COM SCF_TYPE_FMRI) != 0 && 60510491SRishi.Srivatsavai@Sun.COM scf_transaction_property_change(tran, entry, propname, 60610491SRishi.Srivatsavai@Sun.COM SCF_TYPE_FMRI) != 0) 60710491SRishi.Srivatsavai@Sun.COM goto out; 60810491SRishi.Srivatsavai@Sun.COM if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0) 60910491SRishi.Srivatsavai@Sun.COM goto out; 61010491SRishi.Srivatsavai@Sun.COM if (scf_entry_add_value(entry, value) == 0) 61110491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 61210491SRishi.Srivatsavai@Sun.COM 61310491SRishi.Srivatsavai@Sun.COM out: 61410491SRishi.Srivatsavai@Sun.COM if (value != NULL) 61510491SRishi.Srivatsavai@Sun.COM scf_value_destroy(value); 61610491SRishi.Srivatsavai@Sun.COM 61710491SRishi.Srivatsavai@Sun.COM scf_entry_destroy_children(entry); 61810491SRishi.Srivatsavai@Sun.COM scf_entry_destroy(entry); 61910491SRishi.Srivatsavai@Sun.COM 62010491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 62110491SRishi.Srivatsavai@Sun.COM } 62210491SRishi.Srivatsavai@Sun.COM 62310491SRishi.Srivatsavai@Sun.COM static dladm_status_t 62410491SRishi.Srivatsavai@Sun.COM dladm_bridge_persist_conf(dladm_handle_t handle, const char *link, 62510491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid) 62610491SRishi.Srivatsavai@Sun.COM { 62710491SRishi.Srivatsavai@Sun.COM dladm_conf_t conf = DLADM_INVALID_CONF; 62810491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 62910491SRishi.Srivatsavai@Sun.COM 63010491SRishi.Srivatsavai@Sun.COM status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE, 63110491SRishi.Srivatsavai@Sun.COM DL_ETHER, &conf); 63210491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) { 63310491SRishi.Srivatsavai@Sun.COM /* 63410491SRishi.Srivatsavai@Sun.COM * Create the datalink entry for the bridge. Note that all of 63510491SRishi.Srivatsavai@Sun.COM * the real configuration information is in SMF. 63610491SRishi.Srivatsavai@Sun.COM */ 63710491SRishi.Srivatsavai@Sun.COM status = dladm_write_conf(handle, conf); 63810491SRishi.Srivatsavai@Sun.COM dladm_destroy_conf(handle, conf); 63910491SRishi.Srivatsavai@Sun.COM } 64010491SRishi.Srivatsavai@Sun.COM return (status); 64110491SRishi.Srivatsavai@Sun.COM } 64210491SRishi.Srivatsavai@Sun.COM 64310491SRishi.Srivatsavai@Sun.COM /* Convert bridge protection option string to dladm_bridge_prot_t */ 64410491SRishi.Srivatsavai@Sun.COM dladm_status_t 64510491SRishi.Srivatsavai@Sun.COM dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp) 64610491SRishi.Srivatsavai@Sun.COM { 64710491SRishi.Srivatsavai@Sun.COM if (strcmp(str, "stp") == 0) 64810491SRishi.Srivatsavai@Sun.COM *brprotp = DLADM_BRIDGE_PROT_STP; 64910491SRishi.Srivatsavai@Sun.COM else if (strcmp(str, "trill") == 0) 65010491SRishi.Srivatsavai@Sun.COM *brprotp = DLADM_BRIDGE_PROT_TRILL; 65110491SRishi.Srivatsavai@Sun.COM else 65210491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_BADARG); 65310491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 65410491SRishi.Srivatsavai@Sun.COM } 65510491SRishi.Srivatsavai@Sun.COM 65610491SRishi.Srivatsavai@Sun.COM /* Convert bridge protection option from dladm_bridge_prot_t to string */ 65710491SRishi.Srivatsavai@Sun.COM const char * 65810491SRishi.Srivatsavai@Sun.COM dladm_bridge_prot2str(dladm_bridge_prot_t brprot) 65910491SRishi.Srivatsavai@Sun.COM { 66010491SRishi.Srivatsavai@Sun.COM switch (brprot) { 66110491SRishi.Srivatsavai@Sun.COM case DLADM_BRIDGE_PROT_STP: 66210491SRishi.Srivatsavai@Sun.COM return ("stp"); 66310491SRishi.Srivatsavai@Sun.COM case DLADM_BRIDGE_PROT_TRILL: 66410491SRishi.Srivatsavai@Sun.COM return ("trill"); 66510491SRishi.Srivatsavai@Sun.COM default: 66610491SRishi.Srivatsavai@Sun.COM return ("unknown"); 66710491SRishi.Srivatsavai@Sun.COM } 66810491SRishi.Srivatsavai@Sun.COM } 66910491SRishi.Srivatsavai@Sun.COM 67010491SRishi.Srivatsavai@Sun.COM static dladm_status_t 67110491SRishi.Srivatsavai@Sun.COM enable_instance(const char *service_name, const char *instance) 67210491SRishi.Srivatsavai@Sun.COM { 67310491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 67410491SRishi.Srivatsavai@Sun.COM char *fmri = alloc_fmri(service_name, instance); 67510491SRishi.Srivatsavai@Sun.COM 67610491SRishi.Srivatsavai@Sun.COM if (fmri == NULL) 67710491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_NOMEM); 67810491SRishi.Srivatsavai@Sun.COM status = smf_enable_instance(fmri, 0) == 0 ? 67910491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK : DLADM_STATUS_FAILED; 68010491SRishi.Srivatsavai@Sun.COM free(fmri); 68110491SRishi.Srivatsavai@Sun.COM return (status); 68210491SRishi.Srivatsavai@Sun.COM } 68310491SRishi.Srivatsavai@Sun.COM 68410491SRishi.Srivatsavai@Sun.COM /* 68510491SRishi.Srivatsavai@Sun.COM * Shut down a possibly-running service instance. If this is a permanent 68610491SRishi.Srivatsavai@Sun.COM * change, then delete it from the system. 68710491SRishi.Srivatsavai@Sun.COM */ 68810491SRishi.Srivatsavai@Sun.COM static dladm_status_t 68910491SRishi.Srivatsavai@Sun.COM shut_down_instance(const char *service_name, const char *instance, 69010491SRishi.Srivatsavai@Sun.COM uint32_t flags) 69110491SRishi.Srivatsavai@Sun.COM { 69210491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 69310491SRishi.Srivatsavai@Sun.COM char *fmri = alloc_fmri(service_name, instance); 69410491SRishi.Srivatsavai@Sun.COM char *state; 69510491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 69610491SRishi.Srivatsavai@Sun.COM 69710491SRishi.Srivatsavai@Sun.COM if (fmri == NULL) 69810491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_NOMEM); 69910491SRishi.Srivatsavai@Sun.COM 70010491SRishi.Srivatsavai@Sun.COM if (smf_disable_instance(fmri, 70110491SRishi.Srivatsavai@Sun.COM flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) { 70210491SRishi.Srivatsavai@Sun.COM useconds_t usecs, umax; 70310491SRishi.Srivatsavai@Sun.COM 70410491SRishi.Srivatsavai@Sun.COM /* If we can disable, then wait for it to happen. */ 70510491SRishi.Srivatsavai@Sun.COM umax = DEFAULT_TIMEOUT; 70610491SRishi.Srivatsavai@Sun.COM for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) { 70710491SRishi.Srivatsavai@Sun.COM state = smf_get_state(fmri); 70810491SRishi.Srivatsavai@Sun.COM if (state != NULL && 70910491SRishi.Srivatsavai@Sun.COM strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 71010491SRishi.Srivatsavai@Sun.COM break; 71110491SRishi.Srivatsavai@Sun.COM free(state); 71210491SRishi.Srivatsavai@Sun.COM usecs *= 2; 71310491SRishi.Srivatsavai@Sun.COM if (usecs > umax) 71410491SRishi.Srivatsavai@Sun.COM usecs = umax; 71510491SRishi.Srivatsavai@Sun.COM (void) usleep(usecs); 71610491SRishi.Srivatsavai@Sun.COM } 71710491SRishi.Srivatsavai@Sun.COM if (umax == 0) { 71810491SRishi.Srivatsavai@Sun.COM state = smf_get_state(fmri); 71910491SRishi.Srivatsavai@Sun.COM if (state != NULL && 72010491SRishi.Srivatsavai@Sun.COM strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 72110491SRishi.Srivatsavai@Sun.COM umax = 1; 72210491SRishi.Srivatsavai@Sun.COM } 72310491SRishi.Srivatsavai@Sun.COM free(state); 72410491SRishi.Srivatsavai@Sun.COM status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED; 72510491SRishi.Srivatsavai@Sun.COM } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 72610491SRishi.Srivatsavai@Sun.COM free(fmri); 72710491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 72810491SRishi.Srivatsavai@Sun.COM } else { 72910491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_FAILED; 73010491SRishi.Srivatsavai@Sun.COM } 73110491SRishi.Srivatsavai@Sun.COM 73210491SRishi.Srivatsavai@Sun.COM free(fmri); 73310491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) && 73410491SRishi.Srivatsavai@Sun.COM bind_instance(service_name, instance, &sstate) == 0) { 73510491SRishi.Srivatsavai@Sun.COM (void) scf_instance_delete(sstate.ss_inst); 73610491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 73710491SRishi.Srivatsavai@Sun.COM } 73810491SRishi.Srivatsavai@Sun.COM 73910491SRishi.Srivatsavai@Sun.COM return (status); 74010491SRishi.Srivatsavai@Sun.COM } 74110491SRishi.Srivatsavai@Sun.COM 74210491SRishi.Srivatsavai@Sun.COM static dladm_status_t 74310491SRishi.Srivatsavai@Sun.COM disable_trill(const char *instance, uint32_t flags) 74410491SRishi.Srivatsavai@Sun.COM { 74510491SRishi.Srivatsavai@Sun.COM return (shut_down_instance(TRILL_SVC_NAME, instance, flags)); 74610491SRishi.Srivatsavai@Sun.COM } 74710491SRishi.Srivatsavai@Sun.COM 74810491SRishi.Srivatsavai@Sun.COM /* 74910491SRishi.Srivatsavai@Sun.COM * To enable TRILL, we must create a new instance of the TRILL service, then 75010491SRishi.Srivatsavai@Sun.COM * add proper dependencies to it, and finally mark it as enabled. The 75110491SRishi.Srivatsavai@Sun.COM * dependencies will keep it from going on-line until the bridge is running. 75210491SRishi.Srivatsavai@Sun.COM */ 75310491SRishi.Srivatsavai@Sun.COM static dladm_status_t 75410491SRishi.Srivatsavai@Sun.COM enable_trill(const char *instance) 75510491SRishi.Srivatsavai@Sun.COM { 75610491SRishi.Srivatsavai@Sun.COM dladm_status_t status = DLADM_STATUS_FAILED; 75710491SRishi.Srivatsavai@Sun.COM char *fmri = NULL; 75810491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 75910491SRishi.Srivatsavai@Sun.COM scf_transaction_t *tran = NULL; 76010491SRishi.Srivatsavai@Sun.COM boolean_t new_instance = B_FALSE; 76110491SRishi.Srivatsavai@Sun.COM boolean_t new_pg = B_FALSE; 76210491SRishi.Srivatsavai@Sun.COM int rv; 76310491SRishi.Srivatsavai@Sun.COM 76410491SRishi.Srivatsavai@Sun.COM /* 76510491SRishi.Srivatsavai@Sun.COM * This check is here in case the user has installed and then removed 76610491SRishi.Srivatsavai@Sun.COM * the package. SMF should remove the manifest, but currently does 76710491SRishi.Srivatsavai@Sun.COM * not. 76810491SRishi.Srivatsavai@Sun.COM */ 76910491SRishi.Srivatsavai@Sun.COM if (access("/usr/sbin/trilld", F_OK) != 0) 77010491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OPTMISSING); 77110491SRishi.Srivatsavai@Sun.COM 77210491SRishi.Srivatsavai@Sun.COM if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) != 77310491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) 77410491SRishi.Srivatsavai@Sun.COM goto out; 77510491SRishi.Srivatsavai@Sun.COM 77610491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_FAILED; 77710491SRishi.Srivatsavai@Sun.COM if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) != 77810491SRishi.Srivatsavai@Sun.COM 0) { 77910491SRishi.Srivatsavai@Sun.COM if (scf_service_add_instance(sstate.ss_svc, instance, 78010491SRishi.Srivatsavai@Sun.COM sstate.ss_inst) != 0) 78110491SRishi.Srivatsavai@Sun.COM goto out; 78210491SRishi.Srivatsavai@Sun.COM new_instance = B_TRUE; 78310491SRishi.Srivatsavai@Sun.COM } 78410491SRishi.Srivatsavai@Sun.COM 78510491SRishi.Srivatsavai@Sun.COM if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 78610491SRishi.Srivatsavai@Sun.COM goto out; 78710491SRishi.Srivatsavai@Sun.COM 78810491SRishi.Srivatsavai@Sun.COM if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 78910491SRishi.Srivatsavai@Sun.COM goto out; 79010491SRishi.Srivatsavai@Sun.COM 79110491SRishi.Srivatsavai@Sun.COM if (scf_instance_get_pg(sstate.ss_inst, "bridging", 79210491SRishi.Srivatsavai@Sun.COM sstate.ss_pg) == 0) { 79310491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_OK; 79410491SRishi.Srivatsavai@Sun.COM goto out; 79510491SRishi.Srivatsavai@Sun.COM } 79610491SRishi.Srivatsavai@Sun.COM 79710491SRishi.Srivatsavai@Sun.COM if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL) 79810491SRishi.Srivatsavai@Sun.COM goto out; 79910491SRishi.Srivatsavai@Sun.COM 80010491SRishi.Srivatsavai@Sun.COM if (scf_instance_add_pg(sstate.ss_inst, "bridging", 80110491SRishi.Srivatsavai@Sun.COM SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0) 80210491SRishi.Srivatsavai@Sun.COM goto out; 80310491SRishi.Srivatsavai@Sun.COM 80410491SRishi.Srivatsavai@Sun.COM new_pg = B_TRUE; 80510491SRishi.Srivatsavai@Sun.COM do { 80610491SRishi.Srivatsavai@Sun.COM if (scf_transaction_start(tran, sstate.ss_pg) != 0) 80710491SRishi.Srivatsavai@Sun.COM goto out; 80810491SRishi.Srivatsavai@Sun.COM 80910491SRishi.Srivatsavai@Sun.COM if (!set_string_property(sstate.ss_handle, tran, 81010491SRishi.Srivatsavai@Sun.COM SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL)) 81110491SRishi.Srivatsavai@Sun.COM goto out; 81210491SRishi.Srivatsavai@Sun.COM if (!set_string_property(sstate.ss_handle, tran, 81310491SRishi.Srivatsavai@Sun.COM SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART)) 81410491SRishi.Srivatsavai@Sun.COM goto out; 81510491SRishi.Srivatsavai@Sun.COM if (!set_string_property(sstate.ss_handle, tran, 81610491SRishi.Srivatsavai@Sun.COM SCF_PROPERTY_TYPE, "service")) 81710491SRishi.Srivatsavai@Sun.COM goto out; 81810491SRishi.Srivatsavai@Sun.COM if (!set_fmri_property(sstate.ss_handle, tran, 81910491SRishi.Srivatsavai@Sun.COM SCF_PROPERTY_ENTITIES, fmri)) 82010491SRishi.Srivatsavai@Sun.COM goto out; 82110491SRishi.Srivatsavai@Sun.COM 82210491SRishi.Srivatsavai@Sun.COM rv = scf_transaction_commit(tran); 82310491SRishi.Srivatsavai@Sun.COM scf_transaction_reset(tran); 82410491SRishi.Srivatsavai@Sun.COM if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 82510491SRishi.Srivatsavai@Sun.COM goto out; 82610491SRishi.Srivatsavai@Sun.COM } while (rv == 0); 82710491SRishi.Srivatsavai@Sun.COM if (rv != 1) 82810491SRishi.Srivatsavai@Sun.COM goto out; 82910491SRishi.Srivatsavai@Sun.COM 83010491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_OK; 83110491SRishi.Srivatsavai@Sun.COM 83210491SRishi.Srivatsavai@Sun.COM out: 83310491SRishi.Srivatsavai@Sun.COM free(fmri); 83410491SRishi.Srivatsavai@Sun.COM if (tran != NULL) { 83510491SRishi.Srivatsavai@Sun.COM scf_transaction_destroy_children(tran); 83610491SRishi.Srivatsavai@Sun.COM scf_transaction_destroy(tran); 83710491SRishi.Srivatsavai@Sun.COM } 83810491SRishi.Srivatsavai@Sun.COM 83910491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK && new_pg) 84010491SRishi.Srivatsavai@Sun.COM (void) scf_pg_delete(sstate.ss_pg); 84110491SRishi.Srivatsavai@Sun.COM 84210491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 84310491SRishi.Srivatsavai@Sun.COM 84410491SRishi.Srivatsavai@Sun.COM /* 84510491SRishi.Srivatsavai@Sun.COM * If we created an instance and then failed, then remove the instance 84610491SRishi.Srivatsavai@Sun.COM * from the system. 84710491SRishi.Srivatsavai@Sun.COM */ 84810491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK && new_instance) 84910491SRishi.Srivatsavai@Sun.COM (void) scf_instance_delete(sstate.ss_inst); 85010491SRishi.Srivatsavai@Sun.COM 85110491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 85210491SRishi.Srivatsavai@Sun.COM 85310491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) 85410491SRishi.Srivatsavai@Sun.COM status = enable_instance(TRILL_SVC_NAME, instance); 85510491SRishi.Srivatsavai@Sun.COM 85610491SRishi.Srivatsavai@Sun.COM return (status); 85710491SRishi.Srivatsavai@Sun.COM } 85810491SRishi.Srivatsavai@Sun.COM 85910491SRishi.Srivatsavai@Sun.COM /* 86010491SRishi.Srivatsavai@Sun.COM * Create a new bridge or modify an existing one. Update the SMF configuration 86110491SRishi.Srivatsavai@Sun.COM * and add links. 86210491SRishi.Srivatsavai@Sun.COM * 86310491SRishi.Srivatsavai@Sun.COM * Input timer values are in IEEE scaled (* 256) format. 86410491SRishi.Srivatsavai@Sun.COM */ 86510491SRishi.Srivatsavai@Sun.COM dladm_status_t 86610491SRishi.Srivatsavai@Sun.COM dladm_bridge_configure(dladm_handle_t handle, const char *name, 86710491SRishi.Srivatsavai@Sun.COM const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags) 86810491SRishi.Srivatsavai@Sun.COM { 86910491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 87010491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 87110491SRishi.Srivatsavai@Sun.COM scf_transaction_t *tran = NULL; 87210491SRishi.Srivatsavai@Sun.COM boolean_t new_instance = B_FALSE; 87310491SRishi.Srivatsavai@Sun.COM boolean_t new_pg = B_FALSE; 87410491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid = DATALINK_INVALID_LINKID; 87510491SRishi.Srivatsavai@Sun.COM char linkname[MAXLINKNAMELEN]; 87610491SRishi.Srivatsavai@Sun.COM int rv; 87710491SRishi.Srivatsavai@Sun.COM 87810491SRishi.Srivatsavai@Sun.COM if (!dladm_valid_bridgename(name)) 87910491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_FAILED); 88010491SRishi.Srivatsavai@Sun.COM 88110491SRishi.Srivatsavai@Sun.COM if (flags & DLADM_OPT_CREATE) { 88210491SRishi.Srivatsavai@Sun.COM /* 88310491SRishi.Srivatsavai@Sun.COM * This check is here in case the user has installed and then 88410491SRishi.Srivatsavai@Sun.COM * removed the package. SMF should remove the manifest, but 88510491SRishi.Srivatsavai@Sun.COM * currently does not. 88610491SRishi.Srivatsavai@Sun.COM */ 88710491SRishi.Srivatsavai@Sun.COM if (access("/usr/lib/bridged", F_OK) != 0) 88810491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OPTMISSING); 88910491SRishi.Srivatsavai@Sun.COM 89010491SRishi.Srivatsavai@Sun.COM (void) snprintf(linkname, sizeof (linkname), "%s0", name); 89110491SRishi.Srivatsavai@Sun.COM status = dladm_create_datalink_id(handle, linkname, 89210491SRishi.Srivatsavai@Sun.COM DATALINK_CLASS_BRIDGE, DL_ETHER, 89310491SRishi.Srivatsavai@Sun.COM flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid); 89410491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 89510491SRishi.Srivatsavai@Sun.COM return (status); 89610491SRishi.Srivatsavai@Sun.COM 89710491SRishi.Srivatsavai@Sun.COM if ((flags & DLADM_OPT_PERSIST) && 89810491SRishi.Srivatsavai@Sun.COM (status = dladm_bridge_persist_conf(handle, linkname, 89910491SRishi.Srivatsavai@Sun.COM linkid) != DLADM_STATUS_OK)) 90010491SRishi.Srivatsavai@Sun.COM goto dladm_fail; 90110491SRishi.Srivatsavai@Sun.COM } 90210491SRishi.Srivatsavai@Sun.COM 90310491SRishi.Srivatsavai@Sun.COM if (brprot == DLADM_BRIDGE_PROT_TRILL) 90410491SRishi.Srivatsavai@Sun.COM status = enable_trill(name); 90510491SRishi.Srivatsavai@Sun.COM else 90610491SRishi.Srivatsavai@Sun.COM status = disable_trill(name, flags); 90710491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 90810491SRishi.Srivatsavai@Sun.COM goto dladm_fail; 90910491SRishi.Srivatsavai@Sun.COM 91010491SRishi.Srivatsavai@Sun.COM if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) != 91110491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) 91210491SRishi.Srivatsavai@Sun.COM goto out; 91310491SRishi.Srivatsavai@Sun.COM 91410491SRishi.Srivatsavai@Sun.COM /* set up for a series of scf calls */ 91510491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_FAILED; 91610491SRishi.Srivatsavai@Sun.COM 91710491SRishi.Srivatsavai@Sun.COM if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) == 91810491SRishi.Srivatsavai@Sun.COM 0) { 91910491SRishi.Srivatsavai@Sun.COM if (flags & DLADM_OPT_CREATE) { 92010491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_EXIST; 92110491SRishi.Srivatsavai@Sun.COM goto out; 92210491SRishi.Srivatsavai@Sun.COM } 92310491SRishi.Srivatsavai@Sun.COM } else { 92410491SRishi.Srivatsavai@Sun.COM if (!(flags & DLADM_OPT_CREATE)) { 92510491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_NOTFOUND; 92610491SRishi.Srivatsavai@Sun.COM goto out; 92710491SRishi.Srivatsavai@Sun.COM } 92810491SRishi.Srivatsavai@Sun.COM if (scf_service_add_instance(sstate.ss_svc, name, 92910491SRishi.Srivatsavai@Sun.COM sstate.ss_inst) != 0) 93010491SRishi.Srivatsavai@Sun.COM goto out; 93110491SRishi.Srivatsavai@Sun.COM new_instance = B_TRUE; 93210491SRishi.Srivatsavai@Sun.COM } 93310491SRishi.Srivatsavai@Sun.COM 93410491SRishi.Srivatsavai@Sun.COM if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 93510491SRishi.Srivatsavai@Sun.COM goto out; 93610491SRishi.Srivatsavai@Sun.COM 93710491SRishi.Srivatsavai@Sun.COM if (cfg->field_mask & BR_CFG_ALL) { 93810491SRishi.Srivatsavai@Sun.COM if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 93910491SRishi.Srivatsavai@Sun.COM goto out; 94010491SRishi.Srivatsavai@Sun.COM if (scf_instance_add_pg(sstate.ss_inst, "config", 94110491SRishi.Srivatsavai@Sun.COM SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 94210491SRishi.Srivatsavai@Sun.COM new_pg = B_TRUE; 94310491SRishi.Srivatsavai@Sun.COM } else if (scf_instance_get_pg(sstate.ss_inst, "config", 94410491SRishi.Srivatsavai@Sun.COM sstate.ss_pg) != 0) { 94510491SRishi.Srivatsavai@Sun.COM goto out; 94610491SRishi.Srivatsavai@Sun.COM } 94710491SRishi.Srivatsavai@Sun.COM do { 94810491SRishi.Srivatsavai@Sun.COM if (scf_transaction_start(tran, sstate.ss_pg) != 0) 94910491SRishi.Srivatsavai@Sun.COM goto out; 95010491SRishi.Srivatsavai@Sun.COM 95110491SRishi.Srivatsavai@Sun.COM if ((cfg->field_mask & BR_CFG_PRIO) && 95210491SRishi.Srivatsavai@Sun.COM !set_count_property(sstate.ss_handle, tran, 95310491SRishi.Srivatsavai@Sun.COM "priority", cfg->bridge_priority)) 95410491SRishi.Srivatsavai@Sun.COM goto out; 95510491SRishi.Srivatsavai@Sun.COM if ((cfg->field_mask & BR_CFG_AGE) && 95610491SRishi.Srivatsavai@Sun.COM !set_count_property(sstate.ss_handle, tran, 95710491SRishi.Srivatsavai@Sun.COM "max-age", cfg->max_age * IEEE_TIMER_SCALE)) 95810491SRishi.Srivatsavai@Sun.COM goto out; 95910491SRishi.Srivatsavai@Sun.COM if ((cfg->field_mask & BR_CFG_HELLO) && 96010491SRishi.Srivatsavai@Sun.COM !set_count_property(sstate.ss_handle, tran, 96110491SRishi.Srivatsavai@Sun.COM "hello-time", cfg->hello_time * IEEE_TIMER_SCALE)) 96210491SRishi.Srivatsavai@Sun.COM goto out; 96310491SRishi.Srivatsavai@Sun.COM if ((cfg->field_mask & BR_CFG_DELAY) && 96410491SRishi.Srivatsavai@Sun.COM !set_count_property(sstate.ss_handle, tran, 96510491SRishi.Srivatsavai@Sun.COM "forward-delay", 96610491SRishi.Srivatsavai@Sun.COM cfg->forward_delay * IEEE_TIMER_SCALE)) 96710491SRishi.Srivatsavai@Sun.COM goto out; 96810491SRishi.Srivatsavai@Sun.COM if ((cfg->field_mask & BR_CFG_FORCE_VER) && 96910491SRishi.Srivatsavai@Sun.COM !set_count_property(sstate.ss_handle, tran, 97010491SRishi.Srivatsavai@Sun.COM "force-protocol", cfg->force_version)) 97110491SRishi.Srivatsavai@Sun.COM goto out; 97210491SRishi.Srivatsavai@Sun.COM 97310491SRishi.Srivatsavai@Sun.COM rv = scf_transaction_commit(tran); 97410491SRishi.Srivatsavai@Sun.COM scf_transaction_reset(tran); 97510491SRishi.Srivatsavai@Sun.COM if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 97610491SRishi.Srivatsavai@Sun.COM goto out; 97710491SRishi.Srivatsavai@Sun.COM } while (rv == 0); 97810491SRishi.Srivatsavai@Sun.COM if (rv != 1) 97910491SRishi.Srivatsavai@Sun.COM goto out; 98010491SRishi.Srivatsavai@Sun.COM } 98110491SRishi.Srivatsavai@Sun.COM 98210491SRishi.Srivatsavai@Sun.COM /* 98310491SRishi.Srivatsavai@Sun.COM * If we're modifying an existing and running bridge, then tell the 98410491SRishi.Srivatsavai@Sun.COM * daemon to update the requested values. 98510491SRishi.Srivatsavai@Sun.COM */ 98610491SRishi.Srivatsavai@Sun.COM if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE)) 98710491SRishi.Srivatsavai@Sun.COM status = bridge_refresh(name); 98810491SRishi.Srivatsavai@Sun.COM else 98910491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_OK; 99010491SRishi.Srivatsavai@Sun.COM 99110491SRishi.Srivatsavai@Sun.COM out: 99210491SRishi.Srivatsavai@Sun.COM if (tran != NULL) { 99310491SRishi.Srivatsavai@Sun.COM scf_transaction_destroy_children(tran); 99410491SRishi.Srivatsavai@Sun.COM scf_transaction_destroy(tran); 99510491SRishi.Srivatsavai@Sun.COM } 99610491SRishi.Srivatsavai@Sun.COM 99710491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK && new_pg) 99810491SRishi.Srivatsavai@Sun.COM (void) scf_pg_delete(sstate.ss_pg); 99910491SRishi.Srivatsavai@Sun.COM 100010491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 100110491SRishi.Srivatsavai@Sun.COM 100210491SRishi.Srivatsavai@Sun.COM /* 100310491SRishi.Srivatsavai@Sun.COM * If we created an instance and then failed, then remove the instance 100410491SRishi.Srivatsavai@Sun.COM * from the system. 100510491SRishi.Srivatsavai@Sun.COM */ 100610491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK && new_instance) 100710491SRishi.Srivatsavai@Sun.COM (void) scf_instance_delete(sstate.ss_inst); 100810491SRishi.Srivatsavai@Sun.COM 100910491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 101010491SRishi.Srivatsavai@Sun.COM 101110491SRishi.Srivatsavai@Sun.COM /* 101210491SRishi.Srivatsavai@Sun.COM * Remove the bridge linkid if we've allocated one in this function but 101310491SRishi.Srivatsavai@Sun.COM * we've failed to set up the SMF properties. 101410491SRishi.Srivatsavai@Sun.COM */ 101510491SRishi.Srivatsavai@Sun.COM dladm_fail: 101610491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) { 101710491SRishi.Srivatsavai@Sun.COM (void) dladm_remove_conf(handle, linkid); 101810491SRishi.Srivatsavai@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, flags); 101910491SRishi.Srivatsavai@Sun.COM } 102010491SRishi.Srivatsavai@Sun.COM 102110491SRishi.Srivatsavai@Sun.COM return (status); 102210491SRishi.Srivatsavai@Sun.COM } 102310491SRishi.Srivatsavai@Sun.COM 102410491SRishi.Srivatsavai@Sun.COM /* 102510491SRishi.Srivatsavai@Sun.COM * Enable a newly-created bridge in SMF by creating "general/enabled" and 102610491SRishi.Srivatsavai@Sun.COM * deleting any "general_ovr/enabled" (used for temporary services). 102710491SRishi.Srivatsavai@Sun.COM */ 102810491SRishi.Srivatsavai@Sun.COM dladm_status_t 102910491SRishi.Srivatsavai@Sun.COM dladm_bridge_enable(const char *name) 103010491SRishi.Srivatsavai@Sun.COM { 103110491SRishi.Srivatsavai@Sun.COM return (enable_instance(BRIDGE_SVC_NAME, name)); 103210491SRishi.Srivatsavai@Sun.COM } 103310491SRishi.Srivatsavai@Sun.COM 103410491SRishi.Srivatsavai@Sun.COM /* 103510491SRishi.Srivatsavai@Sun.COM * Set a link as a member of a bridge, or remove bridge membership. If the 103610491SRishi.Srivatsavai@Sun.COM * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running. 103710491SRishi.Srivatsavai@Sun.COM * In all other cases, we must tell the daemon to add or delete the link in 103810491SRishi.Srivatsavai@Sun.COM * order to stay in sync. 103910491SRishi.Srivatsavai@Sun.COM */ 104010491SRishi.Srivatsavai@Sun.COM dladm_status_t 104110491SRishi.Srivatsavai@Sun.COM dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid, 104210491SRishi.Srivatsavai@Sun.COM const char *bridge) 104310491SRishi.Srivatsavai@Sun.COM { 104410491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 104510491SRishi.Srivatsavai@Sun.COM dladm_conf_t conf; 104610491SRishi.Srivatsavai@Sun.COM char oldbridge[MAXLINKNAMELEN]; 104710491SRishi.Srivatsavai@Sun.COM boolean_t has_oldbridge; 104810491SRishi.Srivatsavai@Sun.COM boolean_t changed = B_FALSE; 104910491SRishi.Srivatsavai@Sun.COM 105010491SRishi.Srivatsavai@Sun.COM if (*bridge != '\0' && !dladm_valid_bridgename(bridge)) 105110491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_FAILED); 105210491SRishi.Srivatsavai@Sun.COM 105310491SRishi.Srivatsavai@Sun.COM if ((status = dladm_read_conf(handle, linkid, &conf)) != 105410491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) 105510491SRishi.Srivatsavai@Sun.COM return (status); 105610491SRishi.Srivatsavai@Sun.COM 105710491SRishi.Srivatsavai@Sun.COM has_oldbridge = B_FALSE; 105810491SRishi.Srivatsavai@Sun.COM status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge, 105910491SRishi.Srivatsavai@Sun.COM sizeof (oldbridge)); 106010491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) { 106110491SRishi.Srivatsavai@Sun.COM /* 106210491SRishi.Srivatsavai@Sun.COM * Don't allow a link to be reassigned directly from one bridge 106310491SRishi.Srivatsavai@Sun.COM * to another. It must be removed first. 106410491SRishi.Srivatsavai@Sun.COM */ 106510491SRishi.Srivatsavai@Sun.COM if (*oldbridge != '\0' && *bridge != '\0') { 106610491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_EXIST; 106710491SRishi.Srivatsavai@Sun.COM goto out; 106810491SRishi.Srivatsavai@Sun.COM } 106910491SRishi.Srivatsavai@Sun.COM has_oldbridge = B_TRUE; 107010491SRishi.Srivatsavai@Sun.COM } else if (status != DLADM_STATUS_NOTFOUND) { 107110491SRishi.Srivatsavai@Sun.COM goto out; 107210491SRishi.Srivatsavai@Sun.COM } 107310491SRishi.Srivatsavai@Sun.COM 107410491SRishi.Srivatsavai@Sun.COM if (*bridge != '\0') { 107510491SRishi.Srivatsavai@Sun.COM status = dladm_set_conf_field(handle, conf, FBRIDGE, 107610491SRishi.Srivatsavai@Sun.COM DLADM_TYPE_STR, bridge); 107710491SRishi.Srivatsavai@Sun.COM changed = B_TRUE; 107810491SRishi.Srivatsavai@Sun.COM } else if (has_oldbridge) { 107910491SRishi.Srivatsavai@Sun.COM status = dladm_unset_conf_field(handle, conf, FBRIDGE); 108010491SRishi.Srivatsavai@Sun.COM changed = B_TRUE; 108110491SRishi.Srivatsavai@Sun.COM } else { 108210491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_OK; 108310491SRishi.Srivatsavai@Sun.COM goto out; 108410491SRishi.Srivatsavai@Sun.COM } 108510491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) 108610491SRishi.Srivatsavai@Sun.COM status = dladm_write_conf(handle, conf); 108710491SRishi.Srivatsavai@Sun.COM 108810491SRishi.Srivatsavai@Sun.COM out: 108910491SRishi.Srivatsavai@Sun.COM dladm_destroy_conf(handle, conf); 109010491SRishi.Srivatsavai@Sun.COM if (changed && status == DLADM_STATUS_OK) { 109110491SRishi.Srivatsavai@Sun.COM if (bridge[0] == '\0') 109210491SRishi.Srivatsavai@Sun.COM bridge = oldbridge; 109310491SRishi.Srivatsavai@Sun.COM status = bridge_refresh(bridge); 109410491SRishi.Srivatsavai@Sun.COM } 109510491SRishi.Srivatsavai@Sun.COM return (status); 109610491SRishi.Srivatsavai@Sun.COM } 109710491SRishi.Srivatsavai@Sun.COM 109810491SRishi.Srivatsavai@Sun.COM /* 109910491SRishi.Srivatsavai@Sun.COM * Get the name of the bridge of which the given linkid is a member. 110010491SRishi.Srivatsavai@Sun.COM */ 110110491SRishi.Srivatsavai@Sun.COM dladm_status_t 110210491SRishi.Srivatsavai@Sun.COM dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge, 110310491SRishi.Srivatsavai@Sun.COM size_t bridgelen) 110410491SRishi.Srivatsavai@Sun.COM { 110510491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 110610491SRishi.Srivatsavai@Sun.COM dladm_conf_t conf; 110710491SRishi.Srivatsavai@Sun.COM 110810491SRishi.Srivatsavai@Sun.COM if ((status = dladm_read_conf(handle, linkid, &conf)) != 110910491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) 111010491SRishi.Srivatsavai@Sun.COM return (status); 111110491SRishi.Srivatsavai@Sun.COM 111210491SRishi.Srivatsavai@Sun.COM *bridge = '\0'; 111310491SRishi.Srivatsavai@Sun.COM status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen); 111410491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK && *bridge == '\0') 111510491SRishi.Srivatsavai@Sun.COM status = DLADM_STATUS_NOTFOUND; 111610491SRishi.Srivatsavai@Sun.COM 111710491SRishi.Srivatsavai@Sun.COM dladm_destroy_conf(handle, conf); 111810491SRishi.Srivatsavai@Sun.COM return (status); 111910491SRishi.Srivatsavai@Sun.COM } 112010491SRishi.Srivatsavai@Sun.COM 112110491SRishi.Srivatsavai@Sun.COM dladm_status_t 112210491SRishi.Srivatsavai@Sun.COM dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid) 112310491SRishi.Srivatsavai@Sun.COM { 112410491SRishi.Srivatsavai@Sun.COM char bridge[MAXLINKNAMELEN]; 112510491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 112610491SRishi.Srivatsavai@Sun.COM 112710491SRishi.Srivatsavai@Sun.COM status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 112810491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_NOTFOUND) 112910491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_OK); 113010491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) 113110491SRishi.Srivatsavai@Sun.COM status = bridge_refresh(bridge); 113210491SRishi.Srivatsavai@Sun.COM return (status); 113310491SRishi.Srivatsavai@Sun.COM } 113410491SRishi.Srivatsavai@Sun.COM 113510491SRishi.Srivatsavai@Sun.COM typedef struct bridge_held_arg_s { 113610491SRishi.Srivatsavai@Sun.COM const char *bha_bridge; 113710491SRishi.Srivatsavai@Sun.COM boolean_t bha_isheld; 113810491SRishi.Srivatsavai@Sun.COM } bridge_held_arg_t; 113910491SRishi.Srivatsavai@Sun.COM 114010491SRishi.Srivatsavai@Sun.COM static int 114110491SRishi.Srivatsavai@Sun.COM i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 114210491SRishi.Srivatsavai@Sun.COM { 114310491SRishi.Srivatsavai@Sun.COM dladm_status_t status = DLADM_STATUS_FAILED; 114410491SRishi.Srivatsavai@Sun.COM dladm_conf_t conf; 114510491SRishi.Srivatsavai@Sun.COM char bridge[MAXLINKNAMELEN]; 114610491SRishi.Srivatsavai@Sun.COM bridge_held_arg_t *bha = arg; 114710491SRishi.Srivatsavai@Sun.COM 114810491SRishi.Srivatsavai@Sun.COM if ((status = dladm_read_conf(handle, linkid, &conf)) != 114910491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) 115010491SRishi.Srivatsavai@Sun.COM return (DLADM_WALK_CONTINUE); 115110491SRishi.Srivatsavai@Sun.COM status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, 115210491SRishi.Srivatsavai@Sun.COM sizeof (bridge)); 115310491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) { 115410491SRishi.Srivatsavai@Sun.COM bha->bha_isheld = B_TRUE; 115510491SRishi.Srivatsavai@Sun.COM dladm_destroy_conf(handle, conf); 115610491SRishi.Srivatsavai@Sun.COM return (DLADM_WALK_TERMINATE); 115710491SRishi.Srivatsavai@Sun.COM } else { 115810491SRishi.Srivatsavai@Sun.COM dladm_destroy_conf(handle, conf); 115910491SRishi.Srivatsavai@Sun.COM return (DLADM_WALK_CONTINUE); 116010491SRishi.Srivatsavai@Sun.COM } 116110491SRishi.Srivatsavai@Sun.COM } 116210491SRishi.Srivatsavai@Sun.COM 116310491SRishi.Srivatsavai@Sun.COM /* 116410491SRishi.Srivatsavai@Sun.COM * Delete a previously created bridge. 116510491SRishi.Srivatsavai@Sun.COM */ 116610491SRishi.Srivatsavai@Sun.COM dladm_status_t 116710491SRishi.Srivatsavai@Sun.COM dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags) 116810491SRishi.Srivatsavai@Sun.COM { 116910491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid; 117010491SRishi.Srivatsavai@Sun.COM datalink_class_t class; 117110491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 117210491SRishi.Srivatsavai@Sun.COM char linkname[MAXLINKNAMELEN]; 117310491SRishi.Srivatsavai@Sun.COM 117410491SRishi.Srivatsavai@Sun.COM if (!dladm_valid_bridgename(bridge)) 117510491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_LINKINVAL); 117610491SRishi.Srivatsavai@Sun.COM 117710491SRishi.Srivatsavai@Sun.COM /* Get the datalink ID for this bridge */ 117810491SRishi.Srivatsavai@Sun.COM (void) snprintf(linkname, sizeof (linkname), "%s0", bridge); 117910491SRishi.Srivatsavai@Sun.COM if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) != 118010491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) 118110491SRishi.Srivatsavai@Sun.COM linkid = DATALINK_INVALID_LINKID; 118210491SRishi.Srivatsavai@Sun.COM else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 118310491SRishi.Srivatsavai@Sun.COM NULL, 0) != DLADM_STATUS_OK) 118410491SRishi.Srivatsavai@Sun.COM linkid = DATALINK_INVALID_LINKID; 118510491SRishi.Srivatsavai@Sun.COM else if (class != DATALINK_CLASS_BRIDGE) 118610491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_BADARG); 118710491SRishi.Srivatsavai@Sun.COM 118810491SRishi.Srivatsavai@Sun.COM if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID) 118910491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_BADARG); 119010491SRishi.Srivatsavai@Sun.COM 119110491SRishi.Srivatsavai@Sun.COM if (flags & DLADM_OPT_PERSIST) { 119210491SRishi.Srivatsavai@Sun.COM bridge_held_arg_t arg; 119310491SRishi.Srivatsavai@Sun.COM 119410491SRishi.Srivatsavai@Sun.COM arg.bha_bridge = bridge; 119510491SRishi.Srivatsavai@Sun.COM arg.bha_isheld = B_FALSE; 119610491SRishi.Srivatsavai@Sun.COM 119710491SRishi.Srivatsavai@Sun.COM /* 119810491SRishi.Srivatsavai@Sun.COM * See whether there are any persistent links using this 119910491SRishi.Srivatsavai@Sun.COM * bridge. If so, we fail the operation. 120010491SRishi.Srivatsavai@Sun.COM */ 120110491SRishi.Srivatsavai@Sun.COM (void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle, 120210491SRishi.Srivatsavai@Sun.COM &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 120310491SRishi.Srivatsavai@Sun.COM DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET, 120410491SRishi.Srivatsavai@Sun.COM DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 120510491SRishi.Srivatsavai@Sun.COM if (arg.bha_isheld) 120610491SRishi.Srivatsavai@Sun.COM return (DLADM_STATUS_LINKBUSY); 120710491SRishi.Srivatsavai@Sun.COM } 120810491SRishi.Srivatsavai@Sun.COM 120910491SRishi.Srivatsavai@Sun.COM if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK) 121010491SRishi.Srivatsavai@Sun.COM goto out; 121110491SRishi.Srivatsavai@Sun.COM 121210491SRishi.Srivatsavai@Sun.COM /* Disable or remove the SMF instance */ 121310491SRishi.Srivatsavai@Sun.COM status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags); 121410491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 121510491SRishi.Srivatsavai@Sun.COM goto out; 121610491SRishi.Srivatsavai@Sun.COM 121710491SRishi.Srivatsavai@Sun.COM if (flags & DLADM_OPT_ACTIVE) { 121810491SRishi.Srivatsavai@Sun.COM /* 121910491SRishi.Srivatsavai@Sun.COM * Delete ACTIVE linkprop now that daemon is gone. 122010491SRishi.Srivatsavai@Sun.COM */ 122110491SRishi.Srivatsavai@Sun.COM (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 122210491SRishi.Srivatsavai@Sun.COM DLADM_OPT_ACTIVE); 122310491SRishi.Srivatsavai@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, 122410491SRishi.Srivatsavai@Sun.COM DLADM_OPT_ACTIVE); 122510491SRishi.Srivatsavai@Sun.COM } 122610491SRishi.Srivatsavai@Sun.COM 122710491SRishi.Srivatsavai@Sun.COM if (flags & DLADM_OPT_PERSIST) { 122810491SRishi.Srivatsavai@Sun.COM (void) dladm_remove_conf(handle, linkid); 122910491SRishi.Srivatsavai@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, 123010491SRishi.Srivatsavai@Sun.COM DLADM_OPT_PERSIST); 123110491SRishi.Srivatsavai@Sun.COM } 123210491SRishi.Srivatsavai@Sun.COM 123310491SRishi.Srivatsavai@Sun.COM out: 123410491SRishi.Srivatsavai@Sun.COM 123510491SRishi.Srivatsavai@Sun.COM return (status); 123610491SRishi.Srivatsavai@Sun.COM } 123710491SRishi.Srivatsavai@Sun.COM 123810491SRishi.Srivatsavai@Sun.COM /* Check if given name is valid for bridges */ 123910491SRishi.Srivatsavai@Sun.COM boolean_t 124010491SRishi.Srivatsavai@Sun.COM dladm_valid_bridgename(const char *bridge) 124110491SRishi.Srivatsavai@Sun.COM { 124210491SRishi.Srivatsavai@Sun.COM size_t len = strnlen(bridge, MAXLINKNAMELEN); 124310491SRishi.Srivatsavai@Sun.COM const char *cp; 124410491SRishi.Srivatsavai@Sun.COM 124510491SRishi.Srivatsavai@Sun.COM if (len == MAXLINKNAMELEN) 124610491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 124710491SRishi.Srivatsavai@Sun.COM 124810491SRishi.Srivatsavai@Sun.COM /* 124910491SRishi.Srivatsavai@Sun.COM * The bridge name cannot start or end with a digit. 125010491SRishi.Srivatsavai@Sun.COM */ 125110491SRishi.Srivatsavai@Sun.COM if (isdigit(bridge[0]) || isdigit(bridge[len - 1])) 125210491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 125310491SRishi.Srivatsavai@Sun.COM 125410491SRishi.Srivatsavai@Sun.COM /* 125510491SRishi.Srivatsavai@Sun.COM * The legal characters within a bridge name are: 125610491SRishi.Srivatsavai@Sun.COM * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 125710491SRishi.Srivatsavai@Sun.COM */ 125810491SRishi.Srivatsavai@Sun.COM for (cp = bridge; *cp != '\0'; cp++) { 125910491SRishi.Srivatsavai@Sun.COM if (!isalnum(*cp) && *cp != '_') 126010491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 126110491SRishi.Srivatsavai@Sun.COM } 126210491SRishi.Srivatsavai@Sun.COM 126310491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 126410491SRishi.Srivatsavai@Sun.COM } 126510491SRishi.Srivatsavai@Sun.COM 126610491SRishi.Srivatsavai@Sun.COM /* 126710491SRishi.Srivatsavai@Sun.COM * Convert a bridge-related observability node name back into the name of the 126810491SRishi.Srivatsavai@Sun.COM * bridge. Returns B_FALSE without making changes if the input name is not in 126910491SRishi.Srivatsavai@Sun.COM * a legal format. 127010491SRishi.Srivatsavai@Sun.COM */ 127110491SRishi.Srivatsavai@Sun.COM boolean_t 127210491SRishi.Srivatsavai@Sun.COM dladm_observe_to_bridge(char *link) 127310491SRishi.Srivatsavai@Sun.COM { 127410491SRishi.Srivatsavai@Sun.COM int llen; 127510491SRishi.Srivatsavai@Sun.COM 127610491SRishi.Srivatsavai@Sun.COM llen = strnlen(link, MAXLINKNAMELEN); 127710491SRishi.Srivatsavai@Sun.COM if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2])) 127810491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 127910491SRishi.Srivatsavai@Sun.COM link[llen - 1] = '\0'; 128010491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 128110491SRishi.Srivatsavai@Sun.COM } 128210491SRishi.Srivatsavai@Sun.COM 128310491SRishi.Srivatsavai@Sun.COM /* 128410491SRishi.Srivatsavai@Sun.COM * Get bridge property values from the running daemon and return them in a 128510491SRishi.Srivatsavai@Sun.COM * common structure. 128610491SRishi.Srivatsavai@Sun.COM */ 128710491SRishi.Srivatsavai@Sun.COM dladm_status_t 128810491SRishi.Srivatsavai@Sun.COM dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg, 128910491SRishi.Srivatsavai@Sun.COM dladm_bridge_prot_t *brprotp) 129010491SRishi.Srivatsavai@Sun.COM { 129110491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 129210491SRishi.Srivatsavai@Sun.COM bridge_door_cfg_t bdcf; 129310491SRishi.Srivatsavai@Sun.COM bridge_door_cfg_t *bdcfp = &bdcf; 129410491SRishi.Srivatsavai@Sun.COM size_t buflen = sizeof (bdcf); 129510491SRishi.Srivatsavai@Sun.COM 129610491SRishi.Srivatsavai@Sun.COM status = bridge_door_call(instname, bdcBridgeGetConfig, 129710491SRishi.Srivatsavai@Sun.COM DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE); 129810491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) { 129910491SRishi.Srivatsavai@Sun.COM *smcfg = bdcfp->bdcf_cfg; 130010491SRishi.Srivatsavai@Sun.COM *brprotp = bdcfp->bdcf_prot; 130110491SRishi.Srivatsavai@Sun.COM } else { 130210491SRishi.Srivatsavai@Sun.COM smcfg->field_mask = 0; 130310491SRishi.Srivatsavai@Sun.COM *brprotp = DLADM_BRIDGE_PROT_STP; 130410491SRishi.Srivatsavai@Sun.COM } 130510491SRishi.Srivatsavai@Sun.COM return (status); 130610491SRishi.Srivatsavai@Sun.COM } 130710491SRishi.Srivatsavai@Sun.COM 130810491SRishi.Srivatsavai@Sun.COM /* 130910491SRishi.Srivatsavai@Sun.COM * Get bridge state from the running daemon and return in structure borrowed 131010491SRishi.Srivatsavai@Sun.COM * from librstp. 131110491SRishi.Srivatsavai@Sun.COM */ 131210491SRishi.Srivatsavai@Sun.COM dladm_status_t 131310491SRishi.Srivatsavai@Sun.COM dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep) 131410491SRishi.Srivatsavai@Sun.COM { 131510491SRishi.Srivatsavai@Sun.COM size_t buflen = sizeof (*statep); 131610491SRishi.Srivatsavai@Sun.COM 131710491SRishi.Srivatsavai@Sun.COM return (bridge_door_call(instname, bdcBridgeGetState, 131810491SRishi.Srivatsavai@Sun.COM DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE)); 131910491SRishi.Srivatsavai@Sun.COM } 132010491SRishi.Srivatsavai@Sun.COM 132110491SRishi.Srivatsavai@Sun.COM /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */ 132210491SRishi.Srivatsavai@Sun.COM datalink_id_t * 132310491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_portlist(const char *instname, uint_t *nports) 132410491SRishi.Srivatsavai@Sun.COM { 132510491SRishi.Srivatsavai@Sun.COM size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t); 132610491SRishi.Srivatsavai@Sun.COM int *rbuf; 132710491SRishi.Srivatsavai@Sun.COM 132810491SRishi.Srivatsavai@Sun.COM if ((rbuf = malloc(buflen)) == NULL) 132910491SRishi.Srivatsavai@Sun.COM return (NULL); 133010491SRishi.Srivatsavai@Sun.COM if (bridge_door_call(instname, bdcBridgeGetPorts, 133110491SRishi.Srivatsavai@Sun.COM DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) != 133210491SRishi.Srivatsavai@Sun.COM DLADM_STATUS_OK) { 133310491SRishi.Srivatsavai@Sun.COM free(rbuf); 133410491SRishi.Srivatsavai@Sun.COM return (NULL); 133510491SRishi.Srivatsavai@Sun.COM } else { 133610491SRishi.Srivatsavai@Sun.COM /* 133710491SRishi.Srivatsavai@Sun.COM * Returns an array of datalink_id_t values for all the ports 133810491SRishi.Srivatsavai@Sun.COM * part of the bridge instance. First entry in the array is the 133910491SRishi.Srivatsavai@Sun.COM * number of ports. 134010491SRishi.Srivatsavai@Sun.COM */ 134110491SRishi.Srivatsavai@Sun.COM *nports = *rbuf; 134210491SRishi.Srivatsavai@Sun.COM return ((datalink_id_t *)(rbuf + 1)); 134310491SRishi.Srivatsavai@Sun.COM } 134410491SRishi.Srivatsavai@Sun.COM } 134510491SRishi.Srivatsavai@Sun.COM 134610491SRishi.Srivatsavai@Sun.COM void 134710491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_portlist(datalink_id_t *dlp) 134810491SRishi.Srivatsavai@Sun.COM { 134910491SRishi.Srivatsavai@Sun.COM free((int *)dlp - 1); 135010491SRishi.Srivatsavai@Sun.COM } 135110491SRishi.Srivatsavai@Sun.COM 135210491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge port configuration values */ 135310491SRishi.Srivatsavai@Sun.COM dladm_status_t 135410491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid, 135510491SRishi.Srivatsavai@Sun.COM int field, int *valuep) 135610491SRishi.Srivatsavai@Sun.COM { 135710491SRishi.Srivatsavai@Sun.COM UID_STP_PORT_CFG_T portcfg; 135810491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 135910491SRishi.Srivatsavai@Sun.COM 136010491SRishi.Srivatsavai@Sun.COM status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg, 136110491SRishi.Srivatsavai@Sun.COM 0, sizeof (portcfg)); 136210491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 136310491SRishi.Srivatsavai@Sun.COM return (status); 136410491SRishi.Srivatsavai@Sun.COM 136510491SRishi.Srivatsavai@Sun.COM switch (field) { 136610491SRishi.Srivatsavai@Sun.COM case PT_CFG_COST: 136710491SRishi.Srivatsavai@Sun.COM *valuep = portcfg.admin_port_path_cost; 136810491SRishi.Srivatsavai@Sun.COM break; 136910491SRishi.Srivatsavai@Sun.COM case PT_CFG_PRIO: 137010491SRishi.Srivatsavai@Sun.COM *valuep = portcfg.port_priority; 137110491SRishi.Srivatsavai@Sun.COM break; 137210491SRishi.Srivatsavai@Sun.COM case PT_CFG_P2P: 137310491SRishi.Srivatsavai@Sun.COM *valuep = portcfg.admin_point2point; 137410491SRishi.Srivatsavai@Sun.COM break; 137510491SRishi.Srivatsavai@Sun.COM case PT_CFG_EDGE: 137610491SRishi.Srivatsavai@Sun.COM *valuep = portcfg.admin_edge; 137710491SRishi.Srivatsavai@Sun.COM break; 137810491SRishi.Srivatsavai@Sun.COM case PT_CFG_NON_STP: 137910491SRishi.Srivatsavai@Sun.COM *valuep = !portcfg.admin_non_stp; 138010491SRishi.Srivatsavai@Sun.COM break; 138110491SRishi.Srivatsavai@Sun.COM case PT_CFG_MCHECK: 138210491SRishi.Srivatsavai@Sun.COM *valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0; 138310491SRishi.Srivatsavai@Sun.COM break; 138410491SRishi.Srivatsavai@Sun.COM } 138510491SRishi.Srivatsavai@Sun.COM return (status); 138610491SRishi.Srivatsavai@Sun.COM } 138710491SRishi.Srivatsavai@Sun.COM 138810491SRishi.Srivatsavai@Sun.COM /* Retreive Bridge port status (disabled, bad SDU etc.) */ 138910491SRishi.Srivatsavai@Sun.COM dladm_status_t 139010491SRishi.Srivatsavai@Sun.COM dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid, 139110491SRishi.Srivatsavai@Sun.COM UID_STP_PORT_STATE_T *spsp) 139210491SRishi.Srivatsavai@Sun.COM { 139310491SRishi.Srivatsavai@Sun.COM return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0, 139410491SRishi.Srivatsavai@Sun.COM sizeof (*spsp))); 139510491SRishi.Srivatsavai@Sun.COM } 139610491SRishi.Srivatsavai@Sun.COM 139710491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge forwarding status of the given link */ 139810491SRishi.Srivatsavai@Sun.COM dladm_status_t 139910491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid, 140010491SRishi.Srivatsavai@Sun.COM uint_t *valuep) 140110491SRishi.Srivatsavai@Sun.COM { 140210491SRishi.Srivatsavai@Sun.COM int twoints[2]; 140310491SRishi.Srivatsavai@Sun.COM dladm_status_t status; 140410491SRishi.Srivatsavai@Sun.COM 140510491SRishi.Srivatsavai@Sun.COM status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints, 140610491SRishi.Srivatsavai@Sun.COM 0, sizeof (twoints)); 140710491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) 140810491SRishi.Srivatsavai@Sun.COM *valuep = twoints[0]; 140910491SRishi.Srivatsavai@Sun.COM return (status); 141010491SRishi.Srivatsavai@Sun.COM } 141110491SRishi.Srivatsavai@Sun.COM 141210491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge forwarding table entries */ 141310491SRishi.Srivatsavai@Sun.COM bridge_listfwd_t * 141410491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge, 141510491SRishi.Srivatsavai@Sun.COM uint_t *nfwd) 141610491SRishi.Srivatsavai@Sun.COM { 141710491SRishi.Srivatsavai@Sun.COM bridge_listfwd_t *blf = NULL, *newblf, blfread; 141810491SRishi.Srivatsavai@Sun.COM uint_t nblf = 0, maxblf = 0; 141910491SRishi.Srivatsavai@Sun.COM static uint8_t zero_addr[ETHERADDRL]; 142010491SRishi.Srivatsavai@Sun.COM int rc; 142110491SRishi.Srivatsavai@Sun.COM 142210491SRishi.Srivatsavai@Sun.COM (void) memset(&blfread, 0, sizeof (blfread)); 142310491SRishi.Srivatsavai@Sun.COM (void) snprintf(blfread.blf_name, sizeof (blfread.blf_name), 142410491SRishi.Srivatsavai@Sun.COM "%s0", bridge); 142510491SRishi.Srivatsavai@Sun.COM for (;;) { 142610491SRishi.Srivatsavai@Sun.COM if (nblf >= maxblf) { 142710491SRishi.Srivatsavai@Sun.COM maxblf = maxblf == 0 ? 64 : (maxblf << 1); 142810491SRishi.Srivatsavai@Sun.COM newblf = realloc(blf, maxblf * sizeof (*blf)); 142910491SRishi.Srivatsavai@Sun.COM if (newblf == NULL) { 143010491SRishi.Srivatsavai@Sun.COM free(blf); 143110491SRishi.Srivatsavai@Sun.COM blf = NULL; 143210491SRishi.Srivatsavai@Sun.COM break; 143310491SRishi.Srivatsavai@Sun.COM } 143410491SRishi.Srivatsavai@Sun.COM blf = newblf; 143510491SRishi.Srivatsavai@Sun.COM } 143610491SRishi.Srivatsavai@Sun.COM rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread); 143710491SRishi.Srivatsavai@Sun.COM if (rc != 0) { 143810491SRishi.Srivatsavai@Sun.COM free(blf); 143910491SRishi.Srivatsavai@Sun.COM blf = NULL; 144010491SRishi.Srivatsavai@Sun.COM break; 144110491SRishi.Srivatsavai@Sun.COM } 144210491SRishi.Srivatsavai@Sun.COM if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0) 144310491SRishi.Srivatsavai@Sun.COM break; 144410491SRishi.Srivatsavai@Sun.COM blf[nblf++] = blfread; 144510491SRishi.Srivatsavai@Sun.COM } 144610491SRishi.Srivatsavai@Sun.COM if (blf != NULL) 144710491SRishi.Srivatsavai@Sun.COM *nfwd = nblf; 144810491SRishi.Srivatsavai@Sun.COM return (blf); 144910491SRishi.Srivatsavai@Sun.COM } 145010491SRishi.Srivatsavai@Sun.COM 145110491SRishi.Srivatsavai@Sun.COM void 145210491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_fwdtable(bridge_listfwd_t *blf) 145310491SRishi.Srivatsavai@Sun.COM { 145410491SRishi.Srivatsavai@Sun.COM free(blf); 145510491SRishi.Srivatsavai@Sun.COM } 145610491SRishi.Srivatsavai@Sun.COM 145710491SRishi.Srivatsavai@Sun.COM /* Retrieve list of TRILL nicknames from the TRILL module */ 145810491SRishi.Srivatsavai@Sun.COM trill_listnick_t * 145910491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick) 146010491SRishi.Srivatsavai@Sun.COM { 146110491SRishi.Srivatsavai@Sun.COM int fd; 146210491SRishi.Srivatsavai@Sun.COM char brcopy[MAXLINKNAMELEN]; 146310491SRishi.Srivatsavai@Sun.COM trill_listnick_t *tln = NULL, *newtln, tlnread; 146410491SRishi.Srivatsavai@Sun.COM uint_t ntln = 0, maxtln = 0; 146510491SRishi.Srivatsavai@Sun.COM 146610491SRishi.Srivatsavai@Sun.COM if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1) 146710491SRishi.Srivatsavai@Sun.COM return (NULL); 146810491SRishi.Srivatsavai@Sun.COM (void) strlcpy(brcopy, bridge, sizeof (brcopy)); 146910491SRishi.Srivatsavai@Sun.COM if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) { 147010491SRishi.Srivatsavai@Sun.COM (void) close(fd); 147110491SRishi.Srivatsavai@Sun.COM return (NULL); 147210491SRishi.Srivatsavai@Sun.COM } 147310491SRishi.Srivatsavai@Sun.COM (void) memset(&tlnread, 0, sizeof (tlnread)); 147410491SRishi.Srivatsavai@Sun.COM for (;;) { 147510491SRishi.Srivatsavai@Sun.COM if (ntln >= maxtln) { 147610491SRishi.Srivatsavai@Sun.COM maxtln = maxtln == 0 ? 64 : (maxtln << 1); 147710491SRishi.Srivatsavai@Sun.COM newtln = realloc(tln, maxtln * sizeof (*tln)); 147810491SRishi.Srivatsavai@Sun.COM if (newtln == NULL) { 147910491SRishi.Srivatsavai@Sun.COM free(tln); 148010491SRishi.Srivatsavai@Sun.COM tln = NULL; 148110491SRishi.Srivatsavai@Sun.COM break; 148210491SRishi.Srivatsavai@Sun.COM } 148310491SRishi.Srivatsavai@Sun.COM tln = newtln; 148410491SRishi.Srivatsavai@Sun.COM } 148510491SRishi.Srivatsavai@Sun.COM if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) { 148610491SRishi.Srivatsavai@Sun.COM free(tln); 148710491SRishi.Srivatsavai@Sun.COM tln = NULL; 148810491SRishi.Srivatsavai@Sun.COM break; 148910491SRishi.Srivatsavai@Sun.COM } 149010491SRishi.Srivatsavai@Sun.COM if (tlnread.tln_nick == 0) 149110491SRishi.Srivatsavai@Sun.COM break; 149210491SRishi.Srivatsavai@Sun.COM tln[ntln++] = tlnread; 149310491SRishi.Srivatsavai@Sun.COM } 149410491SRishi.Srivatsavai@Sun.COM (void) close(fd); 149510491SRishi.Srivatsavai@Sun.COM if (tln != NULL) 149610491SRishi.Srivatsavai@Sun.COM *nnick = ntln; 149710491SRishi.Srivatsavai@Sun.COM return (tln); 149810491SRishi.Srivatsavai@Sun.COM } 149910491SRishi.Srivatsavai@Sun.COM 150010491SRishi.Srivatsavai@Sun.COM void 150110491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_trillnick(trill_listnick_t *tln) 150210491SRishi.Srivatsavai@Sun.COM { 150310491SRishi.Srivatsavai@Sun.COM free(tln); 150410491SRishi.Srivatsavai@Sun.COM } 150510491SRishi.Srivatsavai@Sun.COM 150610491SRishi.Srivatsavai@Sun.COM /* Retrieve any stored TRILL nickname from TRILL SMF service */ 150710491SRishi.Srivatsavai@Sun.COM uint16_t 150810491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_nick(const char *bridge) 150910491SRishi.Srivatsavai@Sun.COM { 151010491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 151110491SRishi.Srivatsavai@Sun.COM uint64_t value; 151210491SRishi.Srivatsavai@Sun.COM uint16_t nickname = RBRIDGE_NICKNAME_NONE; 151310491SRishi.Srivatsavai@Sun.COM 151410491SRishi.Srivatsavai@Sun.COM if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0) 151510491SRishi.Srivatsavai@Sun.COM return (nickname); 151610491SRishi.Srivatsavai@Sun.COM 151710491SRishi.Srivatsavai@Sun.COM if (get_composed_properties("config", B_TRUE, &sstate) == 0 && 151810491SRishi.Srivatsavai@Sun.COM get_count("nickname", &sstate, &value) == 0) 151910491SRishi.Srivatsavai@Sun.COM nickname = value; 152010491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 152110491SRishi.Srivatsavai@Sun.COM return (nickname); 152210491SRishi.Srivatsavai@Sun.COM } 152310491SRishi.Srivatsavai@Sun.COM 152410491SRishi.Srivatsavai@Sun.COM /* Stores TRILL nickname in SMF configuraiton for the TRILL service */ 152510491SRishi.Srivatsavai@Sun.COM void 152610491SRishi.Srivatsavai@Sun.COM dladm_bridge_set_nick(const char *bridge, uint16_t nick) 152710491SRishi.Srivatsavai@Sun.COM { 152810491SRishi.Srivatsavai@Sun.COM scf_state_t sstate; 152910491SRishi.Srivatsavai@Sun.COM scf_transaction_t *tran = NULL; 153010491SRishi.Srivatsavai@Sun.COM boolean_t new_pg = B_FALSE; 153110491SRishi.Srivatsavai@Sun.COM int rv = 0; 153210491SRishi.Srivatsavai@Sun.COM char *fmri; 153310491SRishi.Srivatsavai@Sun.COM 153410491SRishi.Srivatsavai@Sun.COM if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK) 153510491SRishi.Srivatsavai@Sun.COM return; 153610491SRishi.Srivatsavai@Sun.COM 153710491SRishi.Srivatsavai@Sun.COM if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) != 153810491SRishi.Srivatsavai@Sun.COM 0) 153910491SRishi.Srivatsavai@Sun.COM goto out; 154010491SRishi.Srivatsavai@Sun.COM if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 154110491SRishi.Srivatsavai@Sun.COM goto out; 154210491SRishi.Srivatsavai@Sun.COM if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 154310491SRishi.Srivatsavai@Sun.COM goto out; 154410491SRishi.Srivatsavai@Sun.COM if (scf_instance_add_pg(sstate.ss_inst, "config", 154510491SRishi.Srivatsavai@Sun.COM SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 154610491SRishi.Srivatsavai@Sun.COM new_pg = B_TRUE; 154710491SRishi.Srivatsavai@Sun.COM } else if (scf_instance_get_pg(sstate.ss_inst, "config", 154810491SRishi.Srivatsavai@Sun.COM sstate.ss_pg) != 0) { 154910491SRishi.Srivatsavai@Sun.COM goto out; 155010491SRishi.Srivatsavai@Sun.COM } 155110491SRishi.Srivatsavai@Sun.COM do { 155210491SRishi.Srivatsavai@Sun.COM if (scf_transaction_start(tran, sstate.ss_pg) != 0) 155310491SRishi.Srivatsavai@Sun.COM goto out; 155410491SRishi.Srivatsavai@Sun.COM if (!set_count_property(sstate.ss_handle, tran, "nickname", 155510491SRishi.Srivatsavai@Sun.COM nick)) 155610491SRishi.Srivatsavai@Sun.COM goto out; 155710491SRishi.Srivatsavai@Sun.COM rv = scf_transaction_commit(tran); 155810491SRishi.Srivatsavai@Sun.COM scf_transaction_reset(tran); 155910491SRishi.Srivatsavai@Sun.COM if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 156010491SRishi.Srivatsavai@Sun.COM goto out; 156110491SRishi.Srivatsavai@Sun.COM } while (rv == 0); 156210491SRishi.Srivatsavai@Sun.COM 156310491SRishi.Srivatsavai@Sun.COM out: 156410491SRishi.Srivatsavai@Sun.COM if (tran != NULL) { 156510491SRishi.Srivatsavai@Sun.COM scf_transaction_destroy_children(tran); 156610491SRishi.Srivatsavai@Sun.COM scf_transaction_destroy(tran); 156710491SRishi.Srivatsavai@Sun.COM } 156810491SRishi.Srivatsavai@Sun.COM 156910491SRishi.Srivatsavai@Sun.COM if (rv != 1 && new_pg) 157010491SRishi.Srivatsavai@Sun.COM (void) scf_pg_delete(sstate.ss_pg); 157110491SRishi.Srivatsavai@Sun.COM 157210491SRishi.Srivatsavai@Sun.COM drop_composed(&sstate); 157310491SRishi.Srivatsavai@Sun.COM shut_down_scf(&sstate); 157410491SRishi.Srivatsavai@Sun.COM if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) { 157510491SRishi.Srivatsavai@Sun.COM (void) smf_refresh_instance(fmri); 157610491SRishi.Srivatsavai@Sun.COM free(fmri); 157710491SRishi.Srivatsavai@Sun.COM } 157810491SRishi.Srivatsavai@Sun.COM } 1579