14eaa4710SRishi Srivatsavai /* 24eaa4710SRishi Srivatsavai * CDDL HEADER START 34eaa4710SRishi Srivatsavai * 44eaa4710SRishi Srivatsavai * The contents of this file are subject to the terms of the 54eaa4710SRishi Srivatsavai * Common Development and Distribution License (the "License"). 64eaa4710SRishi Srivatsavai * You may not use this file except in compliance with the License. 74eaa4710SRishi Srivatsavai * 84eaa4710SRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94eaa4710SRishi Srivatsavai * or http://www.opensolaris.org/os/licensing. 104eaa4710SRishi Srivatsavai * See the License for the specific language governing permissions 114eaa4710SRishi Srivatsavai * and limitations under the License. 124eaa4710SRishi Srivatsavai * 134eaa4710SRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each 144eaa4710SRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154eaa4710SRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the 164eaa4710SRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying 174eaa4710SRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner] 184eaa4710SRishi Srivatsavai * 194eaa4710SRishi Srivatsavai * CDDL HEADER END 204eaa4710SRishi Srivatsavai */ 214eaa4710SRishi Srivatsavai /* 22*32715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 234eaa4710SRishi Srivatsavai */ 244eaa4710SRishi Srivatsavai 254eaa4710SRishi Srivatsavai #include <stdio.h> 264eaa4710SRishi Srivatsavai #include <sys/types.h> 274eaa4710SRishi Srivatsavai #include <string.h> 284eaa4710SRishi Srivatsavai #include <fcntl.h> 294eaa4710SRishi Srivatsavai #include <unistd.h> 304eaa4710SRishi Srivatsavai #include <stropts.h> 314eaa4710SRishi Srivatsavai #include <ctype.h> 324eaa4710SRishi Srivatsavai #include <errno.h> 334eaa4710SRishi Srivatsavai #include <stdlib.h> 344eaa4710SRishi Srivatsavai #include <door.h> 354eaa4710SRishi Srivatsavai #include <sys/mman.h> 364eaa4710SRishi Srivatsavai #include <libscf.h> 374eaa4710SRishi Srivatsavai #include <libscf_priv.h> 384eaa4710SRishi Srivatsavai #include <libdllink.h> 394eaa4710SRishi Srivatsavai #include <libdlbridge.h> 404eaa4710SRishi Srivatsavai #include <libdladm_impl.h> 414eaa4710SRishi Srivatsavai #include <stp_in.h> 424eaa4710SRishi Srivatsavai #include <net/bridge.h> 434eaa4710SRishi Srivatsavai #include <net/trill.h> 444eaa4710SRishi Srivatsavai #include <sys/socket.h> 4556a3cd3dSRishi Srivatsavai #include <sys/dld_ioc.h> 464eaa4710SRishi Srivatsavai 474eaa4710SRishi Srivatsavai /* 484eaa4710SRishi Srivatsavai * Bridge Administration Library. 494eaa4710SRishi Srivatsavai * 504eaa4710SRishi Srivatsavai * This library is used by administration tools such as dladm(1M) to configure 514eaa4710SRishi Srivatsavai * bridges, and by the bridge daemon to retrieve configuration information. 524eaa4710SRishi Srivatsavai */ 534eaa4710SRishi Srivatsavai 544eaa4710SRishi Srivatsavai #define BRIDGE_SVC_NAME "network/bridge" 554eaa4710SRishi Srivatsavai #define TRILL_SVC_NAME "network/routing/trill" 564eaa4710SRishi Srivatsavai 574eaa4710SRishi Srivatsavai #define DEFAULT_TIMEOUT 60000000 584eaa4710SRishi Srivatsavai #define INIT_WAIT_USECS 50000 594eaa4710SRishi Srivatsavai #define MAXPORTS 256 604eaa4710SRishi Srivatsavai 614eaa4710SRishi Srivatsavai typedef struct scf_state { 624eaa4710SRishi Srivatsavai scf_handle_t *ss_handle; 634eaa4710SRishi Srivatsavai scf_instance_t *ss_inst; 644eaa4710SRishi Srivatsavai scf_service_t *ss_svc; 654eaa4710SRishi Srivatsavai scf_snapshot_t *ss_snap; 664eaa4710SRishi Srivatsavai scf_propertygroup_t *ss_pg; 674eaa4710SRishi Srivatsavai scf_property_t *ss_prop; 684eaa4710SRishi Srivatsavai } scf_state_t; 694eaa4710SRishi Srivatsavai 704eaa4710SRishi Srivatsavai static void 714eaa4710SRishi Srivatsavai shut_down_scf(scf_state_t *sstate) 724eaa4710SRishi Srivatsavai { 734eaa4710SRishi Srivatsavai scf_instance_destroy(sstate->ss_inst); 744eaa4710SRishi Srivatsavai (void) scf_handle_unbind(sstate->ss_handle); 754eaa4710SRishi Srivatsavai scf_handle_destroy(sstate->ss_handle); 764eaa4710SRishi Srivatsavai } 774eaa4710SRishi Srivatsavai 784eaa4710SRishi Srivatsavai static char * 794eaa4710SRishi Srivatsavai alloc_fmri(const char *service, const char *instance_name) 804eaa4710SRishi Srivatsavai { 814eaa4710SRishi Srivatsavai ssize_t max_fmri; 824eaa4710SRishi Srivatsavai char *fmri; 834eaa4710SRishi Srivatsavai 844eaa4710SRishi Srivatsavai /* If the limit is unknown, then use an arbitrary value */ 854eaa4710SRishi Srivatsavai if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1) 864eaa4710SRishi Srivatsavai max_fmri = 1024; 874eaa4710SRishi Srivatsavai if ((fmri = malloc(max_fmri)) != NULL) { 884eaa4710SRishi Srivatsavai (void) snprintf(fmri, max_fmri, "svc:/%s:%s", service, 894eaa4710SRishi Srivatsavai instance_name); 904eaa4710SRishi Srivatsavai } 914eaa4710SRishi Srivatsavai return (fmri); 924eaa4710SRishi Srivatsavai } 934eaa4710SRishi Srivatsavai 944eaa4710SRishi Srivatsavai /* 954eaa4710SRishi Srivatsavai * Start up SCF and bind the requested instance alone. 964eaa4710SRishi Srivatsavai */ 974eaa4710SRishi Srivatsavai static int 984eaa4710SRishi Srivatsavai bind_instance(const char *service, const char *instance_name, 994eaa4710SRishi Srivatsavai scf_state_t *sstate) 1004eaa4710SRishi Srivatsavai { 1014eaa4710SRishi Srivatsavai char *fmri = NULL; 1024eaa4710SRishi Srivatsavai 1034eaa4710SRishi Srivatsavai (void) memset(sstate, 0, sizeof (*sstate)); 1044eaa4710SRishi Srivatsavai 1054eaa4710SRishi Srivatsavai if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 1064eaa4710SRishi Srivatsavai return (-1); 1074eaa4710SRishi Srivatsavai 1084eaa4710SRishi Srivatsavai if (scf_handle_bind(sstate->ss_handle) != 0) 1094eaa4710SRishi Srivatsavai goto failure; 1104eaa4710SRishi Srivatsavai sstate->ss_inst = scf_instance_create(sstate->ss_handle); 1114eaa4710SRishi Srivatsavai if (sstate->ss_inst == NULL) 1124eaa4710SRishi Srivatsavai goto failure; 1134eaa4710SRishi Srivatsavai 1144eaa4710SRishi Srivatsavai fmri = alloc_fmri(service, instance_name); 1154eaa4710SRishi Srivatsavai 1164eaa4710SRishi Srivatsavai if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL, 1174eaa4710SRishi Srivatsavai sstate->ss_inst, NULL, NULL, 1184eaa4710SRishi Srivatsavai SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) 1194eaa4710SRishi Srivatsavai goto failure; 1204eaa4710SRishi Srivatsavai free(fmri); 1214eaa4710SRishi Srivatsavai return (0); 1224eaa4710SRishi Srivatsavai 1234eaa4710SRishi Srivatsavai failure: 1244eaa4710SRishi Srivatsavai free(fmri); 1254eaa4710SRishi Srivatsavai shut_down_scf(sstate); 1264eaa4710SRishi Srivatsavai return (-1); 1274eaa4710SRishi Srivatsavai } 1284eaa4710SRishi Srivatsavai 1294eaa4710SRishi Srivatsavai /* 1304eaa4710SRishi Srivatsavai * Start up SCF and an exact FMRI. This is used for creating new instances and 1314eaa4710SRishi Srivatsavai * enable/disable actions. 1324eaa4710SRishi Srivatsavai */ 1334eaa4710SRishi Srivatsavai static dladm_status_t 1344eaa4710SRishi Srivatsavai exact_instance(const char *fmri, scf_state_t *sstate) 1354eaa4710SRishi Srivatsavai { 1364eaa4710SRishi Srivatsavai dladm_status_t status; 1374eaa4710SRishi Srivatsavai 1384eaa4710SRishi Srivatsavai (void) memset(sstate, 0, sizeof (*sstate)); 1394eaa4710SRishi Srivatsavai 1404eaa4710SRishi Srivatsavai if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 1414eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 1424eaa4710SRishi Srivatsavai 1434eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 1444eaa4710SRishi Srivatsavai if (scf_handle_bind(sstate->ss_handle) != 0) 1454eaa4710SRishi Srivatsavai goto failure; 1464eaa4710SRishi Srivatsavai sstate->ss_svc = scf_service_create(sstate->ss_handle); 1474eaa4710SRishi Srivatsavai if (sstate->ss_svc == NULL) 1484eaa4710SRishi Srivatsavai goto failure; 1494eaa4710SRishi Srivatsavai if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, 1504eaa4710SRishi Srivatsavai sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 1514eaa4710SRishi Srivatsavai if (scf_error() == SCF_ERROR_NOT_FOUND) 1524eaa4710SRishi Srivatsavai status = DLADM_STATUS_OPTMISSING; 1534eaa4710SRishi Srivatsavai goto failure; 1544eaa4710SRishi Srivatsavai } 1554eaa4710SRishi Srivatsavai sstate->ss_inst = scf_instance_create(sstate->ss_handle); 1564eaa4710SRishi Srivatsavai if (sstate->ss_inst == NULL) 1574eaa4710SRishi Srivatsavai goto failure; 1584eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 1594eaa4710SRishi Srivatsavai 1604eaa4710SRishi Srivatsavai failure: 1614eaa4710SRishi Srivatsavai shut_down_scf(sstate); 1624eaa4710SRishi Srivatsavai return (status); 1634eaa4710SRishi Srivatsavai } 1644eaa4710SRishi Srivatsavai 1654eaa4710SRishi Srivatsavai static void 1664eaa4710SRishi Srivatsavai drop_composed(scf_state_t *sstate) 1674eaa4710SRishi Srivatsavai { 1684eaa4710SRishi Srivatsavai scf_property_destroy(sstate->ss_prop); 1694eaa4710SRishi Srivatsavai scf_pg_destroy(sstate->ss_pg); 1704eaa4710SRishi Srivatsavai scf_snapshot_destroy(sstate->ss_snap); 1714eaa4710SRishi Srivatsavai } 1724eaa4710SRishi Srivatsavai 1734eaa4710SRishi Srivatsavai /* 1744eaa4710SRishi Srivatsavai * This function sets up a composed view of the configuration information for 1754eaa4710SRishi Srivatsavai * the specified instance. When this is done, the get_property() function 1764eaa4710SRishi Srivatsavai * should be able to return individual parameters. 1774eaa4710SRishi Srivatsavai */ 1784eaa4710SRishi Srivatsavai static int 1794eaa4710SRishi Srivatsavai get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate) 1804eaa4710SRishi Srivatsavai { 1814eaa4710SRishi Srivatsavai sstate->ss_snap = NULL; 1824eaa4710SRishi Srivatsavai sstate->ss_pg = NULL; 1834eaa4710SRishi Srivatsavai sstate->ss_prop = NULL; 1844eaa4710SRishi Srivatsavai 1854eaa4710SRishi Srivatsavai if (snap) { 1864eaa4710SRishi Srivatsavai sstate->ss_snap = scf_snapshot_create(sstate->ss_handle); 1874eaa4710SRishi Srivatsavai if (sstate->ss_snap == NULL) 1884eaa4710SRishi Srivatsavai goto failure; 1894eaa4710SRishi Srivatsavai if (scf_instance_get_snapshot(sstate->ss_inst, "running", 1904eaa4710SRishi Srivatsavai sstate->ss_snap) != 0) 1914eaa4710SRishi Srivatsavai goto failure; 1924eaa4710SRishi Srivatsavai } 1934eaa4710SRishi Srivatsavai if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL) 1944eaa4710SRishi Srivatsavai goto failure; 1954eaa4710SRishi Srivatsavai if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg, 1964eaa4710SRishi Srivatsavai sstate->ss_pg) != 0) 1974eaa4710SRishi Srivatsavai goto failure; 1984eaa4710SRishi Srivatsavai if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) == 1994eaa4710SRishi Srivatsavai NULL) 2004eaa4710SRishi Srivatsavai goto failure; 2014eaa4710SRishi Srivatsavai return (0); 2024eaa4710SRishi Srivatsavai 2034eaa4710SRishi Srivatsavai failure: 2044eaa4710SRishi Srivatsavai drop_composed(sstate); 2054eaa4710SRishi Srivatsavai return (-1); 2064eaa4710SRishi Srivatsavai } 2074eaa4710SRishi Srivatsavai 2084eaa4710SRishi Srivatsavai static int 2094eaa4710SRishi Srivatsavai get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer) 2104eaa4710SRishi Srivatsavai { 2114eaa4710SRishi Srivatsavai scf_value_t *val; 2124eaa4710SRishi Srivatsavai int retv; 2134eaa4710SRishi Srivatsavai 2144eaa4710SRishi Srivatsavai if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 2154eaa4710SRishi Srivatsavai return (-1); 2164eaa4710SRishi Srivatsavai if ((val = scf_value_create(sstate->ss_handle)) == NULL) 2174eaa4710SRishi Srivatsavai return (-1); 2184eaa4710SRishi Srivatsavai 2194eaa4710SRishi Srivatsavai if (scf_property_get_value(sstate->ss_prop, val) == 0 && 2204eaa4710SRishi Srivatsavai scf_value_get_count(val, answer) == 0) 2214eaa4710SRishi Srivatsavai retv = 0; 2224eaa4710SRishi Srivatsavai else 2234eaa4710SRishi Srivatsavai retv = -1; 2244eaa4710SRishi Srivatsavai scf_value_destroy(val); 2254eaa4710SRishi Srivatsavai return (retv); 2264eaa4710SRishi Srivatsavai } 2274eaa4710SRishi Srivatsavai 2284eaa4710SRishi Srivatsavai static int 2294eaa4710SRishi Srivatsavai get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer) 2304eaa4710SRishi Srivatsavai { 2314eaa4710SRishi Srivatsavai scf_value_t *val; 2324eaa4710SRishi Srivatsavai int retv; 2334eaa4710SRishi Srivatsavai uint8_t bval; 2344eaa4710SRishi Srivatsavai 2354eaa4710SRishi Srivatsavai if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 2364eaa4710SRishi Srivatsavai return (-1); 2374eaa4710SRishi Srivatsavai if ((val = scf_value_create(sstate->ss_handle)) == NULL) 2384eaa4710SRishi Srivatsavai return (-1); 2394eaa4710SRishi Srivatsavai 2404eaa4710SRishi Srivatsavai if (scf_property_get_value(sstate->ss_prop, val) == 0 && 2414eaa4710SRishi Srivatsavai scf_value_get_boolean(val, &bval) == 0) { 2424eaa4710SRishi Srivatsavai retv = 0; 2434eaa4710SRishi Srivatsavai *answer = bval != 0; 2444eaa4710SRishi Srivatsavai } else { 2454eaa4710SRishi Srivatsavai retv = -1; 2464eaa4710SRishi Srivatsavai } 2474eaa4710SRishi Srivatsavai scf_value_destroy(val); 2484eaa4710SRishi Srivatsavai return (retv); 2494eaa4710SRishi Srivatsavai } 2504eaa4710SRishi Srivatsavai 2514eaa4710SRishi Srivatsavai static dladm_status_t 2524eaa4710SRishi Srivatsavai bridge_door_call(const char *instname, bridge_door_type_t dtype, 2534eaa4710SRishi Srivatsavai datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp, 2544eaa4710SRishi Srivatsavai boolean_t is_list) 2554eaa4710SRishi Srivatsavai { 2564eaa4710SRishi Srivatsavai char doorname[MAXPATHLEN]; 2574eaa4710SRishi Srivatsavai int did, retv, etmp; 2584eaa4710SRishi Srivatsavai bridge_door_cmd_t *bdc; 2594eaa4710SRishi Srivatsavai door_arg_t arg; 2604eaa4710SRishi Srivatsavai 2614eaa4710SRishi Srivatsavai (void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME, 2624eaa4710SRishi Srivatsavai instname); 2634eaa4710SRishi Srivatsavai 2644eaa4710SRishi Srivatsavai /* Knock on the door */ 2654eaa4710SRishi Srivatsavai did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK); 2664eaa4710SRishi Srivatsavai if (did == -1) 2674eaa4710SRishi Srivatsavai return (dladm_errno2status(errno)); 2684eaa4710SRishi Srivatsavai 2694eaa4710SRishi Srivatsavai if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) { 2704eaa4710SRishi Srivatsavai (void) close(did); 2714eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 2724eaa4710SRishi Srivatsavai } 2734eaa4710SRishi Srivatsavai bdc->bdc_type = dtype; 2744eaa4710SRishi Srivatsavai bdc->bdc_linkid = linkid; 2754eaa4710SRishi Srivatsavai if (inlen != 0) 2764eaa4710SRishi Srivatsavai (void) memcpy(bdc + 1, *bufp, inlen); 2774eaa4710SRishi Srivatsavai 2784eaa4710SRishi Srivatsavai (void) memset(&arg, 0, sizeof (arg)); 2794eaa4710SRishi Srivatsavai arg.data_ptr = (char *)bdc; 2804eaa4710SRishi Srivatsavai arg.data_size = sizeof (*bdc) + inlen; 2814eaa4710SRishi Srivatsavai arg.rbuf = *bufp; 2824eaa4710SRishi Srivatsavai arg.rsize = *buflenp; 2834eaa4710SRishi Srivatsavai 2844eaa4710SRishi Srivatsavai /* The door_call function doesn't restart, so take care of that */ 2854eaa4710SRishi Srivatsavai do { 2864eaa4710SRishi Srivatsavai errno = 0; 2874eaa4710SRishi Srivatsavai if ((retv = door_call(did, &arg)) == 0) 2884eaa4710SRishi Srivatsavai break; 2894eaa4710SRishi Srivatsavai } while (errno == EINTR); 2904eaa4710SRishi Srivatsavai 2914eaa4710SRishi Srivatsavai /* If we get an unexpected response, then return an error */ 2924eaa4710SRishi Srivatsavai if (retv == 0) { 2934eaa4710SRishi Srivatsavai /* The daemon returns a single int for errors */ 2944eaa4710SRishi Srivatsavai /* LINTED: pointer alignment */ 2954eaa4710SRishi Srivatsavai if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) { 2964eaa4710SRishi Srivatsavai retv = -1; 2974eaa4710SRishi Srivatsavai /* LINTED: pointer alignment */ 2984eaa4710SRishi Srivatsavai errno = *(int *)arg.rbuf; 2994eaa4710SRishi Srivatsavai } 3004eaa4710SRishi Srivatsavai /* Terminated daemon returns with zero data */ 3014eaa4710SRishi Srivatsavai if (arg.data_size == 0) { 3024eaa4710SRishi Srivatsavai retv = -1; 3034eaa4710SRishi Srivatsavai errno = EBADF; 3044eaa4710SRishi Srivatsavai } 3054eaa4710SRishi Srivatsavai } 3064eaa4710SRishi Srivatsavai 3074eaa4710SRishi Srivatsavai if (retv == 0) { 3084eaa4710SRishi Srivatsavai if (arg.rbuf != *bufp) { 3094eaa4710SRishi Srivatsavai if (is_list) { 3104eaa4710SRishi Srivatsavai void *newp; 3114eaa4710SRishi Srivatsavai 3124eaa4710SRishi Srivatsavai newp = realloc(*bufp, arg.data_size); 3134eaa4710SRishi Srivatsavai if (newp == NULL) { 3144eaa4710SRishi Srivatsavai retv = -1; 3154eaa4710SRishi Srivatsavai } else { 3164eaa4710SRishi Srivatsavai *bufp = newp; 3174eaa4710SRishi Srivatsavai (void) memcpy(*bufp, arg.rbuf, 3184eaa4710SRishi Srivatsavai arg.data_size); 3194eaa4710SRishi Srivatsavai } 3204eaa4710SRishi Srivatsavai } 3214eaa4710SRishi Srivatsavai (void) munmap(arg.rbuf, arg.rsize); 3224eaa4710SRishi Srivatsavai } 3234eaa4710SRishi Srivatsavai if (is_list) { 3244eaa4710SRishi Srivatsavai *buflenp = arg.data_size; 3254eaa4710SRishi Srivatsavai } else if (arg.data_size != *buflenp || arg.rbuf != *bufp) { 3264eaa4710SRishi Srivatsavai errno = EINVAL; 3274eaa4710SRishi Srivatsavai retv = -1; 3284eaa4710SRishi Srivatsavai } 3294eaa4710SRishi Srivatsavai } 3304eaa4710SRishi Srivatsavai 3314eaa4710SRishi Srivatsavai etmp = errno; 3324eaa4710SRishi Srivatsavai (void) close(did); 3334eaa4710SRishi Srivatsavai 3344eaa4710SRishi Srivatsavai /* Revoked door is the same as no door at all */ 3354eaa4710SRishi Srivatsavai if (etmp == EBADF) 3364eaa4710SRishi Srivatsavai etmp = ENOENT; 3374eaa4710SRishi Srivatsavai 3384eaa4710SRishi Srivatsavai return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp)); 3394eaa4710SRishi Srivatsavai } 3404eaa4710SRishi Srivatsavai 3414eaa4710SRishi Srivatsavai /* 3424eaa4710SRishi Srivatsavai * Wrapper function for making per-port calls. 3434eaa4710SRishi Srivatsavai */ 3444eaa4710SRishi Srivatsavai static dladm_status_t 3454eaa4710SRishi Srivatsavai port_door_call(dladm_handle_t handle, datalink_id_t linkid, 3464eaa4710SRishi Srivatsavai bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen) 3474eaa4710SRishi Srivatsavai { 3484eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 3494eaa4710SRishi Srivatsavai dladm_status_t status; 3504eaa4710SRishi Srivatsavai 3514eaa4710SRishi Srivatsavai status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 3524eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 3534eaa4710SRishi Srivatsavai return (status); 3544eaa4710SRishi Srivatsavai return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen, 3554eaa4710SRishi Srivatsavai B_FALSE)); 3564eaa4710SRishi Srivatsavai } 3574eaa4710SRishi Srivatsavai 3584eaa4710SRishi Srivatsavai static dladm_status_t 3594eaa4710SRishi Srivatsavai bridge_refresh(const char *bridge) 3604eaa4710SRishi Srivatsavai { 3614eaa4710SRishi Srivatsavai dladm_status_t status; 3624eaa4710SRishi Srivatsavai int twoints[2]; 3634eaa4710SRishi Srivatsavai void *bdptr; 3644eaa4710SRishi Srivatsavai size_t buflen; 3654eaa4710SRishi Srivatsavai char *fmri; 3664eaa4710SRishi Srivatsavai int refresh_count; 3674eaa4710SRishi Srivatsavai 3684eaa4710SRishi Srivatsavai buflen = sizeof (twoints); 3694eaa4710SRishi Srivatsavai bdptr = twoints; 3704eaa4710SRishi Srivatsavai status = bridge_door_call(bridge, bdcBridgeGetRefreshCount, 3714eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE); 3724eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_NOTFOUND) 3734eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 3744eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 3754eaa4710SRishi Srivatsavai return (status); 3764eaa4710SRishi Srivatsavai refresh_count = twoints[0]; 3774eaa4710SRishi Srivatsavai if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL) 3784eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 3794eaa4710SRishi Srivatsavai status = smf_refresh_instance(fmri) == 0 ? 3804eaa4710SRishi Srivatsavai DLADM_STATUS_OK : DLADM_STATUS_FAILED; 3814eaa4710SRishi Srivatsavai free(fmri); 3824eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 3834eaa4710SRishi Srivatsavai int i = 0; 3844eaa4710SRishi Srivatsavai 3854eaa4710SRishi Srivatsavai /* 3864eaa4710SRishi Srivatsavai * SMF doesn't give any synchronous behavior or dependency 3874eaa4710SRishi Srivatsavai * ordering for refresh operations, so we have to invent our 3884eaa4710SRishi Srivatsavai * own mechanism here. Get the refresh counter from the 3894eaa4710SRishi Srivatsavai * daemon, and wait for it to change. It's not pretty, but 3904eaa4710SRishi Srivatsavai * it's sufficient. 3914eaa4710SRishi Srivatsavai */ 3924eaa4710SRishi Srivatsavai while (++i <= 10) { 3934eaa4710SRishi Srivatsavai buflen = sizeof (twoints); 3944eaa4710SRishi Srivatsavai bdptr = twoints; 3954eaa4710SRishi Srivatsavai status = bridge_door_call(bridge, 3964eaa4710SRishi Srivatsavai bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID, 3974eaa4710SRishi Srivatsavai &bdptr, 0, &buflen, B_FALSE); 3984eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 3994eaa4710SRishi Srivatsavai break; 4004eaa4710SRishi Srivatsavai if (twoints[0] != refresh_count) 4014eaa4710SRishi Srivatsavai break; 4024eaa4710SRishi Srivatsavai (void) usleep(100000); 4034eaa4710SRishi Srivatsavai } 4044eaa4710SRishi Srivatsavai fmri = alloc_fmri(TRILL_SVC_NAME, bridge); 4054eaa4710SRishi Srivatsavai if (fmri == NULL) 4064eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 4074eaa4710SRishi Srivatsavai status = smf_refresh_instance(fmri) == 0 || 4084eaa4710SRishi Srivatsavai scf_error() == SCF_ERROR_NOT_FOUND ? 4094eaa4710SRishi Srivatsavai DLADM_STATUS_OK : DLADM_STATUS_FAILED; 4104eaa4710SRishi Srivatsavai free(fmri); 4114eaa4710SRishi Srivatsavai } 4124eaa4710SRishi Srivatsavai return (status); 4134eaa4710SRishi Srivatsavai } 4144eaa4710SRishi Srivatsavai 4154eaa4710SRishi Srivatsavai /* 4164eaa4710SRishi Srivatsavai * Look up bridge property values from SCF and return them. 4174eaa4710SRishi Srivatsavai */ 4184eaa4710SRishi Srivatsavai dladm_status_t 4194eaa4710SRishi Srivatsavai dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg, 4204eaa4710SRishi Srivatsavai dladm_bridge_prot_t *brprotp) 4214eaa4710SRishi Srivatsavai { 4224eaa4710SRishi Srivatsavai scf_state_t sstate; 4234eaa4710SRishi Srivatsavai uint64_t value; 4244eaa4710SRishi Srivatsavai boolean_t trill_enabled; 4254eaa4710SRishi Srivatsavai 4264eaa4710SRishi Srivatsavai cfg->field_mask = 0; 4274eaa4710SRishi Srivatsavai cfg->bridge_priority = DEF_BR_PRIO; 4284eaa4710SRishi Srivatsavai cfg->max_age = DEF_BR_MAXAGE; 4294eaa4710SRishi Srivatsavai cfg->hello_time = DEF_BR_HELLOT; 4304eaa4710SRishi Srivatsavai cfg->forward_delay = DEF_BR_FWDELAY; 4314eaa4710SRishi Srivatsavai cfg->force_version = DEF_FORCE_VERS; 4324eaa4710SRishi Srivatsavai 4334eaa4710SRishi Srivatsavai (void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name)); 4344eaa4710SRishi Srivatsavai 4354eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_STP; 4364eaa4710SRishi Srivatsavai 4374eaa4710SRishi Srivatsavai /* It's ok for this to be missing; it's installed separately */ 4384eaa4710SRishi Srivatsavai if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) { 4394eaa4710SRishi Srivatsavai trill_enabled = B_FALSE; 4404eaa4710SRishi Srivatsavai if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) == 4414eaa4710SRishi Srivatsavai 0) { 4424eaa4710SRishi Srivatsavai (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 4434eaa4710SRishi Srivatsavai &trill_enabled); 4444eaa4710SRishi Srivatsavai if (trill_enabled) 4454eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_TRILL; 4464eaa4710SRishi Srivatsavai drop_composed(&sstate); 4474eaa4710SRishi Srivatsavai } 4484eaa4710SRishi Srivatsavai if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE, 4494eaa4710SRishi Srivatsavai &sstate) == 0) { 4504eaa4710SRishi Srivatsavai (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 4514eaa4710SRishi Srivatsavai &trill_enabled); 4524eaa4710SRishi Srivatsavai if (trill_enabled) 4534eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_TRILL; 4544eaa4710SRishi Srivatsavai drop_composed(&sstate); 4554eaa4710SRishi Srivatsavai } 4564eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 4574eaa4710SRishi Srivatsavai } 4584eaa4710SRishi Srivatsavai 4594eaa4710SRishi Srivatsavai cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ? 4604eaa4710SRishi Srivatsavai STP_ENABLED : STP_DISABLED; 4614eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_STATE; 4624eaa4710SRishi Srivatsavai 4634eaa4710SRishi Srivatsavai if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 4644eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 4654eaa4710SRishi Srivatsavai 4664eaa4710SRishi Srivatsavai if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 4674eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 4684eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 4694eaa4710SRishi Srivatsavai } 4704eaa4710SRishi Srivatsavai 4714eaa4710SRishi Srivatsavai if (get_count("priority", &sstate, &value) == 0) { 4724eaa4710SRishi Srivatsavai cfg->bridge_priority = value; 4734eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_PRIO; 4744eaa4710SRishi Srivatsavai } 4754eaa4710SRishi Srivatsavai if (get_count("max-age", &sstate, &value) == 0) { 4764eaa4710SRishi Srivatsavai cfg->max_age = value / IEEE_TIMER_SCALE; 4774eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_AGE; 4784eaa4710SRishi Srivatsavai } 4794eaa4710SRishi Srivatsavai if (get_count("hello-time", &sstate, &value) == 0) { 4804eaa4710SRishi Srivatsavai cfg->hello_time = value / IEEE_TIMER_SCALE; 4814eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_HELLO; 4824eaa4710SRishi Srivatsavai } 4834eaa4710SRishi Srivatsavai if (get_count("forward-delay", &sstate, &value) == 0) { 4844eaa4710SRishi Srivatsavai cfg->forward_delay = value / IEEE_TIMER_SCALE; 4854eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_DELAY; 4864eaa4710SRishi Srivatsavai } 4874eaa4710SRishi Srivatsavai if (get_count("force-protocol", &sstate, &value) == 0) { 4884eaa4710SRishi Srivatsavai cfg->force_version = value; 4894eaa4710SRishi Srivatsavai cfg->field_mask |= BR_CFG_FORCE_VER; 4904eaa4710SRishi Srivatsavai } 4914eaa4710SRishi Srivatsavai 4924eaa4710SRishi Srivatsavai drop_composed(&sstate); 4934eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 4944eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 4954eaa4710SRishi Srivatsavai } 4964eaa4710SRishi Srivatsavai 4974eaa4710SRishi Srivatsavai /* 4984eaa4710SRishi Srivatsavai * Retrieve special non-settable and undocumented parameters. 4994eaa4710SRishi Srivatsavai */ 5004eaa4710SRishi Srivatsavai dladm_status_t 5014eaa4710SRishi Srivatsavai dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp, 5024eaa4710SRishi Srivatsavai uint32_t *tablemaxp) 5034eaa4710SRishi Srivatsavai { 5044eaa4710SRishi Srivatsavai scf_state_t sstate; 5054eaa4710SRishi Srivatsavai uint64_t value; 5064eaa4710SRishi Srivatsavai 5074eaa4710SRishi Srivatsavai *debugp = B_FALSE; 5084eaa4710SRishi Srivatsavai *tablemaxp = 10000; 5094eaa4710SRishi Srivatsavai 5104eaa4710SRishi Srivatsavai if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 5114eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 5124eaa4710SRishi Srivatsavai 5134eaa4710SRishi Srivatsavai if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 5144eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 5154eaa4710SRishi Srivatsavai return (DLADM_STATUS_REPOSITORYINVAL); 5164eaa4710SRishi Srivatsavai } 5174eaa4710SRishi Srivatsavai 5184eaa4710SRishi Srivatsavai (void) get_boolean("debug", &sstate, debugp); 5194eaa4710SRishi Srivatsavai if (get_count("table-maximum", &sstate, &value) == 0) 5204eaa4710SRishi Srivatsavai *tablemaxp = (uint32_t)value; 5214eaa4710SRishi Srivatsavai 5224eaa4710SRishi Srivatsavai drop_composed(&sstate); 5234eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 5244eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 5254eaa4710SRishi Srivatsavai } 5264eaa4710SRishi Srivatsavai 5274eaa4710SRishi Srivatsavai static boolean_t 5284eaa4710SRishi Srivatsavai set_count_property(scf_handle_t *handle, scf_transaction_t *tran, 5294eaa4710SRishi Srivatsavai const char *propname, uint64_t propval) 5304eaa4710SRishi Srivatsavai { 5314eaa4710SRishi Srivatsavai scf_transaction_entry_t *entry; 5324eaa4710SRishi Srivatsavai scf_value_t *value = NULL; 5334eaa4710SRishi Srivatsavai 5344eaa4710SRishi Srivatsavai if ((entry = scf_entry_create(handle)) == NULL) 5354eaa4710SRishi Srivatsavai return (B_FALSE); 5364eaa4710SRishi Srivatsavai 5374eaa4710SRishi Srivatsavai if ((value = scf_value_create(handle)) == NULL) 5384eaa4710SRishi Srivatsavai goto out; 5394eaa4710SRishi Srivatsavai if (scf_transaction_property_new(tran, entry, propname, 5404eaa4710SRishi Srivatsavai SCF_TYPE_COUNT) != 0 && 5414eaa4710SRishi Srivatsavai scf_transaction_property_change(tran, entry, propname, 5424eaa4710SRishi Srivatsavai SCF_TYPE_COUNT) != 0) 5434eaa4710SRishi Srivatsavai goto out; 5444eaa4710SRishi Srivatsavai scf_value_set_count(value, propval); 5454eaa4710SRishi Srivatsavai if (scf_entry_add_value(entry, value) == 0) 5464eaa4710SRishi Srivatsavai return (B_TRUE); 5474eaa4710SRishi Srivatsavai 5484eaa4710SRishi Srivatsavai out: 5494eaa4710SRishi Srivatsavai if (value != NULL) 5504eaa4710SRishi Srivatsavai scf_value_destroy(value); 5514eaa4710SRishi Srivatsavai 5524eaa4710SRishi Srivatsavai scf_entry_destroy_children(entry); 5534eaa4710SRishi Srivatsavai scf_entry_destroy(entry); 5544eaa4710SRishi Srivatsavai 5554eaa4710SRishi Srivatsavai return (B_FALSE); 5564eaa4710SRishi Srivatsavai } 5574eaa4710SRishi Srivatsavai 5584eaa4710SRishi Srivatsavai static boolean_t 5594eaa4710SRishi Srivatsavai set_string_property(scf_handle_t *handle, scf_transaction_t *tran, 5604eaa4710SRishi Srivatsavai const char *propname, const char *propval) 5614eaa4710SRishi Srivatsavai { 5624eaa4710SRishi Srivatsavai scf_transaction_entry_t *entry; 5634eaa4710SRishi Srivatsavai scf_value_t *value = NULL; 5644eaa4710SRishi Srivatsavai 5654eaa4710SRishi Srivatsavai if ((entry = scf_entry_create(handle)) == NULL) 5664eaa4710SRishi Srivatsavai return (B_FALSE); 5674eaa4710SRishi Srivatsavai 5684eaa4710SRishi Srivatsavai if ((value = scf_value_create(handle)) == NULL) 5694eaa4710SRishi Srivatsavai goto out; 5704eaa4710SRishi Srivatsavai if (scf_transaction_property_new(tran, entry, propname, 5714eaa4710SRishi Srivatsavai SCF_TYPE_ASTRING) != 0 && 5724eaa4710SRishi Srivatsavai scf_transaction_property_change(tran, entry, propname, 5734eaa4710SRishi Srivatsavai SCF_TYPE_ASTRING) != 0) 5744eaa4710SRishi Srivatsavai goto out; 5754eaa4710SRishi Srivatsavai if (scf_value_set_astring(value, propval) != 0) 5764eaa4710SRishi Srivatsavai goto out; 5774eaa4710SRishi Srivatsavai if (scf_entry_add_value(entry, value) == 0) 5784eaa4710SRishi Srivatsavai return (B_TRUE); 5794eaa4710SRishi Srivatsavai 5804eaa4710SRishi Srivatsavai out: 5814eaa4710SRishi Srivatsavai if (value != NULL) 5824eaa4710SRishi Srivatsavai scf_value_destroy(value); 5834eaa4710SRishi Srivatsavai 5844eaa4710SRishi Srivatsavai scf_entry_destroy_children(entry); 5854eaa4710SRishi Srivatsavai scf_entry_destroy(entry); 5864eaa4710SRishi Srivatsavai 5874eaa4710SRishi Srivatsavai return (B_FALSE); 5884eaa4710SRishi Srivatsavai } 5894eaa4710SRishi Srivatsavai 5904eaa4710SRishi Srivatsavai static boolean_t 5914eaa4710SRishi Srivatsavai set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran, 5924eaa4710SRishi Srivatsavai const char *propname, const char *propval) 5934eaa4710SRishi Srivatsavai { 5944eaa4710SRishi Srivatsavai scf_transaction_entry_t *entry; 5954eaa4710SRishi Srivatsavai scf_value_t *value = NULL; 5964eaa4710SRishi Srivatsavai 5974eaa4710SRishi Srivatsavai if ((entry = scf_entry_create(handle)) == NULL) 5984eaa4710SRishi Srivatsavai return (B_FALSE); 5994eaa4710SRishi Srivatsavai 6004eaa4710SRishi Srivatsavai if ((value = scf_value_create(handle)) == NULL) 6014eaa4710SRishi Srivatsavai goto out; 6024eaa4710SRishi Srivatsavai if (scf_transaction_property_new(tran, entry, propname, 6034eaa4710SRishi Srivatsavai SCF_TYPE_FMRI) != 0 && 6044eaa4710SRishi Srivatsavai scf_transaction_property_change(tran, entry, propname, 6054eaa4710SRishi Srivatsavai SCF_TYPE_FMRI) != 0) 6064eaa4710SRishi Srivatsavai goto out; 6074eaa4710SRishi Srivatsavai if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0) 6084eaa4710SRishi Srivatsavai goto out; 6094eaa4710SRishi Srivatsavai if (scf_entry_add_value(entry, value) == 0) 6104eaa4710SRishi Srivatsavai return (B_TRUE); 6114eaa4710SRishi Srivatsavai 6124eaa4710SRishi Srivatsavai out: 6134eaa4710SRishi Srivatsavai if (value != NULL) 6144eaa4710SRishi Srivatsavai scf_value_destroy(value); 6154eaa4710SRishi Srivatsavai 6164eaa4710SRishi Srivatsavai scf_entry_destroy_children(entry); 6174eaa4710SRishi Srivatsavai scf_entry_destroy(entry); 6184eaa4710SRishi Srivatsavai 6194eaa4710SRishi Srivatsavai return (B_FALSE); 6204eaa4710SRishi Srivatsavai } 6214eaa4710SRishi Srivatsavai 6224eaa4710SRishi Srivatsavai static dladm_status_t 6234eaa4710SRishi Srivatsavai dladm_bridge_persist_conf(dladm_handle_t handle, const char *link, 6244eaa4710SRishi Srivatsavai datalink_id_t linkid) 6254eaa4710SRishi Srivatsavai { 626*32715170SCathy Zhou dladm_conf_t conf; 6274eaa4710SRishi Srivatsavai dladm_status_t status; 6284eaa4710SRishi Srivatsavai 6294eaa4710SRishi Srivatsavai status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE, 6304eaa4710SRishi Srivatsavai DL_ETHER, &conf); 6314eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 6324eaa4710SRishi Srivatsavai /* 6334eaa4710SRishi Srivatsavai * Create the datalink entry for the bridge. Note that all of 6344eaa4710SRishi Srivatsavai * the real configuration information is in SMF. 6354eaa4710SRishi Srivatsavai */ 6364eaa4710SRishi Srivatsavai status = dladm_write_conf(handle, conf); 6374eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 6384eaa4710SRishi Srivatsavai } 6394eaa4710SRishi Srivatsavai return (status); 6404eaa4710SRishi Srivatsavai } 6414eaa4710SRishi Srivatsavai 6424eaa4710SRishi Srivatsavai /* Convert bridge protection option string to dladm_bridge_prot_t */ 6434eaa4710SRishi Srivatsavai dladm_status_t 6444eaa4710SRishi Srivatsavai dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp) 6454eaa4710SRishi Srivatsavai { 6464eaa4710SRishi Srivatsavai if (strcmp(str, "stp") == 0) 6474eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_STP; 6484eaa4710SRishi Srivatsavai else if (strcmp(str, "trill") == 0) 6494eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_TRILL; 6504eaa4710SRishi Srivatsavai else 6514eaa4710SRishi Srivatsavai return (DLADM_STATUS_BADARG); 6524eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 6534eaa4710SRishi Srivatsavai } 6544eaa4710SRishi Srivatsavai 6554eaa4710SRishi Srivatsavai /* Convert bridge protection option from dladm_bridge_prot_t to string */ 6564eaa4710SRishi Srivatsavai const char * 6574eaa4710SRishi Srivatsavai dladm_bridge_prot2str(dladm_bridge_prot_t brprot) 6584eaa4710SRishi Srivatsavai { 6594eaa4710SRishi Srivatsavai switch (brprot) { 6604eaa4710SRishi Srivatsavai case DLADM_BRIDGE_PROT_STP: 6614eaa4710SRishi Srivatsavai return ("stp"); 6624eaa4710SRishi Srivatsavai case DLADM_BRIDGE_PROT_TRILL: 6634eaa4710SRishi Srivatsavai return ("trill"); 6644eaa4710SRishi Srivatsavai default: 6654eaa4710SRishi Srivatsavai return ("unknown"); 6664eaa4710SRishi Srivatsavai } 6674eaa4710SRishi Srivatsavai } 6684eaa4710SRishi Srivatsavai 6694eaa4710SRishi Srivatsavai static dladm_status_t 6704eaa4710SRishi Srivatsavai enable_instance(const char *service_name, const char *instance) 6714eaa4710SRishi Srivatsavai { 6724eaa4710SRishi Srivatsavai dladm_status_t status; 6734eaa4710SRishi Srivatsavai char *fmri = alloc_fmri(service_name, instance); 6744eaa4710SRishi Srivatsavai 6754eaa4710SRishi Srivatsavai if (fmri == NULL) 6764eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 6774eaa4710SRishi Srivatsavai status = smf_enable_instance(fmri, 0) == 0 ? 6784eaa4710SRishi Srivatsavai DLADM_STATUS_OK : DLADM_STATUS_FAILED; 6794eaa4710SRishi Srivatsavai free(fmri); 6804eaa4710SRishi Srivatsavai return (status); 6814eaa4710SRishi Srivatsavai } 6824eaa4710SRishi Srivatsavai 6834eaa4710SRishi Srivatsavai /* 6844eaa4710SRishi Srivatsavai * Shut down a possibly-running service instance. If this is a permanent 6854eaa4710SRishi Srivatsavai * change, then delete it from the system. 6864eaa4710SRishi Srivatsavai */ 6874eaa4710SRishi Srivatsavai static dladm_status_t 6884eaa4710SRishi Srivatsavai shut_down_instance(const char *service_name, const char *instance, 6894eaa4710SRishi Srivatsavai uint32_t flags) 6904eaa4710SRishi Srivatsavai { 6914eaa4710SRishi Srivatsavai dladm_status_t status; 6924eaa4710SRishi Srivatsavai char *fmri = alloc_fmri(service_name, instance); 6934eaa4710SRishi Srivatsavai char *state; 6944eaa4710SRishi Srivatsavai scf_state_t sstate; 6954eaa4710SRishi Srivatsavai 6964eaa4710SRishi Srivatsavai if (fmri == NULL) 6974eaa4710SRishi Srivatsavai return (DLADM_STATUS_NOMEM); 6984eaa4710SRishi Srivatsavai 6994eaa4710SRishi Srivatsavai if (smf_disable_instance(fmri, 7004eaa4710SRishi Srivatsavai flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) { 7014eaa4710SRishi Srivatsavai useconds_t usecs, umax; 7024eaa4710SRishi Srivatsavai 7034eaa4710SRishi Srivatsavai /* If we can disable, then wait for it to happen. */ 7044eaa4710SRishi Srivatsavai umax = DEFAULT_TIMEOUT; 7054eaa4710SRishi Srivatsavai for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) { 7064eaa4710SRishi Srivatsavai state = smf_get_state(fmri); 7074eaa4710SRishi Srivatsavai if (state != NULL && 7084eaa4710SRishi Srivatsavai strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 7094eaa4710SRishi Srivatsavai break; 7104eaa4710SRishi Srivatsavai free(state); 7114eaa4710SRishi Srivatsavai usecs *= 2; 7124eaa4710SRishi Srivatsavai if (usecs > umax) 7134eaa4710SRishi Srivatsavai usecs = umax; 7144eaa4710SRishi Srivatsavai (void) usleep(usecs); 7154eaa4710SRishi Srivatsavai } 7164eaa4710SRishi Srivatsavai if (umax == 0) { 7174eaa4710SRishi Srivatsavai state = smf_get_state(fmri); 7184eaa4710SRishi Srivatsavai if (state != NULL && 7194eaa4710SRishi Srivatsavai strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 7204eaa4710SRishi Srivatsavai umax = 1; 7214eaa4710SRishi Srivatsavai } 7224eaa4710SRishi Srivatsavai free(state); 7234eaa4710SRishi Srivatsavai status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED; 7244eaa4710SRishi Srivatsavai } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 7254eaa4710SRishi Srivatsavai free(fmri); 7264eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 7274eaa4710SRishi Srivatsavai } else { 7284eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 7294eaa4710SRishi Srivatsavai } 7304eaa4710SRishi Srivatsavai 7314eaa4710SRishi Srivatsavai free(fmri); 7324eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) && 7334eaa4710SRishi Srivatsavai bind_instance(service_name, instance, &sstate) == 0) { 7344eaa4710SRishi Srivatsavai (void) scf_instance_delete(sstate.ss_inst); 7354eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 7364eaa4710SRishi Srivatsavai } 7374eaa4710SRishi Srivatsavai 7384eaa4710SRishi Srivatsavai return (status); 7394eaa4710SRishi Srivatsavai } 7404eaa4710SRishi Srivatsavai 7414eaa4710SRishi Srivatsavai static dladm_status_t 7424eaa4710SRishi Srivatsavai disable_trill(const char *instance, uint32_t flags) 7434eaa4710SRishi Srivatsavai { 7444eaa4710SRishi Srivatsavai return (shut_down_instance(TRILL_SVC_NAME, instance, flags)); 7454eaa4710SRishi Srivatsavai } 7464eaa4710SRishi Srivatsavai 7474eaa4710SRishi Srivatsavai /* 7484eaa4710SRishi Srivatsavai * To enable TRILL, we must create a new instance of the TRILL service, then 7494eaa4710SRishi Srivatsavai * add proper dependencies to it, and finally mark it as enabled. The 7504eaa4710SRishi Srivatsavai * dependencies will keep it from going on-line until the bridge is running. 7514eaa4710SRishi Srivatsavai */ 7524eaa4710SRishi Srivatsavai static dladm_status_t 7534eaa4710SRishi Srivatsavai enable_trill(const char *instance) 7544eaa4710SRishi Srivatsavai { 7554eaa4710SRishi Srivatsavai dladm_status_t status = DLADM_STATUS_FAILED; 7564eaa4710SRishi Srivatsavai char *fmri = NULL; 7574eaa4710SRishi Srivatsavai scf_state_t sstate; 7584eaa4710SRishi Srivatsavai scf_transaction_t *tran = NULL; 7594eaa4710SRishi Srivatsavai boolean_t new_instance = B_FALSE; 7604eaa4710SRishi Srivatsavai boolean_t new_pg = B_FALSE; 7614eaa4710SRishi Srivatsavai int rv; 7624eaa4710SRishi Srivatsavai 7634eaa4710SRishi Srivatsavai /* 7644eaa4710SRishi Srivatsavai * This check is here in case the user has installed and then removed 7654eaa4710SRishi Srivatsavai * the package. SMF should remove the manifest, but currently does 7664eaa4710SRishi Srivatsavai * not. 7674eaa4710SRishi Srivatsavai */ 7684eaa4710SRishi Srivatsavai if (access("/usr/sbin/trilld", F_OK) != 0) 7694eaa4710SRishi Srivatsavai return (DLADM_STATUS_OPTMISSING); 7704eaa4710SRishi Srivatsavai 7714eaa4710SRishi Srivatsavai if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) != 7724eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 7734eaa4710SRishi Srivatsavai goto out; 7744eaa4710SRishi Srivatsavai 7754eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 7764eaa4710SRishi Srivatsavai if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) != 7774eaa4710SRishi Srivatsavai 0) { 7784eaa4710SRishi Srivatsavai if (scf_service_add_instance(sstate.ss_svc, instance, 7794eaa4710SRishi Srivatsavai sstate.ss_inst) != 0) 7804eaa4710SRishi Srivatsavai goto out; 7814eaa4710SRishi Srivatsavai new_instance = B_TRUE; 7824eaa4710SRishi Srivatsavai } 7834eaa4710SRishi Srivatsavai 7844eaa4710SRishi Srivatsavai if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 7854eaa4710SRishi Srivatsavai goto out; 7864eaa4710SRishi Srivatsavai 7874eaa4710SRishi Srivatsavai if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 7884eaa4710SRishi Srivatsavai goto out; 7894eaa4710SRishi Srivatsavai 7904eaa4710SRishi Srivatsavai if (scf_instance_get_pg(sstate.ss_inst, "bridging", 7914eaa4710SRishi Srivatsavai sstate.ss_pg) == 0) { 7924eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 7934eaa4710SRishi Srivatsavai goto out; 7944eaa4710SRishi Srivatsavai } 7954eaa4710SRishi Srivatsavai 7964eaa4710SRishi Srivatsavai if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL) 7974eaa4710SRishi Srivatsavai goto out; 7984eaa4710SRishi Srivatsavai 7994eaa4710SRishi Srivatsavai if (scf_instance_add_pg(sstate.ss_inst, "bridging", 8004eaa4710SRishi Srivatsavai SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0) 8014eaa4710SRishi Srivatsavai goto out; 8024eaa4710SRishi Srivatsavai 8034eaa4710SRishi Srivatsavai new_pg = B_TRUE; 8044eaa4710SRishi Srivatsavai do { 8054eaa4710SRishi Srivatsavai if (scf_transaction_start(tran, sstate.ss_pg) != 0) 8064eaa4710SRishi Srivatsavai goto out; 8074eaa4710SRishi Srivatsavai 8084eaa4710SRishi Srivatsavai if (!set_string_property(sstate.ss_handle, tran, 8094eaa4710SRishi Srivatsavai SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL)) 8104eaa4710SRishi Srivatsavai goto out; 8114eaa4710SRishi Srivatsavai if (!set_string_property(sstate.ss_handle, tran, 8124eaa4710SRishi Srivatsavai SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART)) 8134eaa4710SRishi Srivatsavai goto out; 8144eaa4710SRishi Srivatsavai if (!set_string_property(sstate.ss_handle, tran, 8154eaa4710SRishi Srivatsavai SCF_PROPERTY_TYPE, "service")) 8164eaa4710SRishi Srivatsavai goto out; 8174eaa4710SRishi Srivatsavai if (!set_fmri_property(sstate.ss_handle, tran, 8184eaa4710SRishi Srivatsavai SCF_PROPERTY_ENTITIES, fmri)) 8194eaa4710SRishi Srivatsavai goto out; 8204eaa4710SRishi Srivatsavai 8214eaa4710SRishi Srivatsavai rv = scf_transaction_commit(tran); 8224eaa4710SRishi Srivatsavai scf_transaction_reset(tran); 8234eaa4710SRishi Srivatsavai if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 8244eaa4710SRishi Srivatsavai goto out; 8254eaa4710SRishi Srivatsavai } while (rv == 0); 8264eaa4710SRishi Srivatsavai if (rv != 1) 8274eaa4710SRishi Srivatsavai goto out; 8284eaa4710SRishi Srivatsavai 8294eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 8304eaa4710SRishi Srivatsavai 8314eaa4710SRishi Srivatsavai out: 8324eaa4710SRishi Srivatsavai free(fmri); 8334eaa4710SRishi Srivatsavai if (tran != NULL) { 8344eaa4710SRishi Srivatsavai scf_transaction_destroy_children(tran); 8354eaa4710SRishi Srivatsavai scf_transaction_destroy(tran); 8364eaa4710SRishi Srivatsavai } 8374eaa4710SRishi Srivatsavai 8384eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_pg) 8394eaa4710SRishi Srivatsavai (void) scf_pg_delete(sstate.ss_pg); 8404eaa4710SRishi Srivatsavai 8414eaa4710SRishi Srivatsavai drop_composed(&sstate); 8424eaa4710SRishi Srivatsavai 8434eaa4710SRishi Srivatsavai /* 8444eaa4710SRishi Srivatsavai * If we created an instance and then failed, then remove the instance 8454eaa4710SRishi Srivatsavai * from the system. 8464eaa4710SRishi Srivatsavai */ 8474eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_instance) 8484eaa4710SRishi Srivatsavai (void) scf_instance_delete(sstate.ss_inst); 8494eaa4710SRishi Srivatsavai 8504eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 8514eaa4710SRishi Srivatsavai 8524eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 8534eaa4710SRishi Srivatsavai status = enable_instance(TRILL_SVC_NAME, instance); 8544eaa4710SRishi Srivatsavai 8554eaa4710SRishi Srivatsavai return (status); 8564eaa4710SRishi Srivatsavai } 8574eaa4710SRishi Srivatsavai 8584eaa4710SRishi Srivatsavai /* 8594eaa4710SRishi Srivatsavai * Create a new bridge or modify an existing one. Update the SMF configuration 8604eaa4710SRishi Srivatsavai * and add links. 8614eaa4710SRishi Srivatsavai * 8624eaa4710SRishi Srivatsavai * Input timer values are in IEEE scaled (* 256) format. 8634eaa4710SRishi Srivatsavai */ 8644eaa4710SRishi Srivatsavai dladm_status_t 8654eaa4710SRishi Srivatsavai dladm_bridge_configure(dladm_handle_t handle, const char *name, 8664eaa4710SRishi Srivatsavai const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags) 8674eaa4710SRishi Srivatsavai { 8684eaa4710SRishi Srivatsavai dladm_status_t status; 8694eaa4710SRishi Srivatsavai scf_state_t sstate; 8704eaa4710SRishi Srivatsavai scf_transaction_t *tran = NULL; 8714eaa4710SRishi Srivatsavai boolean_t new_instance = B_FALSE; 8724eaa4710SRishi Srivatsavai boolean_t new_pg = B_FALSE; 8734eaa4710SRishi Srivatsavai datalink_id_t linkid = DATALINK_INVALID_LINKID; 8744eaa4710SRishi Srivatsavai char linkname[MAXLINKNAMELEN]; 8754eaa4710SRishi Srivatsavai int rv; 8764eaa4710SRishi Srivatsavai 8774eaa4710SRishi Srivatsavai if (!dladm_valid_bridgename(name)) 8784eaa4710SRishi Srivatsavai return (DLADM_STATUS_FAILED); 8794eaa4710SRishi Srivatsavai 8804eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_CREATE) { 8814eaa4710SRishi Srivatsavai /* 8824eaa4710SRishi Srivatsavai * This check is here in case the user has installed and then 8834eaa4710SRishi Srivatsavai * removed the package. SMF should remove the manifest, but 8844eaa4710SRishi Srivatsavai * currently does not. 8854eaa4710SRishi Srivatsavai */ 8864eaa4710SRishi Srivatsavai if (access("/usr/lib/bridged", F_OK) != 0) 8874eaa4710SRishi Srivatsavai return (DLADM_STATUS_OPTMISSING); 8884eaa4710SRishi Srivatsavai 8894eaa4710SRishi Srivatsavai (void) snprintf(linkname, sizeof (linkname), "%s0", name); 8904eaa4710SRishi Srivatsavai status = dladm_create_datalink_id(handle, linkname, 8914eaa4710SRishi Srivatsavai DATALINK_CLASS_BRIDGE, DL_ETHER, 8924eaa4710SRishi Srivatsavai flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid); 8934eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 8944eaa4710SRishi Srivatsavai return (status); 8954eaa4710SRishi Srivatsavai 8964eaa4710SRishi Srivatsavai if ((flags & DLADM_OPT_PERSIST) && 8974eaa4710SRishi Srivatsavai (status = dladm_bridge_persist_conf(handle, linkname, 8984eaa4710SRishi Srivatsavai linkid) != DLADM_STATUS_OK)) 8994eaa4710SRishi Srivatsavai goto dladm_fail; 9004eaa4710SRishi Srivatsavai } 9014eaa4710SRishi Srivatsavai 9024eaa4710SRishi Srivatsavai if (brprot == DLADM_BRIDGE_PROT_TRILL) 9034eaa4710SRishi Srivatsavai status = enable_trill(name); 9044eaa4710SRishi Srivatsavai else 9054eaa4710SRishi Srivatsavai status = disable_trill(name, flags); 9064eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 9074eaa4710SRishi Srivatsavai goto dladm_fail; 9084eaa4710SRishi Srivatsavai 9094eaa4710SRishi Srivatsavai if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) != 9104eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 9114eaa4710SRishi Srivatsavai goto out; 9124eaa4710SRishi Srivatsavai 9134eaa4710SRishi Srivatsavai /* set up for a series of scf calls */ 9144eaa4710SRishi Srivatsavai status = DLADM_STATUS_FAILED; 9154eaa4710SRishi Srivatsavai 9164eaa4710SRishi Srivatsavai if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) == 9174eaa4710SRishi Srivatsavai 0) { 9184eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_CREATE) { 9194eaa4710SRishi Srivatsavai status = DLADM_STATUS_EXIST; 9204eaa4710SRishi Srivatsavai goto out; 9214eaa4710SRishi Srivatsavai } 9224eaa4710SRishi Srivatsavai } else { 9234eaa4710SRishi Srivatsavai if (!(flags & DLADM_OPT_CREATE)) { 9244eaa4710SRishi Srivatsavai status = DLADM_STATUS_NOTFOUND; 9254eaa4710SRishi Srivatsavai goto out; 9264eaa4710SRishi Srivatsavai } 9274eaa4710SRishi Srivatsavai if (scf_service_add_instance(sstate.ss_svc, name, 9284eaa4710SRishi Srivatsavai sstate.ss_inst) != 0) 9294eaa4710SRishi Srivatsavai goto out; 9304eaa4710SRishi Srivatsavai new_instance = B_TRUE; 9314eaa4710SRishi Srivatsavai } 9324eaa4710SRishi Srivatsavai 9334eaa4710SRishi Srivatsavai if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 9344eaa4710SRishi Srivatsavai goto out; 9354eaa4710SRishi Srivatsavai 9364eaa4710SRishi Srivatsavai if (cfg->field_mask & BR_CFG_ALL) { 9374eaa4710SRishi Srivatsavai if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 9384eaa4710SRishi Srivatsavai goto out; 9394eaa4710SRishi Srivatsavai if (scf_instance_add_pg(sstate.ss_inst, "config", 9404eaa4710SRishi Srivatsavai SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 9414eaa4710SRishi Srivatsavai new_pg = B_TRUE; 9424eaa4710SRishi Srivatsavai } else if (scf_instance_get_pg(sstate.ss_inst, "config", 9434eaa4710SRishi Srivatsavai sstate.ss_pg) != 0) { 9444eaa4710SRishi Srivatsavai goto out; 9454eaa4710SRishi Srivatsavai } 9464eaa4710SRishi Srivatsavai do { 9474eaa4710SRishi Srivatsavai if (scf_transaction_start(tran, sstate.ss_pg) != 0) 9484eaa4710SRishi Srivatsavai goto out; 9494eaa4710SRishi Srivatsavai 9504eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_PRIO) && 9514eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 9524eaa4710SRishi Srivatsavai "priority", cfg->bridge_priority)) 9534eaa4710SRishi Srivatsavai goto out; 9544eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_AGE) && 9554eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 9564eaa4710SRishi Srivatsavai "max-age", cfg->max_age * IEEE_TIMER_SCALE)) 9574eaa4710SRishi Srivatsavai goto out; 9584eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_HELLO) && 9594eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 9604eaa4710SRishi Srivatsavai "hello-time", cfg->hello_time * IEEE_TIMER_SCALE)) 9614eaa4710SRishi Srivatsavai goto out; 9624eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_DELAY) && 9634eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 9644eaa4710SRishi Srivatsavai "forward-delay", 9654eaa4710SRishi Srivatsavai cfg->forward_delay * IEEE_TIMER_SCALE)) 9664eaa4710SRishi Srivatsavai goto out; 9674eaa4710SRishi Srivatsavai if ((cfg->field_mask & BR_CFG_FORCE_VER) && 9684eaa4710SRishi Srivatsavai !set_count_property(sstate.ss_handle, tran, 9694eaa4710SRishi Srivatsavai "force-protocol", cfg->force_version)) 9704eaa4710SRishi Srivatsavai goto out; 9714eaa4710SRishi Srivatsavai 9724eaa4710SRishi Srivatsavai rv = scf_transaction_commit(tran); 9734eaa4710SRishi Srivatsavai scf_transaction_reset(tran); 9744eaa4710SRishi Srivatsavai if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 9754eaa4710SRishi Srivatsavai goto out; 9764eaa4710SRishi Srivatsavai } while (rv == 0); 9774eaa4710SRishi Srivatsavai if (rv != 1) 9784eaa4710SRishi Srivatsavai goto out; 9794eaa4710SRishi Srivatsavai } 9804eaa4710SRishi Srivatsavai 9814eaa4710SRishi Srivatsavai /* 9824eaa4710SRishi Srivatsavai * If we're modifying an existing and running bridge, then tell the 9834eaa4710SRishi Srivatsavai * daemon to update the requested values. 9844eaa4710SRishi Srivatsavai */ 9854eaa4710SRishi Srivatsavai if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE)) 9864eaa4710SRishi Srivatsavai status = bridge_refresh(name); 9874eaa4710SRishi Srivatsavai else 9884eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 9894eaa4710SRishi Srivatsavai 9904eaa4710SRishi Srivatsavai out: 9914eaa4710SRishi Srivatsavai if (tran != NULL) { 9924eaa4710SRishi Srivatsavai scf_transaction_destroy_children(tran); 9934eaa4710SRishi Srivatsavai scf_transaction_destroy(tran); 9944eaa4710SRishi Srivatsavai } 9954eaa4710SRishi Srivatsavai 9964eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_pg) 9974eaa4710SRishi Srivatsavai (void) scf_pg_delete(sstate.ss_pg); 9984eaa4710SRishi Srivatsavai 9994eaa4710SRishi Srivatsavai drop_composed(&sstate); 10004eaa4710SRishi Srivatsavai 10014eaa4710SRishi Srivatsavai /* 10024eaa4710SRishi Srivatsavai * If we created an instance and then failed, then remove the instance 10034eaa4710SRishi Srivatsavai * from the system. 10044eaa4710SRishi Srivatsavai */ 10054eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && new_instance) 10064eaa4710SRishi Srivatsavai (void) scf_instance_delete(sstate.ss_inst); 10074eaa4710SRishi Srivatsavai 10084eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 10094eaa4710SRishi Srivatsavai 10104eaa4710SRishi Srivatsavai /* 10114eaa4710SRishi Srivatsavai * Remove the bridge linkid if we've allocated one in this function but 10124eaa4710SRishi Srivatsavai * we've failed to set up the SMF properties. 10134eaa4710SRishi Srivatsavai */ 10144eaa4710SRishi Srivatsavai dladm_fail: 10154eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) { 10164eaa4710SRishi Srivatsavai (void) dladm_remove_conf(handle, linkid); 10174eaa4710SRishi Srivatsavai (void) dladm_destroy_datalink_id(handle, linkid, flags); 10184eaa4710SRishi Srivatsavai } 10194eaa4710SRishi Srivatsavai 10204eaa4710SRishi Srivatsavai return (status); 10214eaa4710SRishi Srivatsavai } 10224eaa4710SRishi Srivatsavai 10234eaa4710SRishi Srivatsavai /* 10244eaa4710SRishi Srivatsavai * Enable a newly-created bridge in SMF by creating "general/enabled" and 10254eaa4710SRishi Srivatsavai * deleting any "general_ovr/enabled" (used for temporary services). 10264eaa4710SRishi Srivatsavai */ 10274eaa4710SRishi Srivatsavai dladm_status_t 10284eaa4710SRishi Srivatsavai dladm_bridge_enable(const char *name) 10294eaa4710SRishi Srivatsavai { 10304eaa4710SRishi Srivatsavai return (enable_instance(BRIDGE_SVC_NAME, name)); 10314eaa4710SRishi Srivatsavai } 10324eaa4710SRishi Srivatsavai 10334eaa4710SRishi Srivatsavai /* 10344eaa4710SRishi Srivatsavai * Set a link as a member of a bridge, or remove bridge membership. If the 10354eaa4710SRishi Srivatsavai * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running. 10364eaa4710SRishi Srivatsavai * In all other cases, we must tell the daemon to add or delete the link in 10374eaa4710SRishi Srivatsavai * order to stay in sync. 10384eaa4710SRishi Srivatsavai */ 10394eaa4710SRishi Srivatsavai dladm_status_t 10404eaa4710SRishi Srivatsavai dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid, 10414eaa4710SRishi Srivatsavai const char *bridge) 10424eaa4710SRishi Srivatsavai { 10434eaa4710SRishi Srivatsavai dladm_status_t status; 10444eaa4710SRishi Srivatsavai dladm_conf_t conf; 10454eaa4710SRishi Srivatsavai char oldbridge[MAXLINKNAMELEN]; 10464eaa4710SRishi Srivatsavai boolean_t has_oldbridge; 10474eaa4710SRishi Srivatsavai boolean_t changed = B_FALSE; 10484eaa4710SRishi Srivatsavai 10494eaa4710SRishi Srivatsavai if (*bridge != '\0' && !dladm_valid_bridgename(bridge)) 10504eaa4710SRishi Srivatsavai return (DLADM_STATUS_FAILED); 10514eaa4710SRishi Srivatsavai 1052*32715170SCathy Zhou status = dladm_open_conf(handle, linkid, &conf); 1053*32715170SCathy Zhou if (status != DLADM_STATUS_OK) 10544eaa4710SRishi Srivatsavai return (status); 10554eaa4710SRishi Srivatsavai 10564eaa4710SRishi Srivatsavai has_oldbridge = B_FALSE; 10574eaa4710SRishi Srivatsavai status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge, 10584eaa4710SRishi Srivatsavai sizeof (oldbridge)); 10594eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 10604eaa4710SRishi Srivatsavai /* 10614eaa4710SRishi Srivatsavai * Don't allow a link to be reassigned directly from one bridge 10624eaa4710SRishi Srivatsavai * to another. It must be removed first. 10634eaa4710SRishi Srivatsavai */ 10644eaa4710SRishi Srivatsavai if (*oldbridge != '\0' && *bridge != '\0') { 10654eaa4710SRishi Srivatsavai status = DLADM_STATUS_EXIST; 10664eaa4710SRishi Srivatsavai goto out; 10674eaa4710SRishi Srivatsavai } 10684eaa4710SRishi Srivatsavai has_oldbridge = B_TRUE; 10694eaa4710SRishi Srivatsavai } else if (status != DLADM_STATUS_NOTFOUND) { 10704eaa4710SRishi Srivatsavai goto out; 10714eaa4710SRishi Srivatsavai } 10724eaa4710SRishi Srivatsavai 10734eaa4710SRishi Srivatsavai if (*bridge != '\0') { 10744eaa4710SRishi Srivatsavai status = dladm_set_conf_field(handle, conf, FBRIDGE, 10754eaa4710SRishi Srivatsavai DLADM_TYPE_STR, bridge); 10764eaa4710SRishi Srivatsavai changed = B_TRUE; 10774eaa4710SRishi Srivatsavai } else if (has_oldbridge) { 10784eaa4710SRishi Srivatsavai status = dladm_unset_conf_field(handle, conf, FBRIDGE); 10794eaa4710SRishi Srivatsavai changed = B_TRUE; 10804eaa4710SRishi Srivatsavai } else { 10814eaa4710SRishi Srivatsavai status = DLADM_STATUS_OK; 10824eaa4710SRishi Srivatsavai goto out; 10834eaa4710SRishi Srivatsavai } 10844eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 10854eaa4710SRishi Srivatsavai status = dladm_write_conf(handle, conf); 10864eaa4710SRishi Srivatsavai 10874eaa4710SRishi Srivatsavai out: 10884eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 10894eaa4710SRishi Srivatsavai if (changed && status == DLADM_STATUS_OK) { 10904eaa4710SRishi Srivatsavai if (bridge[0] == '\0') 10914eaa4710SRishi Srivatsavai bridge = oldbridge; 10924eaa4710SRishi Srivatsavai status = bridge_refresh(bridge); 10934eaa4710SRishi Srivatsavai } 10944eaa4710SRishi Srivatsavai return (status); 10954eaa4710SRishi Srivatsavai } 10964eaa4710SRishi Srivatsavai 10974eaa4710SRishi Srivatsavai /* 10984eaa4710SRishi Srivatsavai * Get the name of the bridge of which the given linkid is a member. 10994eaa4710SRishi Srivatsavai */ 11004eaa4710SRishi Srivatsavai dladm_status_t 11014eaa4710SRishi Srivatsavai dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge, 11024eaa4710SRishi Srivatsavai size_t bridgelen) 11034eaa4710SRishi Srivatsavai { 11044eaa4710SRishi Srivatsavai dladm_status_t status; 11054eaa4710SRishi Srivatsavai dladm_conf_t conf; 11064eaa4710SRishi Srivatsavai 1107*32715170SCathy Zhou if ((status = dladm_getsnap_conf(handle, linkid, &conf)) != 11084eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 11094eaa4710SRishi Srivatsavai return (status); 11104eaa4710SRishi Srivatsavai 11114eaa4710SRishi Srivatsavai *bridge = '\0'; 11124eaa4710SRishi Srivatsavai status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen); 11134eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK && *bridge == '\0') 11144eaa4710SRishi Srivatsavai status = DLADM_STATUS_NOTFOUND; 11154eaa4710SRishi Srivatsavai 11164eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 11174eaa4710SRishi Srivatsavai return (status); 11184eaa4710SRishi Srivatsavai } 11194eaa4710SRishi Srivatsavai 11204eaa4710SRishi Srivatsavai dladm_status_t 11214eaa4710SRishi Srivatsavai dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid) 11224eaa4710SRishi Srivatsavai { 11234eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 11244eaa4710SRishi Srivatsavai dladm_status_t status; 11254eaa4710SRishi Srivatsavai 11264eaa4710SRishi Srivatsavai status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 11274eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_NOTFOUND) 11284eaa4710SRishi Srivatsavai return (DLADM_STATUS_OK); 11294eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 11304eaa4710SRishi Srivatsavai status = bridge_refresh(bridge); 11314eaa4710SRishi Srivatsavai return (status); 11324eaa4710SRishi Srivatsavai } 11334eaa4710SRishi Srivatsavai 11344eaa4710SRishi Srivatsavai typedef struct bridge_held_arg_s { 11354eaa4710SRishi Srivatsavai const char *bha_bridge; 11364eaa4710SRishi Srivatsavai boolean_t bha_isheld; 11374eaa4710SRishi Srivatsavai } bridge_held_arg_t; 11384eaa4710SRishi Srivatsavai 11394eaa4710SRishi Srivatsavai static int 11404eaa4710SRishi Srivatsavai i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 11414eaa4710SRishi Srivatsavai { 11424eaa4710SRishi Srivatsavai dladm_status_t status = DLADM_STATUS_FAILED; 11434eaa4710SRishi Srivatsavai dladm_conf_t conf; 11444eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 11454eaa4710SRishi Srivatsavai bridge_held_arg_t *bha = arg; 11464eaa4710SRishi Srivatsavai 1147*32715170SCathy Zhou if ((status = dladm_getsnap_conf(handle, linkid, &conf)) != 11484eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 11494eaa4710SRishi Srivatsavai return (DLADM_WALK_CONTINUE); 11504eaa4710SRishi Srivatsavai status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, 11514eaa4710SRishi Srivatsavai sizeof (bridge)); 11524eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) { 11534eaa4710SRishi Srivatsavai bha->bha_isheld = B_TRUE; 11544eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 11554eaa4710SRishi Srivatsavai return (DLADM_WALK_TERMINATE); 11564eaa4710SRishi Srivatsavai } else { 11574eaa4710SRishi Srivatsavai dladm_destroy_conf(handle, conf); 11584eaa4710SRishi Srivatsavai return (DLADM_WALK_CONTINUE); 11594eaa4710SRishi Srivatsavai } 11604eaa4710SRishi Srivatsavai } 11614eaa4710SRishi Srivatsavai 11624eaa4710SRishi Srivatsavai /* 11634eaa4710SRishi Srivatsavai * Delete a previously created bridge. 11644eaa4710SRishi Srivatsavai */ 11654eaa4710SRishi Srivatsavai dladm_status_t 11664eaa4710SRishi Srivatsavai dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags) 11674eaa4710SRishi Srivatsavai { 11684eaa4710SRishi Srivatsavai datalink_id_t linkid; 11694eaa4710SRishi Srivatsavai datalink_class_t class; 11704eaa4710SRishi Srivatsavai dladm_status_t status; 11714eaa4710SRishi Srivatsavai char linkname[MAXLINKNAMELEN]; 11724eaa4710SRishi Srivatsavai 11734eaa4710SRishi Srivatsavai if (!dladm_valid_bridgename(bridge)) 11744eaa4710SRishi Srivatsavai return (DLADM_STATUS_LINKINVAL); 11754eaa4710SRishi Srivatsavai 11764eaa4710SRishi Srivatsavai /* Get the datalink ID for this bridge */ 11774eaa4710SRishi Srivatsavai (void) snprintf(linkname, sizeof (linkname), "%s0", bridge); 11784eaa4710SRishi Srivatsavai if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) != 11794eaa4710SRishi Srivatsavai DLADM_STATUS_OK) 11804eaa4710SRishi Srivatsavai linkid = DATALINK_INVALID_LINKID; 11814eaa4710SRishi Srivatsavai else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 11824eaa4710SRishi Srivatsavai NULL, 0) != DLADM_STATUS_OK) 11834eaa4710SRishi Srivatsavai linkid = DATALINK_INVALID_LINKID; 11844eaa4710SRishi Srivatsavai else if (class != DATALINK_CLASS_BRIDGE) 11854eaa4710SRishi Srivatsavai return (DLADM_STATUS_BADARG); 11864eaa4710SRishi Srivatsavai 11874eaa4710SRishi Srivatsavai if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID) 11884eaa4710SRishi Srivatsavai return (DLADM_STATUS_BADARG); 11894eaa4710SRishi Srivatsavai 11904eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_PERSIST) { 11914eaa4710SRishi Srivatsavai bridge_held_arg_t arg; 11924eaa4710SRishi Srivatsavai 11934eaa4710SRishi Srivatsavai arg.bha_bridge = bridge; 11944eaa4710SRishi Srivatsavai arg.bha_isheld = B_FALSE; 11954eaa4710SRishi Srivatsavai 11964eaa4710SRishi Srivatsavai /* 11974eaa4710SRishi Srivatsavai * See whether there are any persistent links using this 11984eaa4710SRishi Srivatsavai * bridge. If so, we fail the operation. 11994eaa4710SRishi Srivatsavai */ 12004eaa4710SRishi Srivatsavai (void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle, 12014eaa4710SRishi Srivatsavai &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 12024eaa4710SRishi Srivatsavai DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET, 12034eaa4710SRishi Srivatsavai DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 12044eaa4710SRishi Srivatsavai if (arg.bha_isheld) 12054eaa4710SRishi Srivatsavai return (DLADM_STATUS_LINKBUSY); 12064eaa4710SRishi Srivatsavai } 12074eaa4710SRishi Srivatsavai 12084eaa4710SRishi Srivatsavai if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK) 12094eaa4710SRishi Srivatsavai goto out; 12104eaa4710SRishi Srivatsavai 12114eaa4710SRishi Srivatsavai /* Disable or remove the SMF instance */ 12124eaa4710SRishi Srivatsavai status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags); 12134eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 12144eaa4710SRishi Srivatsavai goto out; 12154eaa4710SRishi Srivatsavai 12164eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_ACTIVE) { 12174eaa4710SRishi Srivatsavai /* 12184eaa4710SRishi Srivatsavai * Delete ACTIVE linkprop now that daemon is gone. 12194eaa4710SRishi Srivatsavai */ 12204eaa4710SRishi Srivatsavai (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 12214eaa4710SRishi Srivatsavai DLADM_OPT_ACTIVE); 12224eaa4710SRishi Srivatsavai (void) dladm_destroy_datalink_id(handle, linkid, 12234eaa4710SRishi Srivatsavai DLADM_OPT_ACTIVE); 12244eaa4710SRishi Srivatsavai } 12254eaa4710SRishi Srivatsavai 12264eaa4710SRishi Srivatsavai if (flags & DLADM_OPT_PERSIST) { 12274eaa4710SRishi Srivatsavai (void) dladm_remove_conf(handle, linkid); 12284eaa4710SRishi Srivatsavai (void) dladm_destroy_datalink_id(handle, linkid, 12294eaa4710SRishi Srivatsavai DLADM_OPT_PERSIST); 12304eaa4710SRishi Srivatsavai } 12314eaa4710SRishi Srivatsavai 12324eaa4710SRishi Srivatsavai out: 12334eaa4710SRishi Srivatsavai 12344eaa4710SRishi Srivatsavai return (status); 12354eaa4710SRishi Srivatsavai } 12364eaa4710SRishi Srivatsavai 12374eaa4710SRishi Srivatsavai /* Check if given name is valid for bridges */ 12384eaa4710SRishi Srivatsavai boolean_t 12394eaa4710SRishi Srivatsavai dladm_valid_bridgename(const char *bridge) 12404eaa4710SRishi Srivatsavai { 12414eaa4710SRishi Srivatsavai size_t len = strnlen(bridge, MAXLINKNAMELEN); 12424eaa4710SRishi Srivatsavai const char *cp; 12434eaa4710SRishi Srivatsavai 12444eaa4710SRishi Srivatsavai if (len == MAXLINKNAMELEN) 12454eaa4710SRishi Srivatsavai return (B_FALSE); 12464eaa4710SRishi Srivatsavai 12474eaa4710SRishi Srivatsavai /* 12484eaa4710SRishi Srivatsavai * The bridge name cannot start or end with a digit. 12494eaa4710SRishi Srivatsavai */ 12504eaa4710SRishi Srivatsavai if (isdigit(bridge[0]) || isdigit(bridge[len - 1])) 12514eaa4710SRishi Srivatsavai return (B_FALSE); 12524eaa4710SRishi Srivatsavai 12534eaa4710SRishi Srivatsavai /* 12544eaa4710SRishi Srivatsavai * The legal characters within a bridge name are: 12554eaa4710SRishi Srivatsavai * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 12564eaa4710SRishi Srivatsavai */ 12574eaa4710SRishi Srivatsavai for (cp = bridge; *cp != '\0'; cp++) { 12584eaa4710SRishi Srivatsavai if (!isalnum(*cp) && *cp != '_') 12594eaa4710SRishi Srivatsavai return (B_FALSE); 12604eaa4710SRishi Srivatsavai } 12614eaa4710SRishi Srivatsavai 12624eaa4710SRishi Srivatsavai return (B_TRUE); 12634eaa4710SRishi Srivatsavai } 12644eaa4710SRishi Srivatsavai 12654eaa4710SRishi Srivatsavai /* 12664eaa4710SRishi Srivatsavai * Convert a bridge-related observability node name back into the name of the 12674eaa4710SRishi Srivatsavai * bridge. Returns B_FALSE without making changes if the input name is not in 12684eaa4710SRishi Srivatsavai * a legal format. 12694eaa4710SRishi Srivatsavai */ 12704eaa4710SRishi Srivatsavai boolean_t 12714eaa4710SRishi Srivatsavai dladm_observe_to_bridge(char *link) 12724eaa4710SRishi Srivatsavai { 12734eaa4710SRishi Srivatsavai int llen; 12744eaa4710SRishi Srivatsavai 12754eaa4710SRishi Srivatsavai llen = strnlen(link, MAXLINKNAMELEN); 12764eaa4710SRishi Srivatsavai if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2])) 12774eaa4710SRishi Srivatsavai return (B_FALSE); 12784eaa4710SRishi Srivatsavai link[llen - 1] = '\0'; 12794eaa4710SRishi Srivatsavai return (B_TRUE); 12804eaa4710SRishi Srivatsavai } 12814eaa4710SRishi Srivatsavai 12824eaa4710SRishi Srivatsavai /* 12834eaa4710SRishi Srivatsavai * Get bridge property values from the running daemon and return them in a 12844eaa4710SRishi Srivatsavai * common structure. 12854eaa4710SRishi Srivatsavai */ 12864eaa4710SRishi Srivatsavai dladm_status_t 12874eaa4710SRishi Srivatsavai dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg, 12884eaa4710SRishi Srivatsavai dladm_bridge_prot_t *brprotp) 12894eaa4710SRishi Srivatsavai { 12904eaa4710SRishi Srivatsavai dladm_status_t status; 12914eaa4710SRishi Srivatsavai bridge_door_cfg_t bdcf; 12924eaa4710SRishi Srivatsavai bridge_door_cfg_t *bdcfp = &bdcf; 12934eaa4710SRishi Srivatsavai size_t buflen = sizeof (bdcf); 12944eaa4710SRishi Srivatsavai 12954eaa4710SRishi Srivatsavai status = bridge_door_call(instname, bdcBridgeGetConfig, 12964eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE); 12974eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) { 12984eaa4710SRishi Srivatsavai *smcfg = bdcfp->bdcf_cfg; 12994eaa4710SRishi Srivatsavai *brprotp = bdcfp->bdcf_prot; 13004eaa4710SRishi Srivatsavai } else { 13014eaa4710SRishi Srivatsavai smcfg->field_mask = 0; 13024eaa4710SRishi Srivatsavai *brprotp = DLADM_BRIDGE_PROT_STP; 13034eaa4710SRishi Srivatsavai } 13044eaa4710SRishi Srivatsavai return (status); 13054eaa4710SRishi Srivatsavai } 13064eaa4710SRishi Srivatsavai 13074eaa4710SRishi Srivatsavai /* 13084eaa4710SRishi Srivatsavai * Get bridge state from the running daemon and return in structure borrowed 13094eaa4710SRishi Srivatsavai * from librstp. 13104eaa4710SRishi Srivatsavai */ 13114eaa4710SRishi Srivatsavai dladm_status_t 13124eaa4710SRishi Srivatsavai dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep) 13134eaa4710SRishi Srivatsavai { 13144eaa4710SRishi Srivatsavai size_t buflen = sizeof (*statep); 13154eaa4710SRishi Srivatsavai 13164eaa4710SRishi Srivatsavai return (bridge_door_call(instname, bdcBridgeGetState, 13174eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE)); 13184eaa4710SRishi Srivatsavai } 13194eaa4710SRishi Srivatsavai 13204eaa4710SRishi Srivatsavai /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */ 13214eaa4710SRishi Srivatsavai datalink_id_t * 13224eaa4710SRishi Srivatsavai dladm_bridge_get_portlist(const char *instname, uint_t *nports) 13234eaa4710SRishi Srivatsavai { 13244eaa4710SRishi Srivatsavai size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t); 13254eaa4710SRishi Srivatsavai int *rbuf; 13264eaa4710SRishi Srivatsavai 13274eaa4710SRishi Srivatsavai if ((rbuf = malloc(buflen)) == NULL) 13284eaa4710SRishi Srivatsavai return (NULL); 13294eaa4710SRishi Srivatsavai if (bridge_door_call(instname, bdcBridgeGetPorts, 13304eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) != 13314eaa4710SRishi Srivatsavai DLADM_STATUS_OK) { 13324eaa4710SRishi Srivatsavai free(rbuf); 13334eaa4710SRishi Srivatsavai return (NULL); 13344eaa4710SRishi Srivatsavai } else { 13354eaa4710SRishi Srivatsavai /* 13364eaa4710SRishi Srivatsavai * Returns an array of datalink_id_t values for all the ports 13374eaa4710SRishi Srivatsavai * part of the bridge instance. First entry in the array is the 13384eaa4710SRishi Srivatsavai * number of ports. 13394eaa4710SRishi Srivatsavai */ 13404eaa4710SRishi Srivatsavai *nports = *rbuf; 13414eaa4710SRishi Srivatsavai return ((datalink_id_t *)(rbuf + 1)); 13424eaa4710SRishi Srivatsavai } 13434eaa4710SRishi Srivatsavai } 13444eaa4710SRishi Srivatsavai 13454eaa4710SRishi Srivatsavai void 13464eaa4710SRishi Srivatsavai dladm_bridge_free_portlist(datalink_id_t *dlp) 13474eaa4710SRishi Srivatsavai { 13484eaa4710SRishi Srivatsavai free((int *)dlp - 1); 13494eaa4710SRishi Srivatsavai } 13504eaa4710SRishi Srivatsavai 13514eaa4710SRishi Srivatsavai /* Retrieve Bridge port configuration values */ 13524eaa4710SRishi Srivatsavai dladm_status_t 13534eaa4710SRishi Srivatsavai dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid, 13544eaa4710SRishi Srivatsavai int field, int *valuep) 13554eaa4710SRishi Srivatsavai { 13564eaa4710SRishi Srivatsavai UID_STP_PORT_CFG_T portcfg; 13574eaa4710SRishi Srivatsavai dladm_status_t status; 13584eaa4710SRishi Srivatsavai 13594eaa4710SRishi Srivatsavai status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg, 13604eaa4710SRishi Srivatsavai 0, sizeof (portcfg)); 13614eaa4710SRishi Srivatsavai if (status != DLADM_STATUS_OK) 13624eaa4710SRishi Srivatsavai return (status); 13634eaa4710SRishi Srivatsavai 13644eaa4710SRishi Srivatsavai switch (field) { 13654eaa4710SRishi Srivatsavai case PT_CFG_COST: 13664eaa4710SRishi Srivatsavai *valuep = portcfg.admin_port_path_cost; 13674eaa4710SRishi Srivatsavai break; 13684eaa4710SRishi Srivatsavai case PT_CFG_PRIO: 13694eaa4710SRishi Srivatsavai *valuep = portcfg.port_priority; 13704eaa4710SRishi Srivatsavai break; 13714eaa4710SRishi Srivatsavai case PT_CFG_P2P: 13724eaa4710SRishi Srivatsavai *valuep = portcfg.admin_point2point; 13734eaa4710SRishi Srivatsavai break; 13744eaa4710SRishi Srivatsavai case PT_CFG_EDGE: 13754eaa4710SRishi Srivatsavai *valuep = portcfg.admin_edge; 13764eaa4710SRishi Srivatsavai break; 13774eaa4710SRishi Srivatsavai case PT_CFG_NON_STP: 13784eaa4710SRishi Srivatsavai *valuep = !portcfg.admin_non_stp; 13794eaa4710SRishi Srivatsavai break; 13804eaa4710SRishi Srivatsavai case PT_CFG_MCHECK: 13814eaa4710SRishi Srivatsavai *valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0; 13824eaa4710SRishi Srivatsavai break; 13834eaa4710SRishi Srivatsavai } 13844eaa4710SRishi Srivatsavai return (status); 13854eaa4710SRishi Srivatsavai } 13864eaa4710SRishi Srivatsavai 13874eaa4710SRishi Srivatsavai /* Retreive Bridge port status (disabled, bad SDU etc.) */ 13884eaa4710SRishi Srivatsavai dladm_status_t 13894eaa4710SRishi Srivatsavai dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid, 13904eaa4710SRishi Srivatsavai UID_STP_PORT_STATE_T *spsp) 13914eaa4710SRishi Srivatsavai { 13924eaa4710SRishi Srivatsavai return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0, 13934eaa4710SRishi Srivatsavai sizeof (*spsp))); 13944eaa4710SRishi Srivatsavai } 13954eaa4710SRishi Srivatsavai 13964eaa4710SRishi Srivatsavai /* Retrieve Bridge forwarding status of the given link */ 13974eaa4710SRishi Srivatsavai dladm_status_t 13984eaa4710SRishi Srivatsavai dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid, 13994eaa4710SRishi Srivatsavai uint_t *valuep) 14004eaa4710SRishi Srivatsavai { 14014eaa4710SRishi Srivatsavai int twoints[2]; 14024eaa4710SRishi Srivatsavai dladm_status_t status; 14034eaa4710SRishi Srivatsavai 14044eaa4710SRishi Srivatsavai status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints, 14054eaa4710SRishi Srivatsavai 0, sizeof (twoints)); 14064eaa4710SRishi Srivatsavai if (status == DLADM_STATUS_OK) 14074eaa4710SRishi Srivatsavai *valuep = twoints[0]; 14084eaa4710SRishi Srivatsavai return (status); 14094eaa4710SRishi Srivatsavai } 14104eaa4710SRishi Srivatsavai 14114eaa4710SRishi Srivatsavai /* Retrieve Bridge forwarding table entries */ 14124eaa4710SRishi Srivatsavai bridge_listfwd_t * 14134eaa4710SRishi Srivatsavai dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge, 14144eaa4710SRishi Srivatsavai uint_t *nfwd) 14154eaa4710SRishi Srivatsavai { 14164eaa4710SRishi Srivatsavai bridge_listfwd_t *blf = NULL, *newblf, blfread; 14174eaa4710SRishi Srivatsavai uint_t nblf = 0, maxblf = 0; 14184eaa4710SRishi Srivatsavai static uint8_t zero_addr[ETHERADDRL]; 14194eaa4710SRishi Srivatsavai int rc; 14204eaa4710SRishi Srivatsavai 14214eaa4710SRishi Srivatsavai (void) memset(&blfread, 0, sizeof (blfread)); 14224eaa4710SRishi Srivatsavai (void) snprintf(blfread.blf_name, sizeof (blfread.blf_name), 14234eaa4710SRishi Srivatsavai "%s0", bridge); 14244eaa4710SRishi Srivatsavai for (;;) { 14254eaa4710SRishi Srivatsavai if (nblf >= maxblf) { 14264eaa4710SRishi Srivatsavai maxblf = maxblf == 0 ? 64 : (maxblf << 1); 14274eaa4710SRishi Srivatsavai newblf = realloc(blf, maxblf * sizeof (*blf)); 14284eaa4710SRishi Srivatsavai if (newblf == NULL) { 14294eaa4710SRishi Srivatsavai free(blf); 14304eaa4710SRishi Srivatsavai blf = NULL; 14314eaa4710SRishi Srivatsavai break; 14324eaa4710SRishi Srivatsavai } 14334eaa4710SRishi Srivatsavai blf = newblf; 14344eaa4710SRishi Srivatsavai } 14354eaa4710SRishi Srivatsavai rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread); 14364eaa4710SRishi Srivatsavai if (rc != 0) { 14374eaa4710SRishi Srivatsavai free(blf); 14384eaa4710SRishi Srivatsavai blf = NULL; 14394eaa4710SRishi Srivatsavai break; 14404eaa4710SRishi Srivatsavai } 14414eaa4710SRishi Srivatsavai if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0) 14424eaa4710SRishi Srivatsavai break; 14434eaa4710SRishi Srivatsavai blf[nblf++] = blfread; 14444eaa4710SRishi Srivatsavai } 14454eaa4710SRishi Srivatsavai if (blf != NULL) 14464eaa4710SRishi Srivatsavai *nfwd = nblf; 14474eaa4710SRishi Srivatsavai return (blf); 14484eaa4710SRishi Srivatsavai } 14494eaa4710SRishi Srivatsavai 14504eaa4710SRishi Srivatsavai void 14514eaa4710SRishi Srivatsavai dladm_bridge_free_fwdtable(bridge_listfwd_t *blf) 14524eaa4710SRishi Srivatsavai { 14534eaa4710SRishi Srivatsavai free(blf); 14544eaa4710SRishi Srivatsavai } 14554eaa4710SRishi Srivatsavai 14564eaa4710SRishi Srivatsavai /* Retrieve list of TRILL nicknames from the TRILL module */ 14574eaa4710SRishi Srivatsavai trill_listnick_t * 14584eaa4710SRishi Srivatsavai dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick) 14594eaa4710SRishi Srivatsavai { 14604eaa4710SRishi Srivatsavai int fd; 14614eaa4710SRishi Srivatsavai char brcopy[MAXLINKNAMELEN]; 14624eaa4710SRishi Srivatsavai trill_listnick_t *tln = NULL, *newtln, tlnread; 14634eaa4710SRishi Srivatsavai uint_t ntln = 0, maxtln = 0; 14644eaa4710SRishi Srivatsavai 14654eaa4710SRishi Srivatsavai if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1) 14664eaa4710SRishi Srivatsavai return (NULL); 14674eaa4710SRishi Srivatsavai (void) strlcpy(brcopy, bridge, sizeof (brcopy)); 14684eaa4710SRishi Srivatsavai if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) { 14694eaa4710SRishi Srivatsavai (void) close(fd); 14704eaa4710SRishi Srivatsavai return (NULL); 14714eaa4710SRishi Srivatsavai } 14724eaa4710SRishi Srivatsavai (void) memset(&tlnread, 0, sizeof (tlnread)); 14734eaa4710SRishi Srivatsavai for (;;) { 14744eaa4710SRishi Srivatsavai if (ntln >= maxtln) { 14754eaa4710SRishi Srivatsavai maxtln = maxtln == 0 ? 64 : (maxtln << 1); 14764eaa4710SRishi Srivatsavai newtln = realloc(tln, maxtln * sizeof (*tln)); 14774eaa4710SRishi Srivatsavai if (newtln == NULL) { 14784eaa4710SRishi Srivatsavai free(tln); 14794eaa4710SRishi Srivatsavai tln = NULL; 14804eaa4710SRishi Srivatsavai break; 14814eaa4710SRishi Srivatsavai } 14824eaa4710SRishi Srivatsavai tln = newtln; 14834eaa4710SRishi Srivatsavai } 14844eaa4710SRishi Srivatsavai if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) { 14854eaa4710SRishi Srivatsavai free(tln); 14864eaa4710SRishi Srivatsavai tln = NULL; 14874eaa4710SRishi Srivatsavai break; 14884eaa4710SRishi Srivatsavai } 14894eaa4710SRishi Srivatsavai if (tlnread.tln_nick == 0) 14904eaa4710SRishi Srivatsavai break; 14914eaa4710SRishi Srivatsavai tln[ntln++] = tlnread; 14924eaa4710SRishi Srivatsavai } 14934eaa4710SRishi Srivatsavai (void) close(fd); 14944eaa4710SRishi Srivatsavai if (tln != NULL) 14954eaa4710SRishi Srivatsavai *nnick = ntln; 14964eaa4710SRishi Srivatsavai return (tln); 14974eaa4710SRishi Srivatsavai } 14984eaa4710SRishi Srivatsavai 14994eaa4710SRishi Srivatsavai void 15004eaa4710SRishi Srivatsavai dladm_bridge_free_trillnick(trill_listnick_t *tln) 15014eaa4710SRishi Srivatsavai { 15024eaa4710SRishi Srivatsavai free(tln); 15034eaa4710SRishi Srivatsavai } 15044eaa4710SRishi Srivatsavai 15054eaa4710SRishi Srivatsavai /* Retrieve any stored TRILL nickname from TRILL SMF service */ 15064eaa4710SRishi Srivatsavai uint16_t 15074eaa4710SRishi Srivatsavai dladm_bridge_get_nick(const char *bridge) 15084eaa4710SRishi Srivatsavai { 15094eaa4710SRishi Srivatsavai scf_state_t sstate; 15104eaa4710SRishi Srivatsavai uint64_t value; 15114eaa4710SRishi Srivatsavai uint16_t nickname = RBRIDGE_NICKNAME_NONE; 15124eaa4710SRishi Srivatsavai 15134eaa4710SRishi Srivatsavai if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0) 15144eaa4710SRishi Srivatsavai return (nickname); 15154eaa4710SRishi Srivatsavai 15164eaa4710SRishi Srivatsavai if (get_composed_properties("config", B_TRUE, &sstate) == 0 && 15174eaa4710SRishi Srivatsavai get_count("nickname", &sstate, &value) == 0) 15184eaa4710SRishi Srivatsavai nickname = value; 15194eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 15204eaa4710SRishi Srivatsavai return (nickname); 15214eaa4710SRishi Srivatsavai } 15224eaa4710SRishi Srivatsavai 15234eaa4710SRishi Srivatsavai /* Stores TRILL nickname in SMF configuraiton for the TRILL service */ 15244eaa4710SRishi Srivatsavai void 15254eaa4710SRishi Srivatsavai dladm_bridge_set_nick(const char *bridge, uint16_t nick) 15264eaa4710SRishi Srivatsavai { 15274eaa4710SRishi Srivatsavai scf_state_t sstate; 15284eaa4710SRishi Srivatsavai scf_transaction_t *tran = NULL; 15294eaa4710SRishi Srivatsavai boolean_t new_pg = B_FALSE; 15304eaa4710SRishi Srivatsavai int rv = 0; 15314eaa4710SRishi Srivatsavai char *fmri; 15324eaa4710SRishi Srivatsavai 15334eaa4710SRishi Srivatsavai if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK) 15344eaa4710SRishi Srivatsavai return; 15354eaa4710SRishi Srivatsavai 15364eaa4710SRishi Srivatsavai if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) != 15374eaa4710SRishi Srivatsavai 0) 15384eaa4710SRishi Srivatsavai goto out; 15394eaa4710SRishi Srivatsavai if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 15404eaa4710SRishi Srivatsavai goto out; 15414eaa4710SRishi Srivatsavai if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 15424eaa4710SRishi Srivatsavai goto out; 15434eaa4710SRishi Srivatsavai if (scf_instance_add_pg(sstate.ss_inst, "config", 15444eaa4710SRishi Srivatsavai SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 15454eaa4710SRishi Srivatsavai new_pg = B_TRUE; 15464eaa4710SRishi Srivatsavai } else if (scf_instance_get_pg(sstate.ss_inst, "config", 15474eaa4710SRishi Srivatsavai sstate.ss_pg) != 0) { 15484eaa4710SRishi Srivatsavai goto out; 15494eaa4710SRishi Srivatsavai } 15504eaa4710SRishi Srivatsavai do { 15514eaa4710SRishi Srivatsavai if (scf_transaction_start(tran, sstate.ss_pg) != 0) 15524eaa4710SRishi Srivatsavai goto out; 15534eaa4710SRishi Srivatsavai if (!set_count_property(sstate.ss_handle, tran, "nickname", 15544eaa4710SRishi Srivatsavai nick)) 15554eaa4710SRishi Srivatsavai goto out; 15564eaa4710SRishi Srivatsavai rv = scf_transaction_commit(tran); 15574eaa4710SRishi Srivatsavai scf_transaction_reset(tran); 15584eaa4710SRishi Srivatsavai if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 15594eaa4710SRishi Srivatsavai goto out; 15604eaa4710SRishi Srivatsavai } while (rv == 0); 15614eaa4710SRishi Srivatsavai 15624eaa4710SRishi Srivatsavai out: 15634eaa4710SRishi Srivatsavai if (tran != NULL) { 15644eaa4710SRishi Srivatsavai scf_transaction_destroy_children(tran); 15654eaa4710SRishi Srivatsavai scf_transaction_destroy(tran); 15664eaa4710SRishi Srivatsavai } 15674eaa4710SRishi Srivatsavai 15684eaa4710SRishi Srivatsavai if (rv != 1 && new_pg) 15694eaa4710SRishi Srivatsavai (void) scf_pg_delete(sstate.ss_pg); 15704eaa4710SRishi Srivatsavai 15714eaa4710SRishi Srivatsavai drop_composed(&sstate); 15724eaa4710SRishi Srivatsavai shut_down_scf(&sstate); 15734eaa4710SRishi Srivatsavai if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) { 15744eaa4710SRishi Srivatsavai (void) smf_refresh_instance(fmri); 15754eaa4710SRishi Srivatsavai free(fmri); 15764eaa4710SRishi Srivatsavai } 15774eaa4710SRishi Srivatsavai } 1578