1*10491SRishi.Srivatsavai@Sun.COM /* 2*10491SRishi.Srivatsavai@Sun.COM * CDDL HEADER START 3*10491SRishi.Srivatsavai@Sun.COM * 4*10491SRishi.Srivatsavai@Sun.COM * The contents of this file are subject to the terms of the 5*10491SRishi.Srivatsavai@Sun.COM * Common Development and Distribution License (the "License"). 6*10491SRishi.Srivatsavai@Sun.COM * You may not use this file except in compliance with the License. 7*10491SRishi.Srivatsavai@Sun.COM * 8*10491SRishi.Srivatsavai@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10491SRishi.Srivatsavai@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10491SRishi.Srivatsavai@Sun.COM * See the License for the specific language governing permissions 11*10491SRishi.Srivatsavai@Sun.COM * and limitations under the License. 12*10491SRishi.Srivatsavai@Sun.COM * 13*10491SRishi.Srivatsavai@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10491SRishi.Srivatsavai@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10491SRishi.Srivatsavai@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10491SRishi.Srivatsavai@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10491SRishi.Srivatsavai@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10491SRishi.Srivatsavai@Sun.COM * 19*10491SRishi.Srivatsavai@Sun.COM * CDDL HEADER END 20*10491SRishi.Srivatsavai@Sun.COM */ 21*10491SRishi.Srivatsavai@Sun.COM 22*10491SRishi.Srivatsavai@Sun.COM /* 23*10491SRishi.Srivatsavai@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*10491SRishi.Srivatsavai@Sun.COM * Use is subject to license terms. 25*10491SRishi.Srivatsavai@Sun.COM */ 26*10491SRishi.Srivatsavai@Sun.COM 27*10491SRishi.Srivatsavai@Sun.COM /* 28*10491SRishi.Srivatsavai@Sun.COM * This module implements a STREAMS driver that provides layer-two (Ethernet) 29*10491SRishi.Srivatsavai@Sun.COM * bridging functionality. The STREAMS interface is used to provide 30*10491SRishi.Srivatsavai@Sun.COM * observability (snoop/wireshark) and control, but not for interface plumbing. 31*10491SRishi.Srivatsavai@Sun.COM */ 32*10491SRishi.Srivatsavai@Sun.COM 33*10491SRishi.Srivatsavai@Sun.COM #include <sys/types.h> 34*10491SRishi.Srivatsavai@Sun.COM #include <sys/bitmap.h> 35*10491SRishi.Srivatsavai@Sun.COM #include <sys/cmn_err.h> 36*10491SRishi.Srivatsavai@Sun.COM #include <sys/conf.h> 37*10491SRishi.Srivatsavai@Sun.COM #include <sys/ddi.h> 38*10491SRishi.Srivatsavai@Sun.COM #include <sys/errno.h> 39*10491SRishi.Srivatsavai@Sun.COM #include <sys/kstat.h> 40*10491SRishi.Srivatsavai@Sun.COM #include <sys/modctl.h> 41*10491SRishi.Srivatsavai@Sun.COM #include <sys/note.h> 42*10491SRishi.Srivatsavai@Sun.COM #include <sys/param.h> 43*10491SRishi.Srivatsavai@Sun.COM #include <sys/policy.h> 44*10491SRishi.Srivatsavai@Sun.COM #include <sys/sdt.h> 45*10491SRishi.Srivatsavai@Sun.COM #include <sys/stat.h> 46*10491SRishi.Srivatsavai@Sun.COM #include <sys/stream.h> 47*10491SRishi.Srivatsavai@Sun.COM #include <sys/stropts.h> 48*10491SRishi.Srivatsavai@Sun.COM #include <sys/strsun.h> 49*10491SRishi.Srivatsavai@Sun.COM #include <sys/sunddi.h> 50*10491SRishi.Srivatsavai@Sun.COM #include <sys/sysmacros.h> 51*10491SRishi.Srivatsavai@Sun.COM #include <sys/systm.h> 52*10491SRishi.Srivatsavai@Sun.COM #include <sys/time.h> 53*10491SRishi.Srivatsavai@Sun.COM #include <sys/dlpi.h> 54*10491SRishi.Srivatsavai@Sun.COM #include <sys/dls.h> 55*10491SRishi.Srivatsavai@Sun.COM #include <sys/mac_ether.h> 56*10491SRishi.Srivatsavai@Sun.COM #include <sys/mac_provider.h> 57*10491SRishi.Srivatsavai@Sun.COM #include <sys/mac_client_priv.h> 58*10491SRishi.Srivatsavai@Sun.COM #include <sys/mac_impl.h> 59*10491SRishi.Srivatsavai@Sun.COM #include <sys/vlan.h> 60*10491SRishi.Srivatsavai@Sun.COM #include <net/bridge.h> 61*10491SRishi.Srivatsavai@Sun.COM #include <net/bridge_impl.h> 62*10491SRishi.Srivatsavai@Sun.COM #include <net/trill.h> 63*10491SRishi.Srivatsavai@Sun.COM 64*10491SRishi.Srivatsavai@Sun.COM /* 65*10491SRishi.Srivatsavai@Sun.COM * Locks and reference counts: object lifetime and design. 66*10491SRishi.Srivatsavai@Sun.COM * 67*10491SRishi.Srivatsavai@Sun.COM * bridge_mac_t 68*10491SRishi.Srivatsavai@Sun.COM * Bridge mac (snoop) instances are in bmac_list, which is protected by 69*10491SRishi.Srivatsavai@Sun.COM * bmac_rwlock. They're allocated by bmac_alloc and freed by bridge_timer(). 70*10491SRishi.Srivatsavai@Sun.COM * Every bridge_inst_t has a single bridge_mac_t, but when bridge_inst_t goes 71*10491SRishi.Srivatsavai@Sun.COM * away, the bridge_mac_t remains until either all of the users go away 72*10491SRishi.Srivatsavai@Sun.COM * (detected by a timer) or until the instance is picked up again by the same 73*10491SRishi.Srivatsavai@Sun.COM * bridge starting back up. 74*10491SRishi.Srivatsavai@Sun.COM * 75*10491SRishi.Srivatsavai@Sun.COM * bridge_inst_t 76*10491SRishi.Srivatsavai@Sun.COM * Bridge instances are in inst_list, which is protected by inst_lock. 77*10491SRishi.Srivatsavai@Sun.COM * They're allocated by inst_alloc() and freed by inst_free(). After 78*10491SRishi.Srivatsavai@Sun.COM * allocation, an instance is placed in inst_list, and the reference count is 79*10491SRishi.Srivatsavai@Sun.COM * incremented to represent this. That reference is decremented when the 80*10491SRishi.Srivatsavai@Sun.COM * BIF_SHUTDOWN flag is set, and no new increments may occur. When the last 81*10491SRishi.Srivatsavai@Sun.COM * reference is freed, the instance is removed from the list. 82*10491SRishi.Srivatsavai@Sun.COM * 83*10491SRishi.Srivatsavai@Sun.COM * Bridge instances have lists of links and an AVL tree of forwarding 84*10491SRishi.Srivatsavai@Sun.COM * entries. Each of these structures holds one reference on the bridge 85*10491SRishi.Srivatsavai@Sun.COM * instance. These lists and tree are protected by bi_rwlock. 86*10491SRishi.Srivatsavai@Sun.COM * 87*10491SRishi.Srivatsavai@Sun.COM * bridge_stream_t 88*10491SRishi.Srivatsavai@Sun.COM * Bridge streams are allocated by stream_alloc() and freed by stream_free(). 89*10491SRishi.Srivatsavai@Sun.COM * These streams are created when "bridged" opens /dev/bridgectl, and are 90*10491SRishi.Srivatsavai@Sun.COM * used to create new bridge instances (via BRIOC_NEWBRIDGE) and control the 91*10491SRishi.Srivatsavai@Sun.COM * links on the bridge. When a stream closes, the bridge instance created is 92*10491SRishi.Srivatsavai@Sun.COM * destroyed. There's at most one bridge instance for a given control 93*10491SRishi.Srivatsavai@Sun.COM * stream. 94*10491SRishi.Srivatsavai@Sun.COM * 95*10491SRishi.Srivatsavai@Sun.COM * bridge_link_t 96*10491SRishi.Srivatsavai@Sun.COM * Links are allocated by bridge_add_link() and freed by link_free(). The 97*10491SRishi.Srivatsavai@Sun.COM * bi_links list holds a reference to the link. When the BLF_DELETED flag is 98*10491SRishi.Srivatsavai@Sun.COM * set, that reference is dropped. The link isn't removed from the list 99*10491SRishi.Srivatsavai@Sun.COM * until the last reference drops. Each forwarding entry that uses a given 100*10491SRishi.Srivatsavai@Sun.COM * link holds a reference, as does each thread transmitting a packet via the 101*10491SRishi.Srivatsavai@Sun.COM * link. The MAC layer calls in via bridge_ref_cb() to hold a reference on 102*10491SRishi.Srivatsavai@Sun.COM * a link when transmitting. 103*10491SRishi.Srivatsavai@Sun.COM * 104*10491SRishi.Srivatsavai@Sun.COM * It's important that once BLF_DELETED is set, there's no way for the 105*10491SRishi.Srivatsavai@Sun.COM * reference count to increase again. If it can, then the link may be 106*10491SRishi.Srivatsavai@Sun.COM * double-freed. The BLF_FREED flag is intended for use with assertions to 107*10491SRishi.Srivatsavai@Sun.COM * guard against this in testing. 108*10491SRishi.Srivatsavai@Sun.COM * 109*10491SRishi.Srivatsavai@Sun.COM * bridge_fwd_t 110*10491SRishi.Srivatsavai@Sun.COM * Bridge forwarding entries are allocated by bridge_recv_cb() and freed by 111*10491SRishi.Srivatsavai@Sun.COM * fwd_free(). The bi_fwd AVL tree holds one reference to the entry. Unlike 112*10491SRishi.Srivatsavai@Sun.COM * other data structures, the reference is dropped when the entry is removed 113*10491SRishi.Srivatsavai@Sun.COM * from the tree by fwd_delete(), and the BFF_INTREE flag is removed. Each 114*10491SRishi.Srivatsavai@Sun.COM * thread that's forwarding a packet to a known destination holds a reference 115*10491SRishi.Srivatsavai@Sun.COM * to a forwarding entry. 116*10491SRishi.Srivatsavai@Sun.COM * 117*10491SRishi.Srivatsavai@Sun.COM * TRILL notes: 118*10491SRishi.Srivatsavai@Sun.COM * 119*10491SRishi.Srivatsavai@Sun.COM * The TRILL module does all of its I/O through bridging. It uses references 120*10491SRishi.Srivatsavai@Sun.COM * on the bridge_inst_t and bridge_link_t structures, and has seven entry 121*10491SRishi.Srivatsavai@Sun.COM * points and four callbacks. One entry point is for setting the callbacks 122*10491SRishi.Srivatsavai@Sun.COM * (bridge_trill_register_cb). There are four entry points for taking bridge 123*10491SRishi.Srivatsavai@Sun.COM * and link references (bridge_trill_{br,ln}{ref,unref}). The final two 124*10491SRishi.Srivatsavai@Sun.COM * entry points are for decapsulated packets from TRILL (bridge_trill_decaps) 125*10491SRishi.Srivatsavai@Sun.COM * that need to be bridged locally, and for TRILL-encapsulated output packets 126*10491SRishi.Srivatsavai@Sun.COM * (bridge_trill_output). 127*10491SRishi.Srivatsavai@Sun.COM * 128*10491SRishi.Srivatsavai@Sun.COM * The four callbacks comprise two notification functions for bridges and 129*10491SRishi.Srivatsavai@Sun.COM * links being deleted, one function for raw received TRILL packets, and one 130*10491SRishi.Srivatsavai@Sun.COM * for bridge output to non-local TRILL destinations (tunnel entry). 131*10491SRishi.Srivatsavai@Sun.COM */ 132*10491SRishi.Srivatsavai@Sun.COM 133*10491SRishi.Srivatsavai@Sun.COM /* 134*10491SRishi.Srivatsavai@Sun.COM * Ethernet reserved multicast addresses for TRILL; used also in TRILL module. 135*10491SRishi.Srivatsavai@Sun.COM */ 136*10491SRishi.Srivatsavai@Sun.COM const uint8_t all_isis_rbridges[] = ALL_ISIS_RBRIDGES; 137*10491SRishi.Srivatsavai@Sun.COM static const uint8_t all_esadi_rbridges[] = ALL_ESADI_RBRIDGES; 138*10491SRishi.Srivatsavai@Sun.COM const uint8_t bridge_group_address[] = BRIDGE_GROUP_ADDRESS; 139*10491SRishi.Srivatsavai@Sun.COM 140*10491SRishi.Srivatsavai@Sun.COM static const char *inst_kstats_list[] = { KSINST_NAMES }; 141*10491SRishi.Srivatsavai@Sun.COM static const char *link_kstats_list[] = { KSLINK_NAMES }; 142*10491SRishi.Srivatsavai@Sun.COM 143*10491SRishi.Srivatsavai@Sun.COM #define KREF(p, m, vn) p->m.vn.value.ui64 144*10491SRishi.Srivatsavai@Sun.COM #define KINCR(p, m, vn) ++KREF(p, m, vn) 145*10491SRishi.Srivatsavai@Sun.COM #define KDECR(p, m, vn) --KREF(p, m, vn) 146*10491SRishi.Srivatsavai@Sun.COM 147*10491SRishi.Srivatsavai@Sun.COM #define KIPINCR(p, vn) KINCR(p, bi_kstats, vn) 148*10491SRishi.Srivatsavai@Sun.COM #define KIPDECR(p, vn) KDECR(p, bi_kstats, vn) 149*10491SRishi.Srivatsavai@Sun.COM #define KLPINCR(p, vn) KINCR(p, bl_kstats, vn) 150*10491SRishi.Srivatsavai@Sun.COM 151*10491SRishi.Srivatsavai@Sun.COM #define KIINCR(vn) KIPINCR(bip, vn) 152*10491SRishi.Srivatsavai@Sun.COM #define KIDECR(vn) KIPDECR(bip, vn) 153*10491SRishi.Srivatsavai@Sun.COM #define KLINCR(vn) KLPINCR(blp, vn) 154*10491SRishi.Srivatsavai@Sun.COM 155*10491SRishi.Srivatsavai@Sun.COM #define Dim(x) (sizeof (x) / sizeof (*(x))) 156*10491SRishi.Srivatsavai@Sun.COM 157*10491SRishi.Srivatsavai@Sun.COM /* Amount of overhead added when encapsulating with VLAN headers */ 158*10491SRishi.Srivatsavai@Sun.COM #define VLAN_INCR (sizeof (struct ether_vlan_header) - \ 159*10491SRishi.Srivatsavai@Sun.COM sizeof (struct ether_header)) 160*10491SRishi.Srivatsavai@Sun.COM 161*10491SRishi.Srivatsavai@Sun.COM static dev_info_t *bridge_dev_info; 162*10491SRishi.Srivatsavai@Sun.COM static major_t bridge_major; 163*10491SRishi.Srivatsavai@Sun.COM static ddi_taskq_t *bridge_taskq; 164*10491SRishi.Srivatsavai@Sun.COM 165*10491SRishi.Srivatsavai@Sun.COM /* 166*10491SRishi.Srivatsavai@Sun.COM * These are the bridge instance management data structures. The mutex lock 167*10491SRishi.Srivatsavai@Sun.COM * protects the list of bridge instances. A reference count is then used on 168*10491SRishi.Srivatsavai@Sun.COM * each instance to determine when to free it. We use mac_minor_hold() to 169*10491SRishi.Srivatsavai@Sun.COM * allocate minor_t values, which are used both for self-cloning /dev/net/ 170*10491SRishi.Srivatsavai@Sun.COM * device nodes as well as client streams. Minor node 0 is reserved for the 171*10491SRishi.Srivatsavai@Sun.COM * allocation control node. 172*10491SRishi.Srivatsavai@Sun.COM */ 173*10491SRishi.Srivatsavai@Sun.COM static list_t inst_list; 174*10491SRishi.Srivatsavai@Sun.COM static kcondvar_t inst_cv; /* Allows us to wait for shutdown */ 175*10491SRishi.Srivatsavai@Sun.COM static kmutex_t inst_lock; 176*10491SRishi.Srivatsavai@Sun.COM 177*10491SRishi.Srivatsavai@Sun.COM static krwlock_t bmac_rwlock; 178*10491SRishi.Srivatsavai@Sun.COM static list_t bmac_list; 179*10491SRishi.Srivatsavai@Sun.COM 180*10491SRishi.Srivatsavai@Sun.COM /* Wait for taskq entries that use STREAMS */ 181*10491SRishi.Srivatsavai@Sun.COM static kcondvar_t stream_ref_cv; 182*10491SRishi.Srivatsavai@Sun.COM static kmutex_t stream_ref_lock; 183*10491SRishi.Srivatsavai@Sun.COM 184*10491SRishi.Srivatsavai@Sun.COM static timeout_id_t bridge_timerid; 185*10491SRishi.Srivatsavai@Sun.COM static clock_t bridge_scan_interval; 186*10491SRishi.Srivatsavai@Sun.COM static clock_t bridge_fwd_age; 187*10491SRishi.Srivatsavai@Sun.COM 188*10491SRishi.Srivatsavai@Sun.COM static bridge_inst_t *bridge_find_name(const char *); 189*10491SRishi.Srivatsavai@Sun.COM static void bridge_timer(void *); 190*10491SRishi.Srivatsavai@Sun.COM static void bridge_unref(bridge_inst_t *); 191*10491SRishi.Srivatsavai@Sun.COM 192*10491SRishi.Srivatsavai@Sun.COM static const uint8_t zero_addr[ETHERADDRL] = { 0 }; 193*10491SRishi.Srivatsavai@Sun.COM 194*10491SRishi.Srivatsavai@Sun.COM /* Global TRILL linkage */ 195*10491SRishi.Srivatsavai@Sun.COM static trill_recv_pkt_t trill_recv_fn; 196*10491SRishi.Srivatsavai@Sun.COM static trill_encap_pkt_t trill_encap_fn; 197*10491SRishi.Srivatsavai@Sun.COM static trill_br_dstr_t trill_brdstr_fn; 198*10491SRishi.Srivatsavai@Sun.COM static trill_ln_dstr_t trill_lndstr_fn; 199*10491SRishi.Srivatsavai@Sun.COM 200*10491SRishi.Srivatsavai@Sun.COM /* special settings to accommodate DLD flow control; see dld_str.c */ 201*10491SRishi.Srivatsavai@Sun.COM static struct module_info bridge_dld_modinfo = { 202*10491SRishi.Srivatsavai@Sun.COM 0, /* mi_idnum */ 203*10491SRishi.Srivatsavai@Sun.COM "bridge", /* mi_idname */ 204*10491SRishi.Srivatsavai@Sun.COM 0, /* mi_minpsz */ 205*10491SRishi.Srivatsavai@Sun.COM INFPSZ, /* mi_maxpsz */ 206*10491SRishi.Srivatsavai@Sun.COM 1, /* mi_hiwat */ 207*10491SRishi.Srivatsavai@Sun.COM 0 /* mi_lowat */ 208*10491SRishi.Srivatsavai@Sun.COM }; 209*10491SRishi.Srivatsavai@Sun.COM 210*10491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_dld_rinit = { 211*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_putp */ 212*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_srvp */ 213*10491SRishi.Srivatsavai@Sun.COM dld_open, /* qi_qopen */ 214*10491SRishi.Srivatsavai@Sun.COM dld_close, /* qi_qclose */ 215*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 216*10491SRishi.Srivatsavai@Sun.COM &bridge_dld_modinfo, /* qi_minfo */ 217*10491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 218*10491SRishi.Srivatsavai@Sun.COM }; 219*10491SRishi.Srivatsavai@Sun.COM 220*10491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_dld_winit = { 221*10491SRishi.Srivatsavai@Sun.COM (int (*)())dld_wput, /* qi_putp */ 222*10491SRishi.Srivatsavai@Sun.COM (int (*)())dld_wsrv, /* qi_srvp */ 223*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qopen */ 224*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qclose */ 225*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 226*10491SRishi.Srivatsavai@Sun.COM &bridge_dld_modinfo, /* qi_minfo */ 227*10491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 228*10491SRishi.Srivatsavai@Sun.COM }; 229*10491SRishi.Srivatsavai@Sun.COM 230*10491SRishi.Srivatsavai@Sun.COM static int bridge_ioc_listfwd(void *, intptr_t, int, cred_t *, int *); 231*10491SRishi.Srivatsavai@Sun.COM 232*10491SRishi.Srivatsavai@Sun.COM /* GLDv3 control ioctls used by Bridging */ 233*10491SRishi.Srivatsavai@Sun.COM static dld_ioc_info_t bridge_ioc_list[] = { 234*10491SRishi.Srivatsavai@Sun.COM {BRIDGE_IOC_LISTFWD, DLDCOPYINOUT, sizeof (bridge_listfwd_t), 235*10491SRishi.Srivatsavai@Sun.COM bridge_ioc_listfwd, NULL}, 236*10491SRishi.Srivatsavai@Sun.COM }; 237*10491SRishi.Srivatsavai@Sun.COM 238*10491SRishi.Srivatsavai@Sun.COM /* 239*10491SRishi.Srivatsavai@Sun.COM * Given a bridge mac pointer, get a ref-held pointer to the corresponding 240*10491SRishi.Srivatsavai@Sun.COM * bridge instance, if any. We must hold the global bmac_rwlock so that 241*10491SRishi.Srivatsavai@Sun.COM * bm_inst doesn't slide out from under us. 242*10491SRishi.Srivatsavai@Sun.COM */ 243*10491SRishi.Srivatsavai@Sun.COM static bridge_inst_t * 244*10491SRishi.Srivatsavai@Sun.COM mac_to_inst(const bridge_mac_t *bmp) 245*10491SRishi.Srivatsavai@Sun.COM { 246*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 247*10491SRishi.Srivatsavai@Sun.COM 248*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_READER); 249*10491SRishi.Srivatsavai@Sun.COM if ((bip = bmp->bm_inst) != NULL) 250*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 251*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 252*10491SRishi.Srivatsavai@Sun.COM return (bip); 253*10491SRishi.Srivatsavai@Sun.COM } 254*10491SRishi.Srivatsavai@Sun.COM 255*10491SRishi.Srivatsavai@Sun.COM static void 256*10491SRishi.Srivatsavai@Sun.COM link_sdu_fail(bridge_link_t *blp, boolean_t failed, mblk_t **mlist) 257*10491SRishi.Srivatsavai@Sun.COM { 258*10491SRishi.Srivatsavai@Sun.COM mblk_t *mp; 259*10491SRishi.Srivatsavai@Sun.COM bridge_ctl_t *bcp; 260*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blcmp; 261*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 262*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 263*10491SRishi.Srivatsavai@Sun.COM 264*10491SRishi.Srivatsavai@Sun.COM if (failed) { 265*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_SDUFAIL) 266*10491SRishi.Srivatsavai@Sun.COM return; 267*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_SDUFAIL; 268*10491SRishi.Srivatsavai@Sun.COM } else { 269*10491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_SDUFAIL)) 270*10491SRishi.Srivatsavai@Sun.COM return; 271*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags &= ~BLF_SDUFAIL; 272*10491SRishi.Srivatsavai@Sun.COM } 273*10491SRishi.Srivatsavai@Sun.COM 274*10491SRishi.Srivatsavai@Sun.COM /* 275*10491SRishi.Srivatsavai@Sun.COM * If this link is otherwise up, then check if there are any other 276*10491SRishi.Srivatsavai@Sun.COM * non-failed non-down links. If not, then we control the state of the 277*10491SRishi.Srivatsavai@Sun.COM * whole bridge. 278*10491SRishi.Srivatsavai@Sun.COM */ 279*10491SRishi.Srivatsavai@Sun.COM bip = blp->bl_inst; 280*10491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 281*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkstate != LINK_STATE_DOWN) { 282*10491SRishi.Srivatsavai@Sun.COM for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 283*10491SRishi.Srivatsavai@Sun.COM blcmp = list_next(&bip->bi_links, blcmp)) { 284*10491SRishi.Srivatsavai@Sun.COM if (blp != blcmp && 285*10491SRishi.Srivatsavai@Sun.COM !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) && 286*10491SRishi.Srivatsavai@Sun.COM blcmp->bl_linkstate != LINK_STATE_DOWN) 287*10491SRishi.Srivatsavai@Sun.COM break; 288*10491SRishi.Srivatsavai@Sun.COM } 289*10491SRishi.Srivatsavai@Sun.COM if (blcmp == NULL) { 290*10491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = failed ? LINK_STATE_DOWN : 291*10491SRishi.Srivatsavai@Sun.COM LINK_STATE_UP; 292*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, bmp->bm_linkstate); 293*10491SRishi.Srivatsavai@Sun.COM } 294*10491SRishi.Srivatsavai@Sun.COM } 295*10491SRishi.Srivatsavai@Sun.COM 296*10491SRishi.Srivatsavai@Sun.COM /* 297*10491SRishi.Srivatsavai@Sun.COM * If we're becoming failed, then the link's current true state needs 298*10491SRishi.Srivatsavai@Sun.COM * to be reflected upwards to this link's clients. If we're becoming 299*10491SRishi.Srivatsavai@Sun.COM * unfailed, then we get the state of the bridge instead on all 300*10491SRishi.Srivatsavai@Sun.COM * clients. 301*10491SRishi.Srivatsavai@Sun.COM */ 302*10491SRishi.Srivatsavai@Sun.COM if (failed) { 303*10491SRishi.Srivatsavai@Sun.COM if (bmp->bm_linkstate != blp->bl_linkstate) 304*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, blp->bl_linkstate); 305*10491SRishi.Srivatsavai@Sun.COM } else { 306*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, bmp->bm_linkstate); 307*10491SRishi.Srivatsavai@Sun.COM } 308*10491SRishi.Srivatsavai@Sun.COM 309*10491SRishi.Srivatsavai@Sun.COM /* get the current mblk we're going to send up */ 310*10491SRishi.Srivatsavai@Sun.COM if ((mp = blp->bl_lfailmp) == NULL && 311*10491SRishi.Srivatsavai@Sun.COM (mp = allocb(sizeof (bridge_ctl_t), BPRI_MED)) == NULL) 312*10491SRishi.Srivatsavai@Sun.COM return; 313*10491SRishi.Srivatsavai@Sun.COM 314*10491SRishi.Srivatsavai@Sun.COM /* get a new one for next time */ 315*10491SRishi.Srivatsavai@Sun.COM blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED); 316*10491SRishi.Srivatsavai@Sun.COM 317*10491SRishi.Srivatsavai@Sun.COM /* if none for next time, then report only failures */ 318*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_lfailmp == NULL && !failed) { 319*10491SRishi.Srivatsavai@Sun.COM blp->bl_lfailmp = mp; 320*10491SRishi.Srivatsavai@Sun.COM return; 321*10491SRishi.Srivatsavai@Sun.COM } 322*10491SRishi.Srivatsavai@Sun.COM 323*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 324*10491SRishi.Srivatsavai@Sun.COM bcp = (bridge_ctl_t *)mp->b_rptr; 325*10491SRishi.Srivatsavai@Sun.COM bcp->bc_linkid = blp->bl_linkid; 326*10491SRishi.Srivatsavai@Sun.COM bcp->bc_failed = failed; 327*10491SRishi.Srivatsavai@Sun.COM mp->b_wptr = (uchar_t *)(bcp + 1); 328*10491SRishi.Srivatsavai@Sun.COM mp->b_next = *mlist; 329*10491SRishi.Srivatsavai@Sun.COM *mlist = mp; 330*10491SRishi.Srivatsavai@Sun.COM } 331*10491SRishi.Srivatsavai@Sun.COM 332*10491SRishi.Srivatsavai@Sun.COM /* 333*10491SRishi.Srivatsavai@Sun.COM * Send control messages (link SDU changes) using the stream to the 334*10491SRishi.Srivatsavai@Sun.COM * bridge instance daemon. 335*10491SRishi.Srivatsavai@Sun.COM */ 336*10491SRishi.Srivatsavai@Sun.COM static void 337*10491SRishi.Srivatsavai@Sun.COM send_up_messages(bridge_inst_t *bip, mblk_t *mp) 338*10491SRishi.Srivatsavai@Sun.COM { 339*10491SRishi.Srivatsavai@Sun.COM mblk_t *mnext; 340*10491SRishi.Srivatsavai@Sun.COM queue_t *rq; 341*10491SRishi.Srivatsavai@Sun.COM 342*10491SRishi.Srivatsavai@Sun.COM rq = bip->bi_control->bs_wq; 343*10491SRishi.Srivatsavai@Sun.COM rq = OTHERQ(rq); 344*10491SRishi.Srivatsavai@Sun.COM while (mp != NULL) { 345*10491SRishi.Srivatsavai@Sun.COM mnext = mp->b_next; 346*10491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 347*10491SRishi.Srivatsavai@Sun.COM putnext(rq, mp); 348*10491SRishi.Srivatsavai@Sun.COM mp = mnext; 349*10491SRishi.Srivatsavai@Sun.COM } 350*10491SRishi.Srivatsavai@Sun.COM } 351*10491SRishi.Srivatsavai@Sun.COM 352*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 353*10491SRishi.Srivatsavai@Sun.COM static int 354*10491SRishi.Srivatsavai@Sun.COM bridge_m_getstat(void *arg, uint_t stat, uint64_t *val) 355*10491SRishi.Srivatsavai@Sun.COM { 356*10491SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 357*10491SRishi.Srivatsavai@Sun.COM } 358*10491SRishi.Srivatsavai@Sun.COM 359*10491SRishi.Srivatsavai@Sun.COM static int 360*10491SRishi.Srivatsavai@Sun.COM bridge_m_start(void *arg) 361*10491SRishi.Srivatsavai@Sun.COM { 362*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 363*10491SRishi.Srivatsavai@Sun.COM 364*10491SRishi.Srivatsavai@Sun.COM bmp->bm_flags |= BMF_STARTED; 365*10491SRishi.Srivatsavai@Sun.COM return (0); 366*10491SRishi.Srivatsavai@Sun.COM } 367*10491SRishi.Srivatsavai@Sun.COM 368*10491SRishi.Srivatsavai@Sun.COM static void 369*10491SRishi.Srivatsavai@Sun.COM bridge_m_stop(void *arg) 370*10491SRishi.Srivatsavai@Sun.COM { 371*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 372*10491SRishi.Srivatsavai@Sun.COM 373*10491SRishi.Srivatsavai@Sun.COM bmp->bm_flags &= ~BMF_STARTED; 374*10491SRishi.Srivatsavai@Sun.COM } 375*10491SRishi.Srivatsavai@Sun.COM 376*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 377*10491SRishi.Srivatsavai@Sun.COM static int 378*10491SRishi.Srivatsavai@Sun.COM bridge_m_setpromisc(void *arg, boolean_t on) 379*10491SRishi.Srivatsavai@Sun.COM { 380*10491SRishi.Srivatsavai@Sun.COM return (0); 381*10491SRishi.Srivatsavai@Sun.COM } 382*10491SRishi.Srivatsavai@Sun.COM 383*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 384*10491SRishi.Srivatsavai@Sun.COM static int 385*10491SRishi.Srivatsavai@Sun.COM bridge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 386*10491SRishi.Srivatsavai@Sun.COM { 387*10491SRishi.Srivatsavai@Sun.COM return (0); 388*10491SRishi.Srivatsavai@Sun.COM } 389*10491SRishi.Srivatsavai@Sun.COM 390*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 391*10491SRishi.Srivatsavai@Sun.COM static int 392*10491SRishi.Srivatsavai@Sun.COM bridge_m_unicst(void *arg, const uint8_t *macaddr) 393*10491SRishi.Srivatsavai@Sun.COM { 394*10491SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 395*10491SRishi.Srivatsavai@Sun.COM } 396*10491SRishi.Srivatsavai@Sun.COM 397*10491SRishi.Srivatsavai@Sun.COM static mblk_t * 398*10491SRishi.Srivatsavai@Sun.COM bridge_m_tx(void *arg, mblk_t *mp) 399*10491SRishi.Srivatsavai@Sun.COM { 400*10491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(arg)); 401*10491SRishi.Srivatsavai@Sun.COM freemsgchain(mp); 402*10491SRishi.Srivatsavai@Sun.COM return (NULL); 403*10491SRishi.Srivatsavai@Sun.COM } 404*10491SRishi.Srivatsavai@Sun.COM 405*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 406*10491SRishi.Srivatsavai@Sun.COM static int 407*10491SRishi.Srivatsavai@Sun.COM bridge_ioc_listfwd(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 408*10491SRishi.Srivatsavai@Sun.COM { 409*10491SRishi.Srivatsavai@Sun.COM bridge_listfwd_t *blf = karg; 410*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 411*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, match; 412*10491SRishi.Srivatsavai@Sun.COM avl_index_t where; 413*10491SRishi.Srivatsavai@Sun.COM 414*10491SRishi.Srivatsavai@Sun.COM bip = bridge_find_name(blf->blf_name); 415*10491SRishi.Srivatsavai@Sun.COM if (bip == NULL) 416*10491SRishi.Srivatsavai@Sun.COM return (ENOENT); 417*10491SRishi.Srivatsavai@Sun.COM 418*10491SRishi.Srivatsavai@Sun.COM bcopy(blf->blf_dest, match.bf_dest, ETHERADDRL); 419*10491SRishi.Srivatsavai@Sun.COM match.bf_flags |= BFF_VLANLOCAL; 420*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 421*10491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, &where)) == NULL) 422*10491SRishi.Srivatsavai@Sun.COM bfp = avl_nearest(&bip->bi_fwd, where, AVL_AFTER); 423*10491SRishi.Srivatsavai@Sun.COM else 424*10491SRishi.Srivatsavai@Sun.COM bfp = AVL_NEXT(&bip->bi_fwd, bfp); 425*10491SRishi.Srivatsavai@Sun.COM if (bfp == NULL) { 426*10491SRishi.Srivatsavai@Sun.COM bzero(blf, sizeof (*blf)); 427*10491SRishi.Srivatsavai@Sun.COM } else { 428*10491SRishi.Srivatsavai@Sun.COM bcopy(bfp->bf_dest, blf->blf_dest, ETHERADDRL); 429*10491SRishi.Srivatsavai@Sun.COM blf->blf_trill_nick = bfp->bf_trill_nick; 430*10491SRishi.Srivatsavai@Sun.COM blf->blf_ms_age = 431*10491SRishi.Srivatsavai@Sun.COM drv_hztousec(lbolt - bfp->bf_lastheard) / 1000; 432*10491SRishi.Srivatsavai@Sun.COM blf->blf_is_local = 433*10491SRishi.Srivatsavai@Sun.COM (bfp->bf_flags & BFF_LOCALADDR) != 0; 434*10491SRishi.Srivatsavai@Sun.COM blf->blf_linkid = bfp->bf_links[0]->bl_linkid; 435*10491SRishi.Srivatsavai@Sun.COM } 436*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 437*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 438*10491SRishi.Srivatsavai@Sun.COM return (0); 439*10491SRishi.Srivatsavai@Sun.COM } 440*10491SRishi.Srivatsavai@Sun.COM 441*10491SRishi.Srivatsavai@Sun.COM static int 442*10491SRishi.Srivatsavai@Sun.COM bridge_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 443*10491SRishi.Srivatsavai@Sun.COM uint_t pr_valsize, const void *pr_val) 444*10491SRishi.Srivatsavai@Sun.COM { 445*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 446*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 447*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 448*10491SRishi.Srivatsavai@Sun.COM int err; 449*10491SRishi.Srivatsavai@Sun.COM uint_t maxsdu; 450*10491SRishi.Srivatsavai@Sun.COM mblk_t *mlist; 451*10491SRishi.Srivatsavai@Sun.COM 452*10491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(pr_name)); 453*10491SRishi.Srivatsavai@Sun.COM switch (pr_num) { 454*10491SRishi.Srivatsavai@Sun.COM case MAC_PROP_MTU: 455*10491SRishi.Srivatsavai@Sun.COM if (pr_valsize < sizeof (bmp->bm_maxsdu)) { 456*10491SRishi.Srivatsavai@Sun.COM err = EINVAL; 457*10491SRishi.Srivatsavai@Sun.COM break; 458*10491SRishi.Srivatsavai@Sun.COM } 459*10491SRishi.Srivatsavai@Sun.COM (void) bcopy(pr_val, &maxsdu, sizeof (maxsdu)); 460*10491SRishi.Srivatsavai@Sun.COM if (maxsdu == bmp->bm_maxsdu) { 461*10491SRishi.Srivatsavai@Sun.COM err = 0; 462*10491SRishi.Srivatsavai@Sun.COM } else if ((bip = mac_to_inst(bmp)) == NULL) { 463*10491SRishi.Srivatsavai@Sun.COM err = ENXIO; 464*10491SRishi.Srivatsavai@Sun.COM } else { 465*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 466*10491SRishi.Srivatsavai@Sun.COM mlist = NULL; 467*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 468*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 469*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_DELETED) 470*10491SRishi.Srivatsavai@Sun.COM continue; 471*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_maxsdu == maxsdu) 472*10491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_FALSE, &mlist); 473*10491SRishi.Srivatsavai@Sun.COM else if (blp->bl_maxsdu == bmp->bm_maxsdu) 474*10491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_TRUE, &mlist); 475*10491SRishi.Srivatsavai@Sun.COM } 476*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 477*10491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = maxsdu; 478*10491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 479*10491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 480*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 481*10491SRishi.Srivatsavai@Sun.COM err = 0; 482*10491SRishi.Srivatsavai@Sun.COM } 483*10491SRishi.Srivatsavai@Sun.COM break; 484*10491SRishi.Srivatsavai@Sun.COM 485*10491SRishi.Srivatsavai@Sun.COM default: 486*10491SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 487*10491SRishi.Srivatsavai@Sun.COM break; 488*10491SRishi.Srivatsavai@Sun.COM } 489*10491SRishi.Srivatsavai@Sun.COM return (err); 490*10491SRishi.Srivatsavai@Sun.COM } 491*10491SRishi.Srivatsavai@Sun.COM 492*10491SRishi.Srivatsavai@Sun.COM static int 493*10491SRishi.Srivatsavai@Sun.COM bridge_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 494*10491SRishi.Srivatsavai@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 495*10491SRishi.Srivatsavai@Sun.COM { 496*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 497*10491SRishi.Srivatsavai@Sun.COM int err = 0; 498*10491SRishi.Srivatsavai@Sun.COM 499*10491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(pr_name)); 500*10491SRishi.Srivatsavai@Sun.COM switch (pr_num) { 501*10491SRishi.Srivatsavai@Sun.COM case MAC_PROP_MTU: { 502*10491SRishi.Srivatsavai@Sun.COM mac_propval_range_t range; 503*10491SRishi.Srivatsavai@Sun.COM 504*10491SRishi.Srivatsavai@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 505*10491SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 506*10491SRishi.Srivatsavai@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 507*10491SRishi.Srivatsavai@Sun.COM return (EINVAL); 508*10491SRishi.Srivatsavai@Sun.COM range.mpr_count = 1; 509*10491SRishi.Srivatsavai@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 510*10491SRishi.Srivatsavai@Sun.COM range.range_uint32[0].mpur_min = 511*10491SRishi.Srivatsavai@Sun.COM range.range_uint32[0].mpur_max = bmp->bm_maxsdu; 512*10491SRishi.Srivatsavai@Sun.COM bcopy(&range, pr_val, sizeof (range)); 513*10491SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_RW; 514*10491SRishi.Srivatsavai@Sun.COM break; 515*10491SRishi.Srivatsavai@Sun.COM } 516*10491SRishi.Srivatsavai@Sun.COM case MAC_PROP_STATUS: 517*10491SRishi.Srivatsavai@Sun.COM if (pr_valsize < sizeof (bmp->bm_linkstate)) { 518*10491SRishi.Srivatsavai@Sun.COM err = EINVAL; 519*10491SRishi.Srivatsavai@Sun.COM } else { 520*10491SRishi.Srivatsavai@Sun.COM bcopy(&bmp->bm_linkstate, pr_val, 521*10491SRishi.Srivatsavai@Sun.COM sizeof (&bmp->bm_linkstate)); 522*10491SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_READ; 523*10491SRishi.Srivatsavai@Sun.COM } 524*10491SRishi.Srivatsavai@Sun.COM break; 525*10491SRishi.Srivatsavai@Sun.COM 526*10491SRishi.Srivatsavai@Sun.COM default: 527*10491SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 528*10491SRishi.Srivatsavai@Sun.COM break; 529*10491SRishi.Srivatsavai@Sun.COM } 530*10491SRishi.Srivatsavai@Sun.COM return (err); 531*10491SRishi.Srivatsavai@Sun.COM } 532*10491SRishi.Srivatsavai@Sun.COM 533*10491SRishi.Srivatsavai@Sun.COM static mac_callbacks_t bridge_m_callbacks = { 534*10491SRishi.Srivatsavai@Sun.COM MC_SETPROP | MC_GETPROP, 535*10491SRishi.Srivatsavai@Sun.COM bridge_m_getstat, 536*10491SRishi.Srivatsavai@Sun.COM bridge_m_start, 537*10491SRishi.Srivatsavai@Sun.COM bridge_m_stop, 538*10491SRishi.Srivatsavai@Sun.COM bridge_m_setpromisc, 539*10491SRishi.Srivatsavai@Sun.COM bridge_m_multicst, 540*10491SRishi.Srivatsavai@Sun.COM bridge_m_unicst, 541*10491SRishi.Srivatsavai@Sun.COM bridge_m_tx, 542*10491SRishi.Srivatsavai@Sun.COM NULL, /* ioctl */ 543*10491SRishi.Srivatsavai@Sun.COM NULL, /* getcapab */ 544*10491SRishi.Srivatsavai@Sun.COM NULL, /* open */ 545*10491SRishi.Srivatsavai@Sun.COM NULL, /* close */ 546*10491SRishi.Srivatsavai@Sun.COM bridge_m_setprop, 547*10491SRishi.Srivatsavai@Sun.COM bridge_m_getprop 548*10491SRishi.Srivatsavai@Sun.COM }; 549*10491SRishi.Srivatsavai@Sun.COM 550*10491SRishi.Srivatsavai@Sun.COM /* 551*10491SRishi.Srivatsavai@Sun.COM * Create kstats from a list. 552*10491SRishi.Srivatsavai@Sun.COM */ 553*10491SRishi.Srivatsavai@Sun.COM static kstat_t * 554*10491SRishi.Srivatsavai@Sun.COM kstat_setup(kstat_named_t *knt, const char **names, int nstat, 555*10491SRishi.Srivatsavai@Sun.COM const char *unitname) 556*10491SRishi.Srivatsavai@Sun.COM { 557*10491SRishi.Srivatsavai@Sun.COM kstat_t *ksp; 558*10491SRishi.Srivatsavai@Sun.COM int i; 559*10491SRishi.Srivatsavai@Sun.COM 560*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < nstat; i++) 561*10491SRishi.Srivatsavai@Sun.COM kstat_named_init(&knt[i], names[i], KSTAT_DATA_UINT64); 562*10491SRishi.Srivatsavai@Sun.COM 563*10491SRishi.Srivatsavai@Sun.COM ksp = kstat_create_zone("bridge", 0, unitname, "net", 564*10491SRishi.Srivatsavai@Sun.COM KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID); 565*10491SRishi.Srivatsavai@Sun.COM if (ksp != NULL) { 566*10491SRishi.Srivatsavai@Sun.COM ksp->ks_data = knt; 567*10491SRishi.Srivatsavai@Sun.COM kstat_install(ksp); 568*10491SRishi.Srivatsavai@Sun.COM } 569*10491SRishi.Srivatsavai@Sun.COM return (ksp); 570*10491SRishi.Srivatsavai@Sun.COM } 571*10491SRishi.Srivatsavai@Sun.COM 572*10491SRishi.Srivatsavai@Sun.COM /* 573*10491SRishi.Srivatsavai@Sun.COM * Find an existing bridge_mac_t structure or allocate a new one for the given 574*10491SRishi.Srivatsavai@Sun.COM * bridge instance. This creates the mac driver instance that snoop can use. 575*10491SRishi.Srivatsavai@Sun.COM */ 576*10491SRishi.Srivatsavai@Sun.COM static int 577*10491SRishi.Srivatsavai@Sun.COM bmac_alloc(bridge_inst_t *bip, bridge_mac_t **bmacp) 578*10491SRishi.Srivatsavai@Sun.COM { 579*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp, *bnew; 580*10491SRishi.Srivatsavai@Sun.COM mac_register_t *mac; 581*10491SRishi.Srivatsavai@Sun.COM int err; 582*10491SRishi.Srivatsavai@Sun.COM 583*10491SRishi.Srivatsavai@Sun.COM *bmacp = NULL; 584*10491SRishi.Srivatsavai@Sun.COM if ((mac = mac_alloc(MAC_VERSION)) == NULL) 585*10491SRishi.Srivatsavai@Sun.COM return (EINVAL); 586*10491SRishi.Srivatsavai@Sun.COM 587*10491SRishi.Srivatsavai@Sun.COM bnew = kmem_zalloc(sizeof (*bnew), KM_SLEEP); 588*10491SRishi.Srivatsavai@Sun.COM 589*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_WRITER); 590*10491SRishi.Srivatsavai@Sun.COM for (bmp = list_head(&bmac_list); bmp != NULL; 591*10491SRishi.Srivatsavai@Sun.COM bmp = list_next(&bmac_list, bmp)) { 592*10491SRishi.Srivatsavai@Sun.COM if (strcmp(bip->bi_name, bmp->bm_name) == 0) { 593*10491SRishi.Srivatsavai@Sun.COM ASSERT(bmp->bm_inst == NULL); 594*10491SRishi.Srivatsavai@Sun.COM bmp->bm_inst = bip; 595*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 596*10491SRishi.Srivatsavai@Sun.COM kmem_free(bnew, sizeof (*bnew)); 597*10491SRishi.Srivatsavai@Sun.COM mac_free(mac); 598*10491SRishi.Srivatsavai@Sun.COM *bmacp = bmp; 599*10491SRishi.Srivatsavai@Sun.COM return (0); 600*10491SRishi.Srivatsavai@Sun.COM } 601*10491SRishi.Srivatsavai@Sun.COM } 602*10491SRishi.Srivatsavai@Sun.COM 603*10491SRishi.Srivatsavai@Sun.COM mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 604*10491SRishi.Srivatsavai@Sun.COM mac->m_driver = bnew; 605*10491SRishi.Srivatsavai@Sun.COM mac->m_dip = bridge_dev_info; 606*10491SRishi.Srivatsavai@Sun.COM mac->m_instance = (uint_t)-1; 607*10491SRishi.Srivatsavai@Sun.COM mac->m_src_addr = (uint8_t *)zero_addr; 608*10491SRishi.Srivatsavai@Sun.COM mac->m_callbacks = &bridge_m_callbacks; 609*10491SRishi.Srivatsavai@Sun.COM 610*10491SRishi.Srivatsavai@Sun.COM /* 611*10491SRishi.Srivatsavai@Sun.COM * Note that the SDU limits are irrelevant, as nobody transmits on the 612*10491SRishi.Srivatsavai@Sun.COM * bridge node itself. It's mainly for monitoring but we allow 613*10491SRishi.Srivatsavai@Sun.COM * setting the bridge MTU for quick transition of all links part of the 614*10491SRishi.Srivatsavai@Sun.COM * bridge to a new MTU. 615*10491SRishi.Srivatsavai@Sun.COM */ 616*10491SRishi.Srivatsavai@Sun.COM mac->m_min_sdu = 1; 617*10491SRishi.Srivatsavai@Sun.COM mac->m_max_sdu = 1500; 618*10491SRishi.Srivatsavai@Sun.COM err = mac_register(mac, &bnew->bm_mh); 619*10491SRishi.Srivatsavai@Sun.COM mac_free(mac); 620*10491SRishi.Srivatsavai@Sun.COM if (err != 0) { 621*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 622*10491SRishi.Srivatsavai@Sun.COM kmem_free(bnew, sizeof (*bnew)); 623*10491SRishi.Srivatsavai@Sun.COM return (err); 624*10491SRishi.Srivatsavai@Sun.COM } 625*10491SRishi.Srivatsavai@Sun.COM 626*10491SRishi.Srivatsavai@Sun.COM bnew->bm_inst = bip; 627*10491SRishi.Srivatsavai@Sun.COM (void) strcpy(bnew->bm_name, bip->bi_name); 628*10491SRishi.Srivatsavai@Sun.COM if (list_is_empty(&bmac_list)) { 629*10491SRishi.Srivatsavai@Sun.COM bridge_timerid = timeout(bridge_timer, NULL, 630*10491SRishi.Srivatsavai@Sun.COM bridge_scan_interval); 631*10491SRishi.Srivatsavai@Sun.COM } 632*10491SRishi.Srivatsavai@Sun.COM list_insert_tail(&bmac_list, bnew); 633*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 634*10491SRishi.Srivatsavai@Sun.COM 635*10491SRishi.Srivatsavai@Sun.COM /* 636*10491SRishi.Srivatsavai@Sun.COM * Mark the MAC as unable to go "active" so that only passive clients 637*10491SRishi.Srivatsavai@Sun.COM * (such as snoop) can bind to it. 638*10491SRishi.Srivatsavai@Sun.COM */ 639*10491SRishi.Srivatsavai@Sun.COM mac_no_active(bnew->bm_mh); 640*10491SRishi.Srivatsavai@Sun.COM *bmacp = bnew; 641*10491SRishi.Srivatsavai@Sun.COM return (0); 642*10491SRishi.Srivatsavai@Sun.COM } 643*10491SRishi.Srivatsavai@Sun.COM 644*10491SRishi.Srivatsavai@Sun.COM /* 645*10491SRishi.Srivatsavai@Sun.COM * Disconnect the given bridge_mac_t from its bridge instance. The bridge 646*10491SRishi.Srivatsavai@Sun.COM * instance is going away. The mac instance can't go away until the clients 647*10491SRishi.Srivatsavai@Sun.COM * are gone (see bridge_timer). 648*10491SRishi.Srivatsavai@Sun.COM */ 649*10491SRishi.Srivatsavai@Sun.COM static void 650*10491SRishi.Srivatsavai@Sun.COM bmac_disconnect(bridge_mac_t *bmp) 651*10491SRishi.Srivatsavai@Sun.COM { 652*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 653*10491SRishi.Srivatsavai@Sun.COM 654*10491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = LINK_STATE_DOWN; 655*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN); 656*10491SRishi.Srivatsavai@Sun.COM 657*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_READER); 658*10491SRishi.Srivatsavai@Sun.COM bip = bmp->bm_inst; 659*10491SRishi.Srivatsavai@Sun.COM bip->bi_mac = NULL; 660*10491SRishi.Srivatsavai@Sun.COM bmp->bm_inst = NULL; 661*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 662*10491SRishi.Srivatsavai@Sun.COM } 663*10491SRishi.Srivatsavai@Sun.COM 664*10491SRishi.Srivatsavai@Sun.COM /* This is used by the avl trees to sort forwarding table entries */ 665*10491SRishi.Srivatsavai@Sun.COM static int 666*10491SRishi.Srivatsavai@Sun.COM fwd_compare(const void *addr1, const void *addr2) 667*10491SRishi.Srivatsavai@Sun.COM { 668*10491SRishi.Srivatsavai@Sun.COM const bridge_fwd_t *fwd1 = addr1; 669*10491SRishi.Srivatsavai@Sun.COM const bridge_fwd_t *fwd2 = addr2; 670*10491SRishi.Srivatsavai@Sun.COM int diff = memcmp(fwd1->bf_dest, fwd2->bf_dest, ETHERADDRL); 671*10491SRishi.Srivatsavai@Sun.COM 672*10491SRishi.Srivatsavai@Sun.COM if (diff != 0) 673*10491SRishi.Srivatsavai@Sun.COM return (diff > 0 ? 1 : -1); 674*10491SRishi.Srivatsavai@Sun.COM 675*10491SRishi.Srivatsavai@Sun.COM if ((fwd1->bf_flags ^ fwd2->bf_flags) & BFF_VLANLOCAL) { 676*10491SRishi.Srivatsavai@Sun.COM if (fwd1->bf_vlanid > fwd2->bf_vlanid) 677*10491SRishi.Srivatsavai@Sun.COM return (1); 678*10491SRishi.Srivatsavai@Sun.COM else if (fwd1->bf_vlanid < fwd2->bf_vlanid) 679*10491SRishi.Srivatsavai@Sun.COM return (-1); 680*10491SRishi.Srivatsavai@Sun.COM } 681*10491SRishi.Srivatsavai@Sun.COM return (0); 682*10491SRishi.Srivatsavai@Sun.COM } 683*10491SRishi.Srivatsavai@Sun.COM 684*10491SRishi.Srivatsavai@Sun.COM static void 685*10491SRishi.Srivatsavai@Sun.COM inst_free(bridge_inst_t *bip) 686*10491SRishi.Srivatsavai@Sun.COM { 687*10491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_mac == NULL); 688*10491SRishi.Srivatsavai@Sun.COM rw_destroy(&bip->bi_rwlock); 689*10491SRishi.Srivatsavai@Sun.COM list_destroy(&bip->bi_links); 690*10491SRishi.Srivatsavai@Sun.COM cv_destroy(&bip->bi_linkwait); 691*10491SRishi.Srivatsavai@Sun.COM avl_destroy(&bip->bi_fwd); 692*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_ksp != NULL) 693*10491SRishi.Srivatsavai@Sun.COM kstat_delete(bip->bi_ksp); 694*10491SRishi.Srivatsavai@Sun.COM kmem_free(bip, sizeof (*bip)); 695*10491SRishi.Srivatsavai@Sun.COM } 696*10491SRishi.Srivatsavai@Sun.COM 697*10491SRishi.Srivatsavai@Sun.COM static bridge_inst_t * 698*10491SRishi.Srivatsavai@Sun.COM inst_alloc(const char *bridge) 699*10491SRishi.Srivatsavai@Sun.COM { 700*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 701*10491SRishi.Srivatsavai@Sun.COM 702*10491SRishi.Srivatsavai@Sun.COM bip = kmem_zalloc(sizeof (*bip), KM_SLEEP); 703*10491SRishi.Srivatsavai@Sun.COM bip->bi_refs = 1; 704*10491SRishi.Srivatsavai@Sun.COM (void) strcpy(bip->bi_name, bridge); 705*10491SRishi.Srivatsavai@Sun.COM rw_init(&bip->bi_rwlock, NULL, RW_DRIVER, NULL); 706*10491SRishi.Srivatsavai@Sun.COM list_create(&bip->bi_links, sizeof (bridge_link_t), 707*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_link_t, bl_node)); 708*10491SRishi.Srivatsavai@Sun.COM cv_init(&bip->bi_linkwait, NULL, CV_DRIVER, NULL); 709*10491SRishi.Srivatsavai@Sun.COM avl_create(&bip->bi_fwd, fwd_compare, sizeof (bridge_fwd_t), 710*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 711*10491SRishi.Srivatsavai@Sun.COM return (bip); 712*10491SRishi.Srivatsavai@Sun.COM } 713*10491SRishi.Srivatsavai@Sun.COM 714*10491SRishi.Srivatsavai@Sun.COM static bridge_inst_t * 715*10491SRishi.Srivatsavai@Sun.COM bridge_find_name(const char *bridge) 716*10491SRishi.Srivatsavai@Sun.COM { 717*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 718*10491SRishi.Srivatsavai@Sun.COM 719*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 720*10491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 721*10491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 722*10491SRishi.Srivatsavai@Sun.COM if (!(bip->bi_flags & BIF_SHUTDOWN) && 723*10491SRishi.Srivatsavai@Sun.COM strcmp(bridge, bip->bi_name) == 0) { 724*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 725*10491SRishi.Srivatsavai@Sun.COM break; 726*10491SRishi.Srivatsavai@Sun.COM } 727*10491SRishi.Srivatsavai@Sun.COM } 728*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 729*10491SRishi.Srivatsavai@Sun.COM 730*10491SRishi.Srivatsavai@Sun.COM return (bip); 731*10491SRishi.Srivatsavai@Sun.COM } 732*10491SRishi.Srivatsavai@Sun.COM 733*10491SRishi.Srivatsavai@Sun.COM static int 734*10491SRishi.Srivatsavai@Sun.COM bridge_create(datalink_id_t linkid, const char *bridge, bridge_inst_t **bipc) 735*10491SRishi.Srivatsavai@Sun.COM { 736*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip, *bipnew; 737*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = NULL; 738*10491SRishi.Srivatsavai@Sun.COM int err; 739*10491SRishi.Srivatsavai@Sun.COM 740*10491SRishi.Srivatsavai@Sun.COM *bipc = NULL; 741*10491SRishi.Srivatsavai@Sun.COM bipnew = inst_alloc(bridge); 742*10491SRishi.Srivatsavai@Sun.COM 743*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 744*10491SRishi.Srivatsavai@Sun.COM lookup_retry: 745*10491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 746*10491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 747*10491SRishi.Srivatsavai@Sun.COM if (strcmp(bridge, bip->bi_name) == 0) 748*10491SRishi.Srivatsavai@Sun.COM break; 749*10491SRishi.Srivatsavai@Sun.COM } 750*10491SRishi.Srivatsavai@Sun.COM 751*10491SRishi.Srivatsavai@Sun.COM /* This should not take long; if it does, we've got a design problem */ 752*10491SRishi.Srivatsavai@Sun.COM if (bip != NULL && (bip->bi_flags & BIF_SHUTDOWN)) { 753*10491SRishi.Srivatsavai@Sun.COM cv_wait(&inst_cv, &inst_lock); 754*10491SRishi.Srivatsavai@Sun.COM goto lookup_retry; 755*10491SRishi.Srivatsavai@Sun.COM } 756*10491SRishi.Srivatsavai@Sun.COM 757*10491SRishi.Srivatsavai@Sun.COM if (bip != NULL) { 758*10491SRishi.Srivatsavai@Sun.COM /* We weren't expecting to find anything */ 759*10491SRishi.Srivatsavai@Sun.COM bip = NULL; 760*10491SRishi.Srivatsavai@Sun.COM err = EEXIST; 761*10491SRishi.Srivatsavai@Sun.COM } else { 762*10491SRishi.Srivatsavai@Sun.COM bip = bipnew; 763*10491SRishi.Srivatsavai@Sun.COM bipnew = NULL; 764*10491SRishi.Srivatsavai@Sun.COM list_insert_tail(&inst_list, bip); 765*10491SRishi.Srivatsavai@Sun.COM } 766*10491SRishi.Srivatsavai@Sun.COM 767*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 768*10491SRishi.Srivatsavai@Sun.COM if (bip == NULL) 769*10491SRishi.Srivatsavai@Sun.COM goto fail; 770*10491SRishi.Srivatsavai@Sun.COM 771*10491SRishi.Srivatsavai@Sun.COM bip->bi_ksp = kstat_setup((kstat_named_t *)&bip->bi_kstats, 772*10491SRishi.Srivatsavai@Sun.COM inst_kstats_list, Dim(inst_kstats_list), bip->bi_name); 773*10491SRishi.Srivatsavai@Sun.COM 774*10491SRishi.Srivatsavai@Sun.COM err = bmac_alloc(bip, &bmp); 775*10491SRishi.Srivatsavai@Sun.COM if ((bip->bi_mac = bmp) == NULL) 776*10491SRishi.Srivatsavai@Sun.COM goto fail_create; 777*10491SRishi.Srivatsavai@Sun.COM 778*10491SRishi.Srivatsavai@Sun.COM /* 779*10491SRishi.Srivatsavai@Sun.COM * bm_inst is set, so the timer cannot yank the DLS rug from under us. 780*10491SRishi.Srivatsavai@Sun.COM * No extra locking is needed here. 781*10491SRishi.Srivatsavai@Sun.COM */ 782*10491SRishi.Srivatsavai@Sun.COM if (!(bmp->bm_flags & BMF_DLS)) { 783*10491SRishi.Srivatsavai@Sun.COM if ((err = dls_devnet_create(bmp->bm_mh, linkid)) != 0) 784*10491SRishi.Srivatsavai@Sun.COM goto fail_create; 785*10491SRishi.Srivatsavai@Sun.COM bmp->bm_flags |= BMF_DLS; 786*10491SRishi.Srivatsavai@Sun.COM } 787*10491SRishi.Srivatsavai@Sun.COM 788*10491SRishi.Srivatsavai@Sun.COM bip->bi_dev = makedevice(bridge_major, mac_minor(bmp->bm_mh)); 789*10491SRishi.Srivatsavai@Sun.COM *bipc = bip; 790*10491SRishi.Srivatsavai@Sun.COM return (0); 791*10491SRishi.Srivatsavai@Sun.COM 792*10491SRishi.Srivatsavai@Sun.COM fail_create: 793*10491SRishi.Srivatsavai@Sun.COM if (bmp != NULL) 794*10491SRishi.Srivatsavai@Sun.COM bmac_disconnect(bip->bi_mac); 795*10491SRishi.Srivatsavai@Sun.COM bipnew = bip; 796*10491SRishi.Srivatsavai@Sun.COM fail: 797*10491SRishi.Srivatsavai@Sun.COM ASSERT(bipnew->bi_trilldata == NULL); 798*10491SRishi.Srivatsavai@Sun.COM bipnew->bi_flags |= BIF_SHUTDOWN; 799*10491SRishi.Srivatsavai@Sun.COM inst_free(bipnew); 800*10491SRishi.Srivatsavai@Sun.COM return (err); 801*10491SRishi.Srivatsavai@Sun.COM } 802*10491SRishi.Srivatsavai@Sun.COM 803*10491SRishi.Srivatsavai@Sun.COM static void 804*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bridge_inst_t *bip) 805*10491SRishi.Srivatsavai@Sun.COM { 806*10491SRishi.Srivatsavai@Sun.COM if (atomic_dec_uint_nv(&bip->bi_refs) == 0) { 807*10491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_flags & BIF_SHUTDOWN); 808*10491SRishi.Srivatsavai@Sun.COM /* free up mac for reuse before leaving global list */ 809*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_mac != NULL) 810*10491SRishi.Srivatsavai@Sun.COM bmac_disconnect(bip->bi_mac); 811*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 812*10491SRishi.Srivatsavai@Sun.COM list_remove(&inst_list, bip); 813*10491SRishi.Srivatsavai@Sun.COM cv_broadcast(&inst_cv); 814*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 815*10491SRishi.Srivatsavai@Sun.COM inst_free(bip); 816*10491SRishi.Srivatsavai@Sun.COM } 817*10491SRishi.Srivatsavai@Sun.COM } 818*10491SRishi.Srivatsavai@Sun.COM 819*10491SRishi.Srivatsavai@Sun.COM /* 820*10491SRishi.Srivatsavai@Sun.COM * Stream instances are used only for allocating bridges and serving as a 821*10491SRishi.Srivatsavai@Sun.COM * control node. They serve no data-handling function. 822*10491SRishi.Srivatsavai@Sun.COM */ 823*10491SRishi.Srivatsavai@Sun.COM static bridge_stream_t * 824*10491SRishi.Srivatsavai@Sun.COM stream_alloc(void) 825*10491SRishi.Srivatsavai@Sun.COM { 826*10491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 827*10491SRishi.Srivatsavai@Sun.COM minor_t mn; 828*10491SRishi.Srivatsavai@Sun.COM 829*10491SRishi.Srivatsavai@Sun.COM if ((mn = mac_minor_hold(B_FALSE)) == 0) 830*10491SRishi.Srivatsavai@Sun.COM return (NULL); 831*10491SRishi.Srivatsavai@Sun.COM bsp = kmem_zalloc(sizeof (*bsp), KM_SLEEP); 832*10491SRishi.Srivatsavai@Sun.COM bsp->bs_minor = mn; 833*10491SRishi.Srivatsavai@Sun.COM return (bsp); 834*10491SRishi.Srivatsavai@Sun.COM } 835*10491SRishi.Srivatsavai@Sun.COM 836*10491SRishi.Srivatsavai@Sun.COM static void 837*10491SRishi.Srivatsavai@Sun.COM stream_free(bridge_stream_t *bsp) 838*10491SRishi.Srivatsavai@Sun.COM { 839*10491SRishi.Srivatsavai@Sun.COM mac_minor_rele(bsp->bs_minor); 840*10491SRishi.Srivatsavai@Sun.COM kmem_free(bsp, sizeof (*bsp)); 841*10491SRishi.Srivatsavai@Sun.COM } 842*10491SRishi.Srivatsavai@Sun.COM 843*10491SRishi.Srivatsavai@Sun.COM /* Reference hold/release functions for STREAMS-related taskq */ 844*10491SRishi.Srivatsavai@Sun.COM static void 845*10491SRishi.Srivatsavai@Sun.COM stream_ref(bridge_stream_t *bsp) 846*10491SRishi.Srivatsavai@Sun.COM { 847*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&stream_ref_lock); 848*10491SRishi.Srivatsavai@Sun.COM bsp->bs_taskq_cnt++; 849*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&stream_ref_lock); 850*10491SRishi.Srivatsavai@Sun.COM } 851*10491SRishi.Srivatsavai@Sun.COM 852*10491SRishi.Srivatsavai@Sun.COM static void 853*10491SRishi.Srivatsavai@Sun.COM stream_unref(bridge_stream_t *bsp) 854*10491SRishi.Srivatsavai@Sun.COM { 855*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&stream_ref_lock); 856*10491SRishi.Srivatsavai@Sun.COM if (--bsp->bs_taskq_cnt == 0) 857*10491SRishi.Srivatsavai@Sun.COM cv_broadcast(&stream_ref_cv); 858*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&stream_ref_lock); 859*10491SRishi.Srivatsavai@Sun.COM } 860*10491SRishi.Srivatsavai@Sun.COM 861*10491SRishi.Srivatsavai@Sun.COM static void 862*10491SRishi.Srivatsavai@Sun.COM link_free(bridge_link_t *blp) 863*10491SRishi.Srivatsavai@Sun.COM { 864*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 865*10491SRishi.Srivatsavai@Sun.COM 866*10491SRishi.Srivatsavai@Sun.COM ASSERT(!(blp->bl_flags & BLF_FREED)); 867*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_FREED; 868*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_ksp != NULL) 869*10491SRishi.Srivatsavai@Sun.COM kstat_delete(blp->bl_ksp); 870*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_lfailmp != NULL) 871*10491SRishi.Srivatsavai@Sun.COM freeb(blp->bl_lfailmp); 872*10491SRishi.Srivatsavai@Sun.COM cv_destroy(&blp->bl_trillwait); 873*10491SRishi.Srivatsavai@Sun.COM mutex_destroy(&blp->bl_trilllock); 874*10491SRishi.Srivatsavai@Sun.COM kmem_free(blp, sizeof (*blp)); 875*10491SRishi.Srivatsavai@Sun.COM /* Don't unreference the bridge until the MAC is closed */ 876*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 877*10491SRishi.Srivatsavai@Sun.COM } 878*10491SRishi.Srivatsavai@Sun.COM 879*10491SRishi.Srivatsavai@Sun.COM static void 880*10491SRishi.Srivatsavai@Sun.COM link_unref(bridge_link_t *blp) 881*10491SRishi.Srivatsavai@Sun.COM { 882*10491SRishi.Srivatsavai@Sun.COM if (atomic_dec_uint_nv(&blp->bl_refs) == 0) { 883*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 884*10491SRishi.Srivatsavai@Sun.COM 885*10491SRishi.Srivatsavai@Sun.COM ASSERT(blp->bl_flags & BLF_DELETED); 886*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 887*10491SRishi.Srivatsavai@Sun.COM list_remove(&bip->bi_links, blp); 888*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 889*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_trilldata != NULL && list_is_empty(&bip->bi_links)) 890*10491SRishi.Srivatsavai@Sun.COM cv_broadcast(&bip->bi_linkwait); 891*10491SRishi.Srivatsavai@Sun.COM link_free(blp); 892*10491SRishi.Srivatsavai@Sun.COM } 893*10491SRishi.Srivatsavai@Sun.COM } 894*10491SRishi.Srivatsavai@Sun.COM 895*10491SRishi.Srivatsavai@Sun.COM static bridge_fwd_t * 896*10491SRishi.Srivatsavai@Sun.COM fwd_alloc(const uint8_t *addr, uint_t nlinks, uint16_t nick) 897*10491SRishi.Srivatsavai@Sun.COM { 898*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp; 899*10491SRishi.Srivatsavai@Sun.COM 900*10491SRishi.Srivatsavai@Sun.COM bfp = kmem_zalloc(sizeof (*bfp) + (nlinks * sizeof (bridge_link_t *)), 901*10491SRishi.Srivatsavai@Sun.COM KM_NOSLEEP); 902*10491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) { 903*10491SRishi.Srivatsavai@Sun.COM bcopy(addr, bfp->bf_dest, ETHERADDRL); 904*10491SRishi.Srivatsavai@Sun.COM bfp->bf_lastheard = lbolt; 905*10491SRishi.Srivatsavai@Sun.COM bfp->bf_maxlinks = nlinks; 906*10491SRishi.Srivatsavai@Sun.COM bfp->bf_links = (bridge_link_t **)(bfp + 1); 907*10491SRishi.Srivatsavai@Sun.COM bfp->bf_trill_nick = nick; 908*10491SRishi.Srivatsavai@Sun.COM } 909*10491SRishi.Srivatsavai@Sun.COM return (bfp); 910*10491SRishi.Srivatsavai@Sun.COM } 911*10491SRishi.Srivatsavai@Sun.COM 912*10491SRishi.Srivatsavai@Sun.COM static bridge_fwd_t * 913*10491SRishi.Srivatsavai@Sun.COM fwd_find(bridge_inst_t *bip, const uint8_t *addr, uint16_t vlanid) 914*10491SRishi.Srivatsavai@Sun.COM { 915*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *vbfp; 916*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t match; 917*10491SRishi.Srivatsavai@Sun.COM 918*10491SRishi.Srivatsavai@Sun.COM bcopy(addr, match.bf_dest, ETHERADDRL); 919*10491SRishi.Srivatsavai@Sun.COM match.bf_flags = 0; 920*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 921*10491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) { 922*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_vlanid != vlanid && bfp->bf_vcnt > 0) { 923*10491SRishi.Srivatsavai@Sun.COM match.bf_vlanid = vlanid; 924*10491SRishi.Srivatsavai@Sun.COM match.bf_flags = BFF_VLANLOCAL; 925*10491SRishi.Srivatsavai@Sun.COM vbfp = avl_find(&bip->bi_fwd, &match, NULL); 926*10491SRishi.Srivatsavai@Sun.COM if (vbfp != NULL) 927*10491SRishi.Srivatsavai@Sun.COM bfp = vbfp; 928*10491SRishi.Srivatsavai@Sun.COM } 929*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfp->bf_refs); 930*10491SRishi.Srivatsavai@Sun.COM } 931*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 932*10491SRishi.Srivatsavai@Sun.COM return (bfp); 933*10491SRishi.Srivatsavai@Sun.COM } 934*10491SRishi.Srivatsavai@Sun.COM 935*10491SRishi.Srivatsavai@Sun.COM static void 936*10491SRishi.Srivatsavai@Sun.COM fwd_free(bridge_fwd_t *bfp) 937*10491SRishi.Srivatsavai@Sun.COM { 938*10491SRishi.Srivatsavai@Sun.COM uint_t i; 939*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = bfp->bf_links[0]->bl_inst; 940*10491SRishi.Srivatsavai@Sun.COM 941*10491SRishi.Srivatsavai@Sun.COM KIDECR(bki_count); 942*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) 943*10491SRishi.Srivatsavai@Sun.COM link_unref(bfp->bf_links[i]); 944*10491SRishi.Srivatsavai@Sun.COM kmem_free(bfp, 945*10491SRishi.Srivatsavai@Sun.COM sizeof (*bfp) + bfp->bf_maxlinks * sizeof (bridge_link_t *)); 946*10491SRishi.Srivatsavai@Sun.COM } 947*10491SRishi.Srivatsavai@Sun.COM 948*10491SRishi.Srivatsavai@Sun.COM static void 949*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bridge_fwd_t *bfp) 950*10491SRishi.Srivatsavai@Sun.COM { 951*10491SRishi.Srivatsavai@Sun.COM if (atomic_dec_uint_nv(&bfp->bf_refs) == 0) { 952*10491SRishi.Srivatsavai@Sun.COM ASSERT(!(bfp->bf_flags & BFF_INTREE)); 953*10491SRishi.Srivatsavai@Sun.COM fwd_free(bfp); 954*10491SRishi.Srivatsavai@Sun.COM } 955*10491SRishi.Srivatsavai@Sun.COM } 956*10491SRishi.Srivatsavai@Sun.COM 957*10491SRishi.Srivatsavai@Sun.COM static void 958*10491SRishi.Srivatsavai@Sun.COM fwd_delete(bridge_fwd_t *bfp) 959*10491SRishi.Srivatsavai@Sun.COM { 960*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 961*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfpzero; 962*10491SRishi.Srivatsavai@Sun.COM 963*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_INTREE) { 964*10491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_nlinks > 0); 965*10491SRishi.Srivatsavai@Sun.COM bip = bfp->bf_links[0]->bl_inst; 966*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 967*10491SRishi.Srivatsavai@Sun.COM /* Another thread could beat us to this */ 968*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_INTREE) { 969*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 970*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 971*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_VLANLOCAL) { 972*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_VLANLOCAL; 973*10491SRishi.Srivatsavai@Sun.COM bfpzero = avl_find(&bip->bi_fwd, bfp, NULL); 974*10491SRishi.Srivatsavai@Sun.COM if (bfpzero != NULL && bfpzero->bf_vcnt > 0) 975*10491SRishi.Srivatsavai@Sun.COM bfpzero->bf_vcnt--; 976*10491SRishi.Srivatsavai@Sun.COM } 977*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 978*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* no longer in avl tree */ 979*10491SRishi.Srivatsavai@Sun.COM } else { 980*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 981*10491SRishi.Srivatsavai@Sun.COM } 982*10491SRishi.Srivatsavai@Sun.COM } 983*10491SRishi.Srivatsavai@Sun.COM } 984*10491SRishi.Srivatsavai@Sun.COM 985*10491SRishi.Srivatsavai@Sun.COM static boolean_t 986*10491SRishi.Srivatsavai@Sun.COM fwd_insert(bridge_inst_t *bip, bridge_fwd_t *bfp) 987*10491SRishi.Srivatsavai@Sun.COM { 988*10491SRishi.Srivatsavai@Sun.COM avl_index_t idx; 989*10491SRishi.Srivatsavai@Sun.COM boolean_t retv; 990*10491SRishi.Srivatsavai@Sun.COM 991*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 992*10491SRishi.Srivatsavai@Sun.COM if (!(bip->bi_flags & BIF_SHUTDOWN) && 993*10491SRishi.Srivatsavai@Sun.COM avl_numnodes(&bip->bi_fwd) < bip->bi_tablemax && 994*10491SRishi.Srivatsavai@Sun.COM avl_find(&bip->bi_fwd, bfp, &idx) == NULL) { 995*10491SRishi.Srivatsavai@Sun.COM avl_insert(&bip->bi_fwd, bfp, idx); 996*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags |= BFF_INTREE; 997*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfp->bf_refs); /* avl entry */ 998*10491SRishi.Srivatsavai@Sun.COM retv = B_TRUE; 999*10491SRishi.Srivatsavai@Sun.COM } else { 1000*10491SRishi.Srivatsavai@Sun.COM retv = B_FALSE; 1001*10491SRishi.Srivatsavai@Sun.COM } 1002*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1003*10491SRishi.Srivatsavai@Sun.COM return (retv); 1004*10491SRishi.Srivatsavai@Sun.COM } 1005*10491SRishi.Srivatsavai@Sun.COM 1006*10491SRishi.Srivatsavai@Sun.COM static void 1007*10491SRishi.Srivatsavai@Sun.COM fwd_update_local(bridge_link_t *blp, const uint8_t *oldaddr, 1008*10491SRishi.Srivatsavai@Sun.COM const uint8_t *newaddr) 1009*10491SRishi.Srivatsavai@Sun.COM { 1010*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 1011*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnew; 1012*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t match; 1013*10491SRishi.Srivatsavai@Sun.COM avl_index_t idx; 1014*10491SRishi.Srivatsavai@Sun.COM boolean_t drop_ref = B_FALSE; 1015*10491SRishi.Srivatsavai@Sun.COM 1016*10491SRishi.Srivatsavai@Sun.COM if (bcmp(oldaddr, newaddr, ETHERADDRL) == 0) 1017*10491SRishi.Srivatsavai@Sun.COM return; 1018*10491SRishi.Srivatsavai@Sun.COM 1019*10491SRishi.Srivatsavai@Sun.COM if (bcmp(oldaddr, zero_addr, ETHERADDRL) == 0) 1020*10491SRishi.Srivatsavai@Sun.COM goto no_old_addr; 1021*10491SRishi.Srivatsavai@Sun.COM 1022*10491SRishi.Srivatsavai@Sun.COM /* 1023*10491SRishi.Srivatsavai@Sun.COM * Find the previous entry, and remove our link from it. 1024*10491SRishi.Srivatsavai@Sun.COM */ 1025*10491SRishi.Srivatsavai@Sun.COM bcopy(oldaddr, match.bf_dest, ETHERADDRL); 1026*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 1027*10491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) { 1028*10491SRishi.Srivatsavai@Sun.COM int i; 1029*10491SRishi.Srivatsavai@Sun.COM 1030*10491SRishi.Srivatsavai@Sun.COM /* 1031*10491SRishi.Srivatsavai@Sun.COM * See if we're in the list, and remove if so. 1032*10491SRishi.Srivatsavai@Sun.COM */ 1033*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 1034*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) { 1035*10491SRishi.Srivatsavai@Sun.COM /* 1036*10491SRishi.Srivatsavai@Sun.COM * We assume writes are atomic, so no special 1037*10491SRishi.Srivatsavai@Sun.COM * MT handling is needed. The list length is 1038*10491SRishi.Srivatsavai@Sun.COM * decremented first, and then we remove 1039*10491SRishi.Srivatsavai@Sun.COM * entries. 1040*10491SRishi.Srivatsavai@Sun.COM */ 1041*10491SRishi.Srivatsavai@Sun.COM bfp->bf_nlinks--; 1042*10491SRishi.Srivatsavai@Sun.COM for (; i < bfp->bf_nlinks; i++) 1043*10491SRishi.Srivatsavai@Sun.COM bfp->bf_links[i] = bfp->bf_links[i + 1]; 1044*10491SRishi.Srivatsavai@Sun.COM drop_ref = B_TRUE; 1045*10491SRishi.Srivatsavai@Sun.COM break; 1046*10491SRishi.Srivatsavai@Sun.COM } 1047*10491SRishi.Srivatsavai@Sun.COM } 1048*10491SRishi.Srivatsavai@Sun.COM /* If no more links, then remove and free up */ 1049*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_nlinks == 0) { 1050*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 1051*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 1052*10491SRishi.Srivatsavai@Sun.COM } else { 1053*10491SRishi.Srivatsavai@Sun.COM bfp = NULL; 1054*10491SRishi.Srivatsavai@Sun.COM } 1055*10491SRishi.Srivatsavai@Sun.COM } 1056*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1057*10491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) 1058*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* no longer in avl tree */ 1059*10491SRishi.Srivatsavai@Sun.COM 1060*10491SRishi.Srivatsavai@Sun.COM /* 1061*10491SRishi.Srivatsavai@Sun.COM * Now get the new link address and add this link to the list. The 1062*10491SRishi.Srivatsavai@Sun.COM * list should be of length 1 unless the user has configured multiple 1063*10491SRishi.Srivatsavai@Sun.COM * NICs with the same address. (That's an incorrect configuration, but 1064*10491SRishi.Srivatsavai@Sun.COM * we support it anyway.) 1065*10491SRishi.Srivatsavai@Sun.COM */ 1066*10491SRishi.Srivatsavai@Sun.COM no_old_addr: 1067*10491SRishi.Srivatsavai@Sun.COM bfp = NULL; 1068*10491SRishi.Srivatsavai@Sun.COM if ((bip->bi_flags & BIF_SHUTDOWN) || 1069*10491SRishi.Srivatsavai@Sun.COM bcmp(newaddr, zero_addr, ETHERADDRL) == 0) 1070*10491SRishi.Srivatsavai@Sun.COM goto no_new_addr; 1071*10491SRishi.Srivatsavai@Sun.COM 1072*10491SRishi.Srivatsavai@Sun.COM bcopy(newaddr, match.bf_dest, ETHERADDRL); 1073*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 1074*10491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, &idx)) == NULL) { 1075*10491SRishi.Srivatsavai@Sun.COM bfnew = fwd_alloc(newaddr, 1, RBRIDGE_NICKNAME_NONE); 1076*10491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL) 1077*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_count); 1078*10491SRishi.Srivatsavai@Sun.COM } else if (bfp->bf_nlinks < bfp->bf_maxlinks) { 1079*10491SRishi.Srivatsavai@Sun.COM /* special case: link fits in existing entry */ 1080*10491SRishi.Srivatsavai@Sun.COM bfnew = bfp; 1081*10491SRishi.Srivatsavai@Sun.COM } else { 1082*10491SRishi.Srivatsavai@Sun.COM bfnew = fwd_alloc(newaddr, bfp->bf_nlinks + 1, 1083*10491SRishi.Srivatsavai@Sun.COM RBRIDGE_NICKNAME_NONE); 1084*10491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL) { 1085*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_count); 1086*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 1087*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 1088*10491SRishi.Srivatsavai@Sun.COM bfnew->bf_nlinks = bfp->bf_nlinks; 1089*10491SRishi.Srivatsavai@Sun.COM bcopy(bfp->bf_links, bfnew->bf_links, 1090*10491SRishi.Srivatsavai@Sun.COM bfp->bf_nlinks * sizeof (bfp)); 1091*10491SRishi.Srivatsavai@Sun.COM /* reset the idx value due to removal above */ 1092*10491SRishi.Srivatsavai@Sun.COM (void) avl_find(&bip->bi_fwd, &match, &idx); 1093*10491SRishi.Srivatsavai@Sun.COM } 1094*10491SRishi.Srivatsavai@Sun.COM } 1095*10491SRishi.Srivatsavai@Sun.COM 1096*10491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL) { 1097*10491SRishi.Srivatsavai@Sun.COM bfnew->bf_links[bfnew->bf_nlinks++] = blp; 1098*10491SRishi.Srivatsavai@Sun.COM if (drop_ref) 1099*10491SRishi.Srivatsavai@Sun.COM drop_ref = B_FALSE; 1100*10491SRishi.Srivatsavai@Sun.COM else 1101*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); /* bf_links entry */ 1102*10491SRishi.Srivatsavai@Sun.COM 1103*10491SRishi.Srivatsavai@Sun.COM if (bfnew != bfp) { 1104*10491SRishi.Srivatsavai@Sun.COM /* local addresses are not subject to table limits */ 1105*10491SRishi.Srivatsavai@Sun.COM avl_insert(&bip->bi_fwd, bfnew, idx); 1106*10491SRishi.Srivatsavai@Sun.COM bfnew->bf_flags |= (BFF_INTREE | BFF_LOCALADDR); 1107*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfnew->bf_refs); /* avl entry */ 1108*10491SRishi.Srivatsavai@Sun.COM } 1109*10491SRishi.Srivatsavai@Sun.COM } 1110*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1111*10491SRishi.Srivatsavai@Sun.COM 1112*10491SRishi.Srivatsavai@Sun.COM no_new_addr: 1113*10491SRishi.Srivatsavai@Sun.COM /* 1114*10491SRishi.Srivatsavai@Sun.COM * If we found an existing entry and we replaced it with a new one, 1115*10491SRishi.Srivatsavai@Sun.COM * then drop the table reference from the old one. We removed it from 1116*10491SRishi.Srivatsavai@Sun.COM * the AVL tree above. 1117*10491SRishi.Srivatsavai@Sun.COM */ 1118*10491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL && bfp != NULL && bfnew != bfp) 1119*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1120*10491SRishi.Srivatsavai@Sun.COM 1121*10491SRishi.Srivatsavai@Sun.COM /* Account for removed entry. */ 1122*10491SRishi.Srivatsavai@Sun.COM if (drop_ref) 1123*10491SRishi.Srivatsavai@Sun.COM link_unref(blp); 1124*10491SRishi.Srivatsavai@Sun.COM } 1125*10491SRishi.Srivatsavai@Sun.COM 1126*10491SRishi.Srivatsavai@Sun.COM static void 1127*10491SRishi.Srivatsavai@Sun.COM bridge_new_unicst(bridge_link_t *blp) 1128*10491SRishi.Srivatsavai@Sun.COM { 1129*10491SRishi.Srivatsavai@Sun.COM uint8_t new_mac[ETHERADDRL]; 1130*10491SRishi.Srivatsavai@Sun.COM 1131*10491SRishi.Srivatsavai@Sun.COM mac_unicast_primary_get(blp->bl_mh, new_mac); 1132*10491SRishi.Srivatsavai@Sun.COM fwd_update_local(blp, blp->bl_local_mac, new_mac); 1133*10491SRishi.Srivatsavai@Sun.COM bcopy(new_mac, blp->bl_local_mac, ETHERADDRL); 1134*10491SRishi.Srivatsavai@Sun.COM } 1135*10491SRishi.Srivatsavai@Sun.COM 1136*10491SRishi.Srivatsavai@Sun.COM /* 1137*10491SRishi.Srivatsavai@Sun.COM * We must shut down a link prior to freeing it, and doing that requires 1138*10491SRishi.Srivatsavai@Sun.COM * blocking to wait for running MAC threads while holding a reference. This is 1139*10491SRishi.Srivatsavai@Sun.COM * run from a taskq to accomplish proper link shutdown followed by reference 1140*10491SRishi.Srivatsavai@Sun.COM * drop. 1141*10491SRishi.Srivatsavai@Sun.COM */ 1142*10491SRishi.Srivatsavai@Sun.COM static void 1143*10491SRishi.Srivatsavai@Sun.COM link_shutdown(void *arg) 1144*10491SRishi.Srivatsavai@Sun.COM { 1145*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = arg; 1146*10491SRishi.Srivatsavai@Sun.COM mac_handle_t mh = blp->bl_mh; 1147*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 1148*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 1149*10491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 1150*10491SRishi.Srivatsavai@Sun.COM int i; 1151*10491SRishi.Srivatsavai@Sun.COM 1152*10491SRishi.Srivatsavai@Sun.COM /* 1153*10491SRishi.Srivatsavai@Sun.COM * This link is being destroyed. Notify TRILL now that it's no longer 1154*10491SRishi.Srivatsavai@Sun.COM * possible to send packets. Data packets may still arrive until TRILL 1155*10491SRishi.Srivatsavai@Sun.COM * calls bridge_trill_lnunref. 1156*10491SRishi.Srivatsavai@Sun.COM */ 1157*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_trilldata != NULL) 1158*10491SRishi.Srivatsavai@Sun.COM trill_lndstr_fn(blp->bl_trilldata, blp); 1159*10491SRishi.Srivatsavai@Sun.COM 1160*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_PROM_ADDED) 1161*10491SRishi.Srivatsavai@Sun.COM (void) mac_promisc_remove(blp->bl_mphp); 1162*10491SRishi.Srivatsavai@Sun.COM 1163*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_SET_BRIDGE) 1164*10491SRishi.Srivatsavai@Sun.COM mac_bridge_clear(mh, (mac_handle_t)blp); 1165*10491SRishi.Srivatsavai@Sun.COM 1166*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_MARGIN_ADDED) { 1167*10491SRishi.Srivatsavai@Sun.COM mac_notify_remove(blp->bl_mnh, B_TRUE); 1168*10491SRishi.Srivatsavai@Sun.COM (void) mac_margin_remove(mh, blp->bl_margin); 1169*10491SRishi.Srivatsavai@Sun.COM } 1170*10491SRishi.Srivatsavai@Sun.COM 1171*10491SRishi.Srivatsavai@Sun.COM /* Tell the clients the real link state when we leave */ 1172*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, 1173*10491SRishi.Srivatsavai@Sun.COM mac_stat_get(blp->bl_mh, MAC_STAT_LOWLINK_STATE)); 1174*10491SRishi.Srivatsavai@Sun.COM 1175*10491SRishi.Srivatsavai@Sun.COM /* Destroy all of the forwarding entries related to this link */ 1176*10491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 1177*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 1178*10491SRishi.Srivatsavai@Sun.COM bip = blp->bl_inst; 1179*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 1180*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 1181*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 1182*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 1183*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 1184*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) 1185*10491SRishi.Srivatsavai@Sun.COM break; 1186*10491SRishi.Srivatsavai@Sun.COM } 1187*10491SRishi.Srivatsavai@Sun.COM if (i >= bfp->bf_nlinks) 1188*10491SRishi.Srivatsavai@Sun.COM continue; 1189*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_nlinks > 1) { 1190*10491SRishi.Srivatsavai@Sun.COM /* note that this can't be the last reference */ 1191*10491SRishi.Srivatsavai@Sun.COM link_unref(blp); 1192*10491SRishi.Srivatsavai@Sun.COM bfp->bf_nlinks--; 1193*10491SRishi.Srivatsavai@Sun.COM for (; i < bfp->bf_nlinks; i++) 1194*10491SRishi.Srivatsavai@Sun.COM bfp->bf_links[i] = bfp->bf_links[i + 1]; 1195*10491SRishi.Srivatsavai@Sun.COM } else { 1196*10491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 1197*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 1198*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 1199*10491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 1200*10491SRishi.Srivatsavai@Sun.COM } 1201*10491SRishi.Srivatsavai@Sun.COM } 1202*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1203*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 1204*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 1205*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 1206*10491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 1207*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1208*10491SRishi.Srivatsavai@Sun.COM } 1209*10491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 1210*10491SRishi.Srivatsavai@Sun.COM 1211*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_CLIENT_OPEN) 1212*10491SRishi.Srivatsavai@Sun.COM mac_client_close(blp->bl_mch, 0); 1213*10491SRishi.Srivatsavai@Sun.COM 1214*10491SRishi.Srivatsavai@Sun.COM mac_close(mh); 1215*10491SRishi.Srivatsavai@Sun.COM 1216*10491SRishi.Srivatsavai@Sun.COM /* 1217*10491SRishi.Srivatsavai@Sun.COM * We are now completely removed from the active list, so drop the 1218*10491SRishi.Srivatsavai@Sun.COM * reference (see bridge_add_link). 1219*10491SRishi.Srivatsavai@Sun.COM */ 1220*10491SRishi.Srivatsavai@Sun.COM link_unref(blp); 1221*10491SRishi.Srivatsavai@Sun.COM } 1222*10491SRishi.Srivatsavai@Sun.COM 1223*10491SRishi.Srivatsavai@Sun.COM static void 1224*10491SRishi.Srivatsavai@Sun.COM shutdown_inst(bridge_inst_t *bip) 1225*10491SRishi.Srivatsavai@Sun.COM { 1226*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp, *blnext; 1227*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp; 1228*10491SRishi.Srivatsavai@Sun.COM 1229*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 1230*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_flags & BIF_SHUTDOWN) { 1231*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 1232*10491SRishi.Srivatsavai@Sun.COM return; 1233*10491SRishi.Srivatsavai@Sun.COM } 1234*10491SRishi.Srivatsavai@Sun.COM 1235*10491SRishi.Srivatsavai@Sun.COM /* 1236*10491SRishi.Srivatsavai@Sun.COM * Once on the inst_list, the bridge instance must not leave that list 1237*10491SRishi.Srivatsavai@Sun.COM * without having the shutdown flag set first. When the shutdown flag 1238*10491SRishi.Srivatsavai@Sun.COM * is set, we own the list reference, so we must drop it before 1239*10491SRishi.Srivatsavai@Sun.COM * returning. 1240*10491SRishi.Srivatsavai@Sun.COM */ 1241*10491SRishi.Srivatsavai@Sun.COM bip->bi_flags |= BIF_SHUTDOWN; 1242*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 1243*10491SRishi.Srivatsavai@Sun.COM 1244*10491SRishi.Srivatsavai@Sun.COM bip->bi_control = NULL; 1245*10491SRishi.Srivatsavai@Sun.COM 1246*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 1247*10491SRishi.Srivatsavai@Sun.COM blnext = list_head(&bip->bi_links); 1248*10491SRishi.Srivatsavai@Sun.COM while ((blp = blnext) != NULL) { 1249*10491SRishi.Srivatsavai@Sun.COM blnext = list_next(&bip->bi_links, blp); 1250*10491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED)) { 1251*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_DELETED; 1252*10491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown, 1253*10491SRishi.Srivatsavai@Sun.COM blp, DDI_SLEEP); 1254*10491SRishi.Srivatsavai@Sun.COM } 1255*10491SRishi.Srivatsavai@Sun.COM } 1256*10491SRishi.Srivatsavai@Sun.COM while ((bfp = avl_first(&bip->bi_fwd)) != NULL) { 1257*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfp->bf_refs); 1258*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1259*10491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 1260*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1261*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 1262*10491SRishi.Srivatsavai@Sun.COM } 1263*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1264*10491SRishi.Srivatsavai@Sun.COM 1265*10491SRishi.Srivatsavai@Sun.COM /* 1266*10491SRishi.Srivatsavai@Sun.COM * This bridge is being destroyed. Notify TRILL once all of the 1267*10491SRishi.Srivatsavai@Sun.COM * links are all gone. 1268*10491SRishi.Srivatsavai@Sun.COM */ 1269*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 1270*10491SRishi.Srivatsavai@Sun.COM while (bip->bi_trilldata != NULL && !list_is_empty(&bip->bi_links)) 1271*10491SRishi.Srivatsavai@Sun.COM cv_wait(&bip->bi_linkwait, &inst_lock); 1272*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 1273*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_trilldata != NULL) 1274*10491SRishi.Srivatsavai@Sun.COM trill_brdstr_fn(bip->bi_trilldata, bip); 1275*10491SRishi.Srivatsavai@Sun.COM 1276*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 1277*10491SRishi.Srivatsavai@Sun.COM } 1278*10491SRishi.Srivatsavai@Sun.COM 1279*10491SRishi.Srivatsavai@Sun.COM /* 1280*10491SRishi.Srivatsavai@Sun.COM * This is called once by the TRILL module when it starts up. It just sets the 1281*10491SRishi.Srivatsavai@Sun.COM * global TRILL callback function pointers -- data transmit/receive and bridge 1282*10491SRishi.Srivatsavai@Sun.COM * and link destroy notification. There's only one TRILL module, so only one 1283*10491SRishi.Srivatsavai@Sun.COM * registration is needed. 1284*10491SRishi.Srivatsavai@Sun.COM * 1285*10491SRishi.Srivatsavai@Sun.COM * TRILL should call this function with NULL pointers before unloading. It 1286*10491SRishi.Srivatsavai@Sun.COM * must not do so before dropping all references to bridges and links. We 1287*10491SRishi.Srivatsavai@Sun.COM * assert that this is true on debug builds. 1288*10491SRishi.Srivatsavai@Sun.COM */ 1289*10491SRishi.Srivatsavai@Sun.COM void 1290*10491SRishi.Srivatsavai@Sun.COM bridge_trill_register_cb(trill_recv_pkt_t recv_fn, trill_encap_pkt_t encap_fn, 1291*10491SRishi.Srivatsavai@Sun.COM trill_br_dstr_t brdstr_fn, trill_ln_dstr_t lndstr_fn) 1292*10491SRishi.Srivatsavai@Sun.COM { 1293*10491SRishi.Srivatsavai@Sun.COM #ifdef DEBUG 1294*10491SRishi.Srivatsavai@Sun.COM if (recv_fn == NULL && trill_recv_fn != NULL) { 1295*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 1296*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 1297*10491SRishi.Srivatsavai@Sun.COM 1298*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 1299*10491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 1300*10491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 1301*10491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata == NULL); 1302*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 1303*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 1304*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 1305*10491SRishi.Srivatsavai@Sun.COM ASSERT(blp->bl_trilldata == NULL); 1306*10491SRishi.Srivatsavai@Sun.COM } 1307*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1308*10491SRishi.Srivatsavai@Sun.COM } 1309*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 1310*10491SRishi.Srivatsavai@Sun.COM } 1311*10491SRishi.Srivatsavai@Sun.COM #endif 1312*10491SRishi.Srivatsavai@Sun.COM trill_recv_fn = recv_fn; 1313*10491SRishi.Srivatsavai@Sun.COM trill_encap_fn = encap_fn; 1314*10491SRishi.Srivatsavai@Sun.COM trill_brdstr_fn = brdstr_fn; 1315*10491SRishi.Srivatsavai@Sun.COM trill_lndstr_fn = lndstr_fn; 1316*10491SRishi.Srivatsavai@Sun.COM } 1317*10491SRishi.Srivatsavai@Sun.COM 1318*10491SRishi.Srivatsavai@Sun.COM /* 1319*10491SRishi.Srivatsavai@Sun.COM * This registers the TRILL instance pointer with a bridge. Before this 1320*10491SRishi.Srivatsavai@Sun.COM * pointer is set, the forwarding, TRILL receive, and bridge destructor 1321*10491SRishi.Srivatsavai@Sun.COM * functions won't be called. 1322*10491SRishi.Srivatsavai@Sun.COM * 1323*10491SRishi.Srivatsavai@Sun.COM * TRILL holds a reference on a bridge with this call. It must free the 1324*10491SRishi.Srivatsavai@Sun.COM * reference by calling the unregister function below. 1325*10491SRishi.Srivatsavai@Sun.COM */ 1326*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t * 1327*10491SRishi.Srivatsavai@Sun.COM bridge_trill_brref(const char *bname, void *ptr) 1328*10491SRishi.Srivatsavai@Sun.COM { 1329*10491SRishi.Srivatsavai@Sun.COM char bridge[MAXLINKNAMELEN]; 1330*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 1331*10491SRishi.Srivatsavai@Sun.COM 1332*10491SRishi.Srivatsavai@Sun.COM (void) snprintf(bridge, MAXLINKNAMELEN, "%s0", bname); 1333*10491SRishi.Srivatsavai@Sun.COM bip = bridge_find_name(bridge); 1334*10491SRishi.Srivatsavai@Sun.COM if (bip != NULL) { 1335*10491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata == NULL && ptr != NULL); 1336*10491SRishi.Srivatsavai@Sun.COM bip->bi_trilldata = ptr; 1337*10491SRishi.Srivatsavai@Sun.COM } 1338*10491SRishi.Srivatsavai@Sun.COM return (bip); 1339*10491SRishi.Srivatsavai@Sun.COM } 1340*10491SRishi.Srivatsavai@Sun.COM 1341*10491SRishi.Srivatsavai@Sun.COM void 1342*10491SRishi.Srivatsavai@Sun.COM bridge_trill_brunref(bridge_inst_t *bip) 1343*10491SRishi.Srivatsavai@Sun.COM { 1344*10491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata != NULL); 1345*10491SRishi.Srivatsavai@Sun.COM bip->bi_trilldata = NULL; 1346*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 1347*10491SRishi.Srivatsavai@Sun.COM } 1348*10491SRishi.Srivatsavai@Sun.COM 1349*10491SRishi.Srivatsavai@Sun.COM /* 1350*10491SRishi.Srivatsavai@Sun.COM * TRILL calls this function when referencing a particular link on a bridge. 1351*10491SRishi.Srivatsavai@Sun.COM * 1352*10491SRishi.Srivatsavai@Sun.COM * It holds a reference on the link, so TRILL must clear out the reference when 1353*10491SRishi.Srivatsavai@Sun.COM * it's done with the link (on unbinding). 1354*10491SRishi.Srivatsavai@Sun.COM */ 1355*10491SRishi.Srivatsavai@Sun.COM bridge_link_t * 1356*10491SRishi.Srivatsavai@Sun.COM bridge_trill_lnref(bridge_inst_t *bip, datalink_id_t linkid, void *ptr) 1357*10491SRishi.Srivatsavai@Sun.COM { 1358*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 1359*10491SRishi.Srivatsavai@Sun.COM 1360*10491SRishi.Srivatsavai@Sun.COM ASSERT(ptr != NULL); 1361*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 1362*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 1363*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 1364*10491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED) && 1365*10491SRishi.Srivatsavai@Sun.COM blp->bl_linkid == linkid && blp->bl_trilldata == NULL) { 1366*10491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata = ptr; 1367*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags &= ~BLF_TRILLACTIVE; 1368*10491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_afs, 0, sizeof (blp->bl_afs)); 1369*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); 1370*10491SRishi.Srivatsavai@Sun.COM break; 1371*10491SRishi.Srivatsavai@Sun.COM } 1372*10491SRishi.Srivatsavai@Sun.COM } 1373*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1374*10491SRishi.Srivatsavai@Sun.COM return (blp); 1375*10491SRishi.Srivatsavai@Sun.COM } 1376*10491SRishi.Srivatsavai@Sun.COM 1377*10491SRishi.Srivatsavai@Sun.COM void 1378*10491SRishi.Srivatsavai@Sun.COM bridge_trill_lnunref(bridge_link_t *blp) 1379*10491SRishi.Srivatsavai@Sun.COM { 1380*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 1381*10491SRishi.Srivatsavai@Sun.COM ASSERT(blp->bl_trilldata != NULL); 1382*10491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata = NULL; 1383*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags &= ~BLF_TRILLACTIVE; 1384*10491SRishi.Srivatsavai@Sun.COM while (blp->bl_trillthreads > 0) 1385*10491SRishi.Srivatsavai@Sun.COM cv_wait(&blp->bl_trillwait, &blp->bl_trilllock); 1386*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 1387*10491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs)); 1388*10491SRishi.Srivatsavai@Sun.COM link_unref(blp); 1389*10491SRishi.Srivatsavai@Sun.COM } 1390*10491SRishi.Srivatsavai@Sun.COM 1391*10491SRishi.Srivatsavai@Sun.COM /* 1392*10491SRishi.Srivatsavai@Sun.COM * This periodic timer performs three functions: 1393*10491SRishi.Srivatsavai@Sun.COM * 1. It scans the list of learned forwarding entries, and removes ones that 1394*10491SRishi.Srivatsavai@Sun.COM * haven't been heard from in a while. The time limit is backed down if 1395*10491SRishi.Srivatsavai@Sun.COM * we're above the configured table limit. 1396*10491SRishi.Srivatsavai@Sun.COM * 2. It walks the links and decays away the bl_learns counter. 1397*10491SRishi.Srivatsavai@Sun.COM * 3. It scans the observability node entries looking for ones that can be 1398*10491SRishi.Srivatsavai@Sun.COM * freed up. 1399*10491SRishi.Srivatsavai@Sun.COM */ 1400*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 1401*10491SRishi.Srivatsavai@Sun.COM static void 1402*10491SRishi.Srivatsavai@Sun.COM bridge_timer(void *arg) 1403*10491SRishi.Srivatsavai@Sun.COM { 1404*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 1405*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 1406*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp, *bmnext; 1407*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 1408*10491SRishi.Srivatsavai@Sun.COM int err; 1409*10491SRishi.Srivatsavai@Sun.COM datalink_id_t tmpid; 1410*10491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 1411*10491SRishi.Srivatsavai@Sun.COM clock_t age_limit; 1412*10491SRishi.Srivatsavai@Sun.COM uint32_t ldecay; 1413*10491SRishi.Srivatsavai@Sun.COM 1414*10491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 1415*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 1416*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 1417*10491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 1418*10491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 1419*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_flags & BIF_SHUTDOWN) 1420*10491SRishi.Srivatsavai@Sun.COM continue; 1421*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 1422*10491SRishi.Srivatsavai@Sun.COM /* compute scaled maximum age based on table limit */ 1423*10491SRishi.Srivatsavai@Sun.COM if (avl_numnodes(&bip->bi_fwd) > bip->bi_tablemax) 1424*10491SRishi.Srivatsavai@Sun.COM bip->bi_tshift++; 1425*10491SRishi.Srivatsavai@Sun.COM else 1426*10491SRishi.Srivatsavai@Sun.COM bip->bi_tshift = 0; 1427*10491SRishi.Srivatsavai@Sun.COM if ((age_limit = bridge_fwd_age >> bip->bi_tshift) == 0) { 1428*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_tshift != 0) 1429*10491SRishi.Srivatsavai@Sun.COM bip->bi_tshift--; 1430*10491SRishi.Srivatsavai@Sun.COM age_limit = 1; 1431*10491SRishi.Srivatsavai@Sun.COM } 1432*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 1433*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 1434*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 1435*10491SRishi.Srivatsavai@Sun.COM if (!(bfp->bf_flags & BFF_LOCALADDR) && 1436*10491SRishi.Srivatsavai@Sun.COM (lbolt - bfp->bf_lastheard) > age_limit) { 1437*10491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 1438*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 1439*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 1440*10491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 1441*10491SRishi.Srivatsavai@Sun.COM } 1442*10491SRishi.Srivatsavai@Sun.COM } 1443*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 1444*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 1445*10491SRishi.Srivatsavai@Sun.COM ldecay = mac_get_ldecay(blp->bl_mh); 1446*10491SRishi.Srivatsavai@Sun.COM if (ldecay >= blp->bl_learns) 1447*10491SRishi.Srivatsavai@Sun.COM blp->bl_learns = 0; 1448*10491SRishi.Srivatsavai@Sun.COM else 1449*10491SRishi.Srivatsavai@Sun.COM atomic_add_int(&blp->bl_learns, -(int)ldecay); 1450*10491SRishi.Srivatsavai@Sun.COM } 1451*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 1452*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 1453*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 1454*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 1455*10491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 1456*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_expire); 1457*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* drop tree reference */ 1458*10491SRishi.Srivatsavai@Sun.COM } 1459*10491SRishi.Srivatsavai@Sun.COM } 1460*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 1461*10491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 1462*10491SRishi.Srivatsavai@Sun.COM 1463*10491SRishi.Srivatsavai@Sun.COM /* 1464*10491SRishi.Srivatsavai@Sun.COM * Scan the bridge_mac_t entries and try to free up the ones that are 1465*10491SRishi.Srivatsavai@Sun.COM * no longer active. This must be done by polling, as neither DLS nor 1466*10491SRishi.Srivatsavai@Sun.COM * MAC provides a driver any sort of positive control over clients. 1467*10491SRishi.Srivatsavai@Sun.COM */ 1468*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_WRITER); 1469*10491SRishi.Srivatsavai@Sun.COM bmnext = list_head(&bmac_list); 1470*10491SRishi.Srivatsavai@Sun.COM while ((bmp = bmnext) != NULL) { 1471*10491SRishi.Srivatsavai@Sun.COM bmnext = list_next(&bmac_list, bmp); 1472*10491SRishi.Srivatsavai@Sun.COM 1473*10491SRishi.Srivatsavai@Sun.COM /* ignore active bridges */ 1474*10491SRishi.Srivatsavai@Sun.COM if (bmp->bm_inst != NULL) 1475*10491SRishi.Srivatsavai@Sun.COM continue; 1476*10491SRishi.Srivatsavai@Sun.COM 1477*10491SRishi.Srivatsavai@Sun.COM if (bmp->bm_flags & BMF_DLS) { 1478*10491SRishi.Srivatsavai@Sun.COM err = dls_devnet_destroy(bmp->bm_mh, &tmpid, B_FALSE); 1479*10491SRishi.Srivatsavai@Sun.COM ASSERT(err == 0 || err == EBUSY); 1480*10491SRishi.Srivatsavai@Sun.COM if (err == 0) 1481*10491SRishi.Srivatsavai@Sun.COM bmp->bm_flags &= ~BMF_DLS; 1482*10491SRishi.Srivatsavai@Sun.COM } 1483*10491SRishi.Srivatsavai@Sun.COM 1484*10491SRishi.Srivatsavai@Sun.COM if (!(bmp->bm_flags & BMF_DLS)) { 1485*10491SRishi.Srivatsavai@Sun.COM err = mac_unregister(bmp->bm_mh); 1486*10491SRishi.Srivatsavai@Sun.COM ASSERT(err == 0 || err == EBUSY); 1487*10491SRishi.Srivatsavai@Sun.COM if (err == 0) { 1488*10491SRishi.Srivatsavai@Sun.COM list_remove(&bmac_list, bmp); 1489*10491SRishi.Srivatsavai@Sun.COM kmem_free(bmp, sizeof (*bmp)); 1490*10491SRishi.Srivatsavai@Sun.COM } 1491*10491SRishi.Srivatsavai@Sun.COM } 1492*10491SRishi.Srivatsavai@Sun.COM } 1493*10491SRishi.Srivatsavai@Sun.COM if (list_is_empty(&bmac_list)) { 1494*10491SRishi.Srivatsavai@Sun.COM bridge_timerid = 0; 1495*10491SRishi.Srivatsavai@Sun.COM } else { 1496*10491SRishi.Srivatsavai@Sun.COM bridge_timerid = timeout(bridge_timer, NULL, 1497*10491SRishi.Srivatsavai@Sun.COM bridge_scan_interval); 1498*10491SRishi.Srivatsavai@Sun.COM } 1499*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 1500*10491SRishi.Srivatsavai@Sun.COM } 1501*10491SRishi.Srivatsavai@Sun.COM 1502*10491SRishi.Srivatsavai@Sun.COM static int 1503*10491SRishi.Srivatsavai@Sun.COM bridge_open(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp) 1504*10491SRishi.Srivatsavai@Sun.COM { 1505*10491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 1506*10491SRishi.Srivatsavai@Sun.COM 1507*10491SRishi.Srivatsavai@Sun.COM if (rq->q_ptr != NULL) 1508*10491SRishi.Srivatsavai@Sun.COM return (0); 1509*10491SRishi.Srivatsavai@Sun.COM 1510*10491SRishi.Srivatsavai@Sun.COM if (sflag & MODOPEN) 1511*10491SRishi.Srivatsavai@Sun.COM return (EINVAL); 1512*10491SRishi.Srivatsavai@Sun.COM 1513*10491SRishi.Srivatsavai@Sun.COM /* 1514*10491SRishi.Srivatsavai@Sun.COM * Check the minor node number being opened. This tells us which 1515*10491SRishi.Srivatsavai@Sun.COM * bridge instance the user wants. 1516*10491SRishi.Srivatsavai@Sun.COM */ 1517*10491SRishi.Srivatsavai@Sun.COM if (getminor(*devp) != 0) { 1518*10491SRishi.Srivatsavai@Sun.COM /* 1519*10491SRishi.Srivatsavai@Sun.COM * This is a regular DLPI stream for snoop or the like. 1520*10491SRishi.Srivatsavai@Sun.COM * Redirect it through DLD. 1521*10491SRishi.Srivatsavai@Sun.COM */ 1522*10491SRishi.Srivatsavai@Sun.COM rq->q_qinfo = &bridge_dld_rinit; 1523*10491SRishi.Srivatsavai@Sun.COM OTHERQ(rq)->q_qinfo = &bridge_dld_winit; 1524*10491SRishi.Srivatsavai@Sun.COM return (dld_open(rq, devp, oflag, sflag, credp)); 1525*10491SRishi.Srivatsavai@Sun.COM } else { 1526*10491SRishi.Srivatsavai@Sun.COM /* 1527*10491SRishi.Srivatsavai@Sun.COM * Allocate the bridge control stream structure. 1528*10491SRishi.Srivatsavai@Sun.COM */ 1529*10491SRishi.Srivatsavai@Sun.COM if ((bsp = stream_alloc()) == NULL) 1530*10491SRishi.Srivatsavai@Sun.COM return (ENOSR); 1531*10491SRishi.Srivatsavai@Sun.COM rq->q_ptr = WR(rq)->q_ptr = (caddr_t)bsp; 1532*10491SRishi.Srivatsavai@Sun.COM bsp->bs_wq = WR(rq); 1533*10491SRishi.Srivatsavai@Sun.COM *devp = makedevice(getmajor(*devp), bsp->bs_minor); 1534*10491SRishi.Srivatsavai@Sun.COM qprocson(rq); 1535*10491SRishi.Srivatsavai@Sun.COM return (0); 1536*10491SRishi.Srivatsavai@Sun.COM } 1537*10491SRishi.Srivatsavai@Sun.COM } 1538*10491SRishi.Srivatsavai@Sun.COM 1539*10491SRishi.Srivatsavai@Sun.COM /* 1540*10491SRishi.Srivatsavai@Sun.COM * This is used only for bridge control streams. DLPI goes through dld 1541*10491SRishi.Srivatsavai@Sun.COM * instead. 1542*10491SRishi.Srivatsavai@Sun.COM */ 1543*10491SRishi.Srivatsavai@Sun.COM static int 1544*10491SRishi.Srivatsavai@Sun.COM bridge_close(queue_t *rq) 1545*10491SRishi.Srivatsavai@Sun.COM { 1546*10491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp = rq->q_ptr; 1547*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 1548*10491SRishi.Srivatsavai@Sun.COM 1549*10491SRishi.Srivatsavai@Sun.COM /* 1550*10491SRishi.Srivatsavai@Sun.COM * Wait for any stray taskq (add/delete link) entries related to this 1551*10491SRishi.Srivatsavai@Sun.COM * stream to leave the system. 1552*10491SRishi.Srivatsavai@Sun.COM */ 1553*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&stream_ref_lock); 1554*10491SRishi.Srivatsavai@Sun.COM while (bsp->bs_taskq_cnt != 0) 1555*10491SRishi.Srivatsavai@Sun.COM cv_wait(&stream_ref_cv, &stream_ref_lock); 1556*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&stream_ref_lock); 1557*10491SRishi.Srivatsavai@Sun.COM 1558*10491SRishi.Srivatsavai@Sun.COM qprocsoff(rq); 1559*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) != NULL) 1560*10491SRishi.Srivatsavai@Sun.COM shutdown_inst(bip); 1561*10491SRishi.Srivatsavai@Sun.COM rq->q_ptr = WR(rq)->q_ptr = NULL; 1562*10491SRishi.Srivatsavai@Sun.COM stream_free(bsp); 1563*10491SRishi.Srivatsavai@Sun.COM if (bip != NULL) 1564*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 1565*10491SRishi.Srivatsavai@Sun.COM 1566*10491SRishi.Srivatsavai@Sun.COM return (0); 1567*10491SRishi.Srivatsavai@Sun.COM } 1568*10491SRishi.Srivatsavai@Sun.COM 1569*10491SRishi.Srivatsavai@Sun.COM static void 1570*10491SRishi.Srivatsavai@Sun.COM bridge_learn(bridge_link_t *blp, const uint8_t *saddr, uint16_t ingress_nick, 1571*10491SRishi.Srivatsavai@Sun.COM uint16_t vlanid) 1572*10491SRishi.Srivatsavai@Sun.COM { 1573*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 1574*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfpnew; 1575*10491SRishi.Srivatsavai@Sun.COM int i; 1576*10491SRishi.Srivatsavai@Sun.COM boolean_t replaced = B_FALSE; 1577*10491SRishi.Srivatsavai@Sun.COM 1578*10491SRishi.Srivatsavai@Sun.COM /* Ignore multi-destination address used as source; it's nonsense. */ 1579*10491SRishi.Srivatsavai@Sun.COM if (*saddr & 1) 1580*10491SRishi.Srivatsavai@Sun.COM return; 1581*10491SRishi.Srivatsavai@Sun.COM 1582*10491SRishi.Srivatsavai@Sun.COM /* 1583*10491SRishi.Srivatsavai@Sun.COM * If the source is known, then check whether it belongs on this link. 1584*10491SRishi.Srivatsavai@Sun.COM * If not, and this isn't a fixed local address, then we've detected a 1585*10491SRishi.Srivatsavai@Sun.COM * move. If it's not known, learn it. 1586*10491SRishi.Srivatsavai@Sun.COM */ 1587*10491SRishi.Srivatsavai@Sun.COM if ((bfp = fwd_find(bip, saddr, vlanid)) != NULL) { 1588*10491SRishi.Srivatsavai@Sun.COM /* 1589*10491SRishi.Srivatsavai@Sun.COM * If the packet has a fixed local source address, then there's 1590*10491SRishi.Srivatsavai@Sun.COM * nothing we can learn. We must quit. If this was a received 1591*10491SRishi.Srivatsavai@Sun.COM * packet, then the sender has stolen our address, but there's 1592*10491SRishi.Srivatsavai@Sun.COM * nothing we can do. If it's a transmitted packet, then 1593*10491SRishi.Srivatsavai@Sun.COM * that's the normal case. 1594*10491SRishi.Srivatsavai@Sun.COM */ 1595*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) { 1596*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1597*10491SRishi.Srivatsavai@Sun.COM return; 1598*10491SRishi.Srivatsavai@Sun.COM } 1599*10491SRishi.Srivatsavai@Sun.COM 1600*10491SRishi.Srivatsavai@Sun.COM /* 1601*10491SRishi.Srivatsavai@Sun.COM * Check if the link (and TRILL sender, if any) being used is 1602*10491SRishi.Srivatsavai@Sun.COM * among the ones registered for this address. If so, then 1603*10491SRishi.Srivatsavai@Sun.COM * this is information that we already know. 1604*10491SRishi.Srivatsavai@Sun.COM */ 1605*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick == ingress_nick) { 1606*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 1607*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) { 1608*10491SRishi.Srivatsavai@Sun.COM bfp->bf_lastheard = lbolt; 1609*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1610*10491SRishi.Srivatsavai@Sun.COM return; 1611*10491SRishi.Srivatsavai@Sun.COM } 1612*10491SRishi.Srivatsavai@Sun.COM } 1613*10491SRishi.Srivatsavai@Sun.COM } 1614*10491SRishi.Srivatsavai@Sun.COM } 1615*10491SRishi.Srivatsavai@Sun.COM 1616*10491SRishi.Srivatsavai@Sun.COM /* 1617*10491SRishi.Srivatsavai@Sun.COM * Note that we intentionally "unlearn" things that appear to be under 1618*10491SRishi.Srivatsavai@Sun.COM * attack on this link. The forwarding cache is a negative thing for 1619*10491SRishi.Srivatsavai@Sun.COM * security -- it disables reachability as a performance optimization 1620*10491SRishi.Srivatsavai@Sun.COM * -- so leaving out entries optimizes for success and defends against 1621*10491SRishi.Srivatsavai@Sun.COM * the attack. Thus, the bare increment without a check in the delete 1622*10491SRishi.Srivatsavai@Sun.COM * code above is right. (And it's ok if we skid over the limit a 1623*10491SRishi.Srivatsavai@Sun.COM * little, so there's no syncronization needed on the test.) 1624*10491SRishi.Srivatsavai@Sun.COM */ 1625*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_learns >= mac_get_llimit(blp->bl_mh)) { 1626*10491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) { 1627*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_vcnt == 0) 1628*10491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 1629*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1630*10491SRishi.Srivatsavai@Sun.COM } 1631*10491SRishi.Srivatsavai@Sun.COM return; 1632*10491SRishi.Srivatsavai@Sun.COM } 1633*10491SRishi.Srivatsavai@Sun.COM 1634*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_learns); 1635*10491SRishi.Srivatsavai@Sun.COM 1636*10491SRishi.Srivatsavai@Sun.COM if ((bfpnew = fwd_alloc(saddr, 1, ingress_nick)) == NULL) { 1637*10491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) 1638*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1639*10491SRishi.Srivatsavai@Sun.COM return; 1640*10491SRishi.Srivatsavai@Sun.COM } 1641*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_count); 1642*10491SRishi.Srivatsavai@Sun.COM 1643*10491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) { 1644*10491SRishi.Srivatsavai@Sun.COM /* 1645*10491SRishi.Srivatsavai@Sun.COM * If this is a new destination for the same VLAN, then delete 1646*10491SRishi.Srivatsavai@Sun.COM * so that we can update. If it's a different VLAN, then we're 1647*10491SRishi.Srivatsavai@Sun.COM * not going to delete the original. Split off instead into an 1648*10491SRishi.Srivatsavai@Sun.COM * IVL entry. 1649*10491SRishi.Srivatsavai@Sun.COM */ 1650*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_vlanid == vlanid) { 1651*10491SRishi.Srivatsavai@Sun.COM /* save the count of IVL duplicates */ 1652*10491SRishi.Srivatsavai@Sun.COM bfpnew->bf_vcnt = bfp->bf_vcnt; 1653*10491SRishi.Srivatsavai@Sun.COM 1654*10491SRishi.Srivatsavai@Sun.COM /* entry deletes count as learning events */ 1655*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_learns); 1656*10491SRishi.Srivatsavai@Sun.COM 1657*10491SRishi.Srivatsavai@Sun.COM /* destroy and create anew; node moved */ 1658*10491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 1659*10491SRishi.Srivatsavai@Sun.COM replaced = B_TRUE; 1660*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_moved); 1661*10491SRishi.Srivatsavai@Sun.COM } else { 1662*10491SRishi.Srivatsavai@Sun.COM bfp->bf_vcnt++; 1663*10491SRishi.Srivatsavai@Sun.COM bfpnew->bf_flags |= BFF_VLANLOCAL; 1664*10491SRishi.Srivatsavai@Sun.COM } 1665*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1666*10491SRishi.Srivatsavai@Sun.COM } 1667*10491SRishi.Srivatsavai@Sun.COM bfpnew->bf_links[0] = blp; 1668*10491SRishi.Srivatsavai@Sun.COM bfpnew->bf_nlinks = 1; 1669*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); /* bf_links entry */ 1670*10491SRishi.Srivatsavai@Sun.COM if (!fwd_insert(bip, bfpnew)) 1671*10491SRishi.Srivatsavai@Sun.COM fwd_free(bfpnew); 1672*10491SRishi.Srivatsavai@Sun.COM else if (!replaced) 1673*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_source); 1674*10491SRishi.Srivatsavai@Sun.COM } 1675*10491SRishi.Srivatsavai@Sun.COM 1676*10491SRishi.Srivatsavai@Sun.COM /* 1677*10491SRishi.Srivatsavai@Sun.COM * Process the VLAN headers for output on a given link. There are several 1678*10491SRishi.Srivatsavai@Sun.COM * cases (noting that we don't map VLANs): 1679*10491SRishi.Srivatsavai@Sun.COM * 1. The input packet is good as it is; either 1680*10491SRishi.Srivatsavai@Sun.COM * a. It has no tag, and output has same PVID 1681*10491SRishi.Srivatsavai@Sun.COM * b. It has a non-zero priority-only tag for PVID, and b_band is same 1682*10491SRishi.Srivatsavai@Sun.COM * c. It has a tag with VLAN different from PVID, and b_band is same 1683*10491SRishi.Srivatsavai@Sun.COM * 2. The tag must change: non-zero b_band is different from tag priority 1684*10491SRishi.Srivatsavai@Sun.COM * 3. The packet has a tag and should not (VLAN same as PVID, b_band zero) 1685*10491SRishi.Srivatsavai@Sun.COM * 4. The packet has no tag and needs one: 1686*10491SRishi.Srivatsavai@Sun.COM * a. VLAN ID same as PVID, but b_band is non-zero 1687*10491SRishi.Srivatsavai@Sun.COM * b. VLAN ID different from PVID 1688*10491SRishi.Srivatsavai@Sun.COM * We exclude case 1 first, then modify the packet. Note that output packets 1689*10491SRishi.Srivatsavai@Sun.COM * get a priority set by the mblk, not by the header, because QoS in bridging 1690*10491SRishi.Srivatsavai@Sun.COM * requires priority recalculation at each node. 1691*10491SRishi.Srivatsavai@Sun.COM * 1692*10491SRishi.Srivatsavai@Sun.COM * The passed-in tci is the "impossible" value 0xFFFF when no tag is present. 1693*10491SRishi.Srivatsavai@Sun.COM */ 1694*10491SRishi.Srivatsavai@Sun.COM static mblk_t * 1695*10491SRishi.Srivatsavai@Sun.COM reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid) 1696*10491SRishi.Srivatsavai@Sun.COM { 1697*10491SRishi.Srivatsavai@Sun.COM boolean_t source_has_tag = (tci != 0xFFFF); 1698*10491SRishi.Srivatsavai@Sun.COM mblk_t *mpcopy; 1699*10491SRishi.Srivatsavai@Sun.COM size_t mlen, minlen; 1700*10491SRishi.Srivatsavai@Sun.COM struct ether_vlan_header *evh; 1701*10491SRishi.Srivatsavai@Sun.COM int pri; 1702*10491SRishi.Srivatsavai@Sun.COM 1703*10491SRishi.Srivatsavai@Sun.COM /* This helps centralize error handling in the caller. */ 1704*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) 1705*10491SRishi.Srivatsavai@Sun.COM return (mp); 1706*10491SRishi.Srivatsavai@Sun.COM 1707*10491SRishi.Srivatsavai@Sun.COM /* No forwarded packet can have hardware checksum enabled */ 1708*10491SRishi.Srivatsavai@Sun.COM DB_CKSUMFLAGS(mp) = 0; 1709*10491SRishi.Srivatsavai@Sun.COM 1710*10491SRishi.Srivatsavai@Sun.COM /* Get the no-modification cases out of the way first */ 1711*10491SRishi.Srivatsavai@Sun.COM if (!source_has_tag && vlanid == pvid) /* 1a */ 1712*10491SRishi.Srivatsavai@Sun.COM return (mp); 1713*10491SRishi.Srivatsavai@Sun.COM 1714*10491SRishi.Srivatsavai@Sun.COM pri = VLAN_PRI(tci); 1715*10491SRishi.Srivatsavai@Sun.COM if (source_has_tag && mp->b_band == pri) { 1716*10491SRishi.Srivatsavai@Sun.COM if (vlanid != pvid) /* 1c */ 1717*10491SRishi.Srivatsavai@Sun.COM return (mp); 1718*10491SRishi.Srivatsavai@Sun.COM if (pri != 0 && VLAN_ID(tci) == 0) /* 1b */ 1719*10491SRishi.Srivatsavai@Sun.COM return (mp); 1720*10491SRishi.Srivatsavai@Sun.COM } 1721*10491SRishi.Srivatsavai@Sun.COM 1722*10491SRishi.Srivatsavai@Sun.COM /* 1723*10491SRishi.Srivatsavai@Sun.COM * We now know that we must modify the packet. Prepare for that. Note 1724*10491SRishi.Srivatsavai@Sun.COM * that if a tag is present, the caller has already done a pullup for 1725*10491SRishi.Srivatsavai@Sun.COM * the VLAN header, so we're good to go. 1726*10491SRishi.Srivatsavai@Sun.COM */ 1727*10491SRishi.Srivatsavai@Sun.COM if (MBLKL(mp) < sizeof (struct ether_header)) { 1728*10491SRishi.Srivatsavai@Sun.COM mpcopy = msgpullup(mp, sizeof (struct ether_header)); 1729*10491SRishi.Srivatsavai@Sun.COM if (mpcopy == NULL) { 1730*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 1731*10491SRishi.Srivatsavai@Sun.COM return (NULL); 1732*10491SRishi.Srivatsavai@Sun.COM } 1733*10491SRishi.Srivatsavai@Sun.COM mp = mpcopy; 1734*10491SRishi.Srivatsavai@Sun.COM } 1735*10491SRishi.Srivatsavai@Sun.COM if (DB_REF(mp) > 1 || !IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)) || 1736*10491SRishi.Srivatsavai@Sun.COM (!source_has_tag && MBLKTAIL(mp) < VLAN_INCR)) { 1737*10491SRishi.Srivatsavai@Sun.COM minlen = mlen = MBLKL(mp); 1738*10491SRishi.Srivatsavai@Sun.COM if (!source_has_tag) 1739*10491SRishi.Srivatsavai@Sun.COM minlen += VLAN_INCR; 1740*10491SRishi.Srivatsavai@Sun.COM ASSERT(minlen >= sizeof (struct ether_vlan_header)); 1741*10491SRishi.Srivatsavai@Sun.COM /* 1742*10491SRishi.Srivatsavai@Sun.COM * We're willing to copy some data to avoid fragmentation, but 1743*10491SRishi.Srivatsavai@Sun.COM * not a lot. 1744*10491SRishi.Srivatsavai@Sun.COM */ 1745*10491SRishi.Srivatsavai@Sun.COM if (minlen > 256) 1746*10491SRishi.Srivatsavai@Sun.COM minlen = sizeof (struct ether_vlan_header); 1747*10491SRishi.Srivatsavai@Sun.COM mpcopy = allocb(minlen, BPRI_MED); 1748*10491SRishi.Srivatsavai@Sun.COM if (mpcopy == NULL) { 1749*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 1750*10491SRishi.Srivatsavai@Sun.COM return (NULL); 1751*10491SRishi.Srivatsavai@Sun.COM } 1752*10491SRishi.Srivatsavai@Sun.COM if (mlen <= minlen) { 1753*10491SRishi.Srivatsavai@Sun.COM /* We toss the first mblk when we can. */ 1754*10491SRishi.Srivatsavai@Sun.COM bcopy(mp->b_rptr, mpcopy->b_rptr, mlen); 1755*10491SRishi.Srivatsavai@Sun.COM mpcopy->b_wptr += mlen; 1756*10491SRishi.Srivatsavai@Sun.COM mpcopy->b_cont = mp->b_cont; 1757*10491SRishi.Srivatsavai@Sun.COM freeb(mp); 1758*10491SRishi.Srivatsavai@Sun.COM } else { 1759*10491SRishi.Srivatsavai@Sun.COM /* If not, then just copy what we need */ 1760*10491SRishi.Srivatsavai@Sun.COM if (!source_has_tag) 1761*10491SRishi.Srivatsavai@Sun.COM minlen = sizeof (struct ether_header); 1762*10491SRishi.Srivatsavai@Sun.COM bcopy(mp->b_rptr, mpcopy->b_rptr, minlen); 1763*10491SRishi.Srivatsavai@Sun.COM mpcopy->b_wptr += minlen; 1764*10491SRishi.Srivatsavai@Sun.COM mpcopy->b_cont = mp; 1765*10491SRishi.Srivatsavai@Sun.COM mp->b_rptr += minlen; 1766*10491SRishi.Srivatsavai@Sun.COM } 1767*10491SRishi.Srivatsavai@Sun.COM mp = mpcopy; 1768*10491SRishi.Srivatsavai@Sun.COM } 1769*10491SRishi.Srivatsavai@Sun.COM 1770*10491SRishi.Srivatsavai@Sun.COM /* LINTED: pointer alignment */ 1771*10491SRishi.Srivatsavai@Sun.COM evh = (struct ether_vlan_header *)mp->b_rptr; 1772*10491SRishi.Srivatsavai@Sun.COM if (source_has_tag) { 1773*10491SRishi.Srivatsavai@Sun.COM if (mp->b_band == 0 && vlanid == pvid) { /* 3 */ 1774*10491SRishi.Srivatsavai@Sun.COM evh->ether_tpid = evh->ether_type; 1775*10491SRishi.Srivatsavai@Sun.COM mlen = MBLKL(mp); 1776*10491SRishi.Srivatsavai@Sun.COM if (mlen > sizeof (struct ether_vlan_header)) 1777*10491SRishi.Srivatsavai@Sun.COM ovbcopy(mp->b_rptr + 1778*10491SRishi.Srivatsavai@Sun.COM sizeof (struct ether_vlan_header), 1779*10491SRishi.Srivatsavai@Sun.COM mp->b_rptr + sizeof (struct ether_header), 1780*10491SRishi.Srivatsavai@Sun.COM mlen - sizeof (struct ether_vlan_header)); 1781*10491SRishi.Srivatsavai@Sun.COM mp->b_wptr -= VLAN_INCR; 1782*10491SRishi.Srivatsavai@Sun.COM } else { /* 2 */ 1783*10491SRishi.Srivatsavai@Sun.COM if (vlanid == pvid) 1784*10491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID_NONE; 1785*10491SRishi.Srivatsavai@Sun.COM tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid); 1786*10491SRishi.Srivatsavai@Sun.COM evh->ether_tci = htons(tci); 1787*10491SRishi.Srivatsavai@Sun.COM } 1788*10491SRishi.Srivatsavai@Sun.COM } else { 1789*10491SRishi.Srivatsavai@Sun.COM /* case 4: no header present, but one is needed */ 1790*10491SRishi.Srivatsavai@Sun.COM mlen = MBLKL(mp); 1791*10491SRishi.Srivatsavai@Sun.COM if (mlen > sizeof (struct ether_header)) 1792*10491SRishi.Srivatsavai@Sun.COM ovbcopy(mp->b_rptr + sizeof (struct ether_header), 1793*10491SRishi.Srivatsavai@Sun.COM mp->b_rptr + sizeof (struct ether_vlan_header), 1794*10491SRishi.Srivatsavai@Sun.COM mlen - sizeof (struct ether_header)); 1795*10491SRishi.Srivatsavai@Sun.COM mp->b_wptr += VLAN_INCR; 1796*10491SRishi.Srivatsavai@Sun.COM ASSERT(mp->b_wptr <= DB_LIM(mp)); 1797*10491SRishi.Srivatsavai@Sun.COM if (vlanid == pvid) 1798*10491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID_NONE; 1799*10491SRishi.Srivatsavai@Sun.COM tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid); 1800*10491SRishi.Srivatsavai@Sun.COM evh->ether_type = evh->ether_tpid; 1801*10491SRishi.Srivatsavai@Sun.COM evh->ether_tpid = htons(ETHERTYPE_VLAN); 1802*10491SRishi.Srivatsavai@Sun.COM evh->ether_tci = htons(tci); 1803*10491SRishi.Srivatsavai@Sun.COM } 1804*10491SRishi.Srivatsavai@Sun.COM return (mp); 1805*10491SRishi.Srivatsavai@Sun.COM } 1806*10491SRishi.Srivatsavai@Sun.COM 1807*10491SRishi.Srivatsavai@Sun.COM /* Record VLAN information and strip header if requested . */ 1808*10491SRishi.Srivatsavai@Sun.COM static void 1809*10491SRishi.Srivatsavai@Sun.COM update_header(mblk_t *mp, mac_header_info_t *hdr_info, boolean_t striphdr) 1810*10491SRishi.Srivatsavai@Sun.COM { 1811*10491SRishi.Srivatsavai@Sun.COM if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) { 1812*10491SRishi.Srivatsavai@Sun.COM struct ether_vlan_header *evhp; 1813*10491SRishi.Srivatsavai@Sun.COM uint16_t ether_type; 1814*10491SRishi.Srivatsavai@Sun.COM 1815*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 1816*10491SRishi.Srivatsavai@Sun.COM evhp = (struct ether_vlan_header *)mp->b_rptr; 1817*10491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_istagged = B_TRUE; 1818*10491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_tci = ntohs(evhp->ether_tci); 1819*10491SRishi.Srivatsavai@Sun.COM if (striphdr) { 1820*10491SRishi.Srivatsavai@Sun.COM /* 1821*10491SRishi.Srivatsavai@Sun.COM * For VLAN tagged frames update the ether_type 1822*10491SRishi.Srivatsavai@Sun.COM * in hdr_info before stripping the header. 1823*10491SRishi.Srivatsavai@Sun.COM */ 1824*10491SRishi.Srivatsavai@Sun.COM ether_type = ntohs(evhp->ether_type); 1825*10491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_origsap = ether_type; 1826*10491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ? 1827*10491SRishi.Srivatsavai@Sun.COM ether_type : DLS_SAP_LLC; 1828*10491SRishi.Srivatsavai@Sun.COM mp->b_rptr = (uchar_t *)(evhp + 1); 1829*10491SRishi.Srivatsavai@Sun.COM } 1830*10491SRishi.Srivatsavai@Sun.COM } else { 1831*10491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_istagged = B_FALSE; 1832*10491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_tci = VLAN_ID_NONE; 1833*10491SRishi.Srivatsavai@Sun.COM if (striphdr) 1834*10491SRishi.Srivatsavai@Sun.COM mp->b_rptr += sizeof (struct ether_header); 1835*10491SRishi.Srivatsavai@Sun.COM } 1836*10491SRishi.Srivatsavai@Sun.COM } 1837*10491SRishi.Srivatsavai@Sun.COM 1838*10491SRishi.Srivatsavai@Sun.COM /* 1839*10491SRishi.Srivatsavai@Sun.COM * Return B_TRUE if we're allowed to send on this link with the given VLAN ID. 1840*10491SRishi.Srivatsavai@Sun.COM */ 1841*10491SRishi.Srivatsavai@Sun.COM static boolean_t 1842*10491SRishi.Srivatsavai@Sun.COM bridge_can_send(bridge_link_t *blp, uint16_t vlanid) 1843*10491SRishi.Srivatsavai@Sun.COM { 1844*10491SRishi.Srivatsavai@Sun.COM ASSERT(vlanid != VLAN_ID_NONE); 1845*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_DELETED) 1846*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 1847*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_trilldata == NULL && blp->bl_state != BLS_FORWARDING) 1848*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 1849*10491SRishi.Srivatsavai@Sun.COM return (BRIDGE_VLAN_ISSET(blp, vlanid) && BRIDGE_AF_ISSET(blp, vlanid)); 1850*10491SRishi.Srivatsavai@Sun.COM } 1851*10491SRishi.Srivatsavai@Sun.COM 1852*10491SRishi.Srivatsavai@Sun.COM /* 1853*10491SRishi.Srivatsavai@Sun.COM * This function scans the bridge forwarding tables in order to forward a given 1854*10491SRishi.Srivatsavai@Sun.COM * packet. If the packet either doesn't need forwarding (the current link is 1855*10491SRishi.Srivatsavai@Sun.COM * correct) or the current link needs a copy as well, then the packet is 1856*10491SRishi.Srivatsavai@Sun.COM * returned to the caller. 1857*10491SRishi.Srivatsavai@Sun.COM * 1858*10491SRishi.Srivatsavai@Sun.COM * If a packet has been decapsulated from TRILL, then it must *NOT* reenter a 1859*10491SRishi.Srivatsavai@Sun.COM * TRILL tunnel. If the destination points there, then drop instead. 1860*10491SRishi.Srivatsavai@Sun.COM */ 1861*10491SRishi.Srivatsavai@Sun.COM static mblk_t * 1862*10491SRishi.Srivatsavai@Sun.COM bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, 1863*10491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, uint16_t tci, boolean_t from_trill, boolean_t is_xmit) 1864*10491SRishi.Srivatsavai@Sun.COM { 1865*10491SRishi.Srivatsavai@Sun.COM mblk_t *mpsend, *mpcopy; 1866*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 1867*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blpsend, *blpnext; 1868*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp; 1869*10491SRishi.Srivatsavai@Sun.COM uint_t i; 1870*10491SRishi.Srivatsavai@Sun.COM boolean_t selfseen = B_FALSE; 1871*10491SRishi.Srivatsavai@Sun.COM void *tdp; 1872*10491SRishi.Srivatsavai@Sun.COM const uint8_t *daddr = hdr_info->mhi_daddr; 1873*10491SRishi.Srivatsavai@Sun.COM 1874*10491SRishi.Srivatsavai@Sun.COM /* 1875*10491SRishi.Srivatsavai@Sun.COM * Check for the IEEE "reserved" multicast addresses. Messages sent to 1876*10491SRishi.Srivatsavai@Sun.COM * these addresses are used for link-local control (STP and pause), and 1877*10491SRishi.Srivatsavai@Sun.COM * are never forwarded or redirected. 1878*10491SRishi.Srivatsavai@Sun.COM */ 1879*10491SRishi.Srivatsavai@Sun.COM if (daddr[0] == 1 && daddr[1] == 0x80 && daddr[2] == 0xc2 && 1880*10491SRishi.Srivatsavai@Sun.COM daddr[3] == 0 && daddr[4] == 0 && (daddr[5] & 0xf0) == 0) { 1881*10491SRishi.Srivatsavai@Sun.COM if (from_trill) { 1882*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 1883*10491SRishi.Srivatsavai@Sun.COM mp = NULL; 1884*10491SRishi.Srivatsavai@Sun.COM } 1885*10491SRishi.Srivatsavai@Sun.COM return (mp); 1886*10491SRishi.Srivatsavai@Sun.COM } 1887*10491SRishi.Srivatsavai@Sun.COM 1888*10491SRishi.Srivatsavai@Sun.COM if ((bfp = fwd_find(bip, daddr, vlanid)) != NULL) { 1889*10491SRishi.Srivatsavai@Sun.COM 1890*10491SRishi.Srivatsavai@Sun.COM /* 1891*10491SRishi.Srivatsavai@Sun.COM * If trill indicates a destination for this node, then it's 1892*10491SRishi.Srivatsavai@Sun.COM * clearly not intended for local delivery. We must tell TRILL 1893*10491SRishi.Srivatsavai@Sun.COM * to encapsulate, as long as we didn't just decapsulate it. 1894*10491SRishi.Srivatsavai@Sun.COM */ 1895*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) { 1896*10491SRishi.Srivatsavai@Sun.COM /* 1897*10491SRishi.Srivatsavai@Sun.COM * Error case: can't reencapsulate if the protocols are 1898*10491SRishi.Srivatsavai@Sun.COM * working correctly. 1899*10491SRishi.Srivatsavai@Sun.COM */ 1900*10491SRishi.Srivatsavai@Sun.COM if (from_trill) { 1901*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 1902*10491SRishi.Srivatsavai@Sun.COM return (NULL); 1903*10491SRishi.Srivatsavai@Sun.COM } 1904*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 1905*10491SRishi.Srivatsavai@Sun.COM if ((tdp = blp->bl_trilldata) != NULL) { 1906*10491SRishi.Srivatsavai@Sun.COM blp->bl_trillthreads++; 1907*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 1908*10491SRishi.Srivatsavai@Sun.COM update_header(mp, hdr_info, B_FALSE); 1909*10491SRishi.Srivatsavai@Sun.COM if (is_xmit) 1910*10491SRishi.Srivatsavai@Sun.COM mp = mac_fix_cksum(mp); 1911*10491SRishi.Srivatsavai@Sun.COM /* all trill data frames have Inner.VLAN */ 1912*10491SRishi.Srivatsavai@Sun.COM mp = reform_vlan_header(mp, vlanid, tci, 0); 1913*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 1914*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 1915*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1916*10491SRishi.Srivatsavai@Sun.COM return (NULL); 1917*10491SRishi.Srivatsavai@Sun.COM } 1918*10491SRishi.Srivatsavai@Sun.COM trill_encap_fn(tdp, blp, hdr_info, mp, 1919*10491SRishi.Srivatsavai@Sun.COM bfp->bf_trill_nick); 1920*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 1921*10491SRishi.Srivatsavai@Sun.COM if (--blp->bl_trillthreads == 0 && 1922*10491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata == NULL) 1923*10491SRishi.Srivatsavai@Sun.COM cv_broadcast(&blp->bl_trillwait); 1924*10491SRishi.Srivatsavai@Sun.COM } 1925*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 1926*10491SRishi.Srivatsavai@Sun.COM 1927*10491SRishi.Srivatsavai@Sun.COM /* if TRILL has been disabled, then kill this stray */ 1928*10491SRishi.Srivatsavai@Sun.COM if (tdp == NULL) { 1929*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 1930*10491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 1931*10491SRishi.Srivatsavai@Sun.COM } 1932*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1933*10491SRishi.Srivatsavai@Sun.COM return (NULL); 1934*10491SRishi.Srivatsavai@Sun.COM } 1935*10491SRishi.Srivatsavai@Sun.COM 1936*10491SRishi.Srivatsavai@Sun.COM /* find first link we can send on */ 1937*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 1938*10491SRishi.Srivatsavai@Sun.COM blpsend = bfp->bf_links[i]; 1939*10491SRishi.Srivatsavai@Sun.COM if (blpsend == blp) 1940*10491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 1941*10491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpsend, vlanid)) 1942*10491SRishi.Srivatsavai@Sun.COM break; 1943*10491SRishi.Srivatsavai@Sun.COM } 1944*10491SRishi.Srivatsavai@Sun.COM 1945*10491SRishi.Srivatsavai@Sun.COM while (i < bfp->bf_nlinks) { 1946*10491SRishi.Srivatsavai@Sun.COM blpsend = bfp->bf_links[i]; 1947*10491SRishi.Srivatsavai@Sun.COM for (i++; i < bfp->bf_nlinks; i++) { 1948*10491SRishi.Srivatsavai@Sun.COM blpnext = bfp->bf_links[i]; 1949*10491SRishi.Srivatsavai@Sun.COM if (blpnext == blp) 1950*10491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 1951*10491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpnext, vlanid)) 1952*10491SRishi.Srivatsavai@Sun.COM break; 1953*10491SRishi.Srivatsavai@Sun.COM } 1954*10491SRishi.Srivatsavai@Sun.COM if (i == bfp->bf_nlinks && !selfseen) { 1955*10491SRishi.Srivatsavai@Sun.COM mpsend = mp; 1956*10491SRishi.Srivatsavai@Sun.COM mp = NULL; 1957*10491SRishi.Srivatsavai@Sun.COM } else { 1958*10491SRishi.Srivatsavai@Sun.COM mpsend = copymsg(mp); 1959*10491SRishi.Srivatsavai@Sun.COM } 1960*10491SRishi.Srivatsavai@Sun.COM 1961*10491SRishi.Srivatsavai@Sun.COM if (!from_trill && is_xmit) 1962*10491SRishi.Srivatsavai@Sun.COM mpsend = mac_fix_cksum(mpsend); 1963*10491SRishi.Srivatsavai@Sun.COM 1964*10491SRishi.Srivatsavai@Sun.COM mpsend = reform_vlan_header(mpsend, vlanid, tci, 1965*10491SRishi.Srivatsavai@Sun.COM blpsend->bl_pvid); 1966*10491SRishi.Srivatsavai@Sun.COM if (mpsend == NULL) { 1967*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 1968*10491SRishi.Srivatsavai@Sun.COM continue; 1969*10491SRishi.Srivatsavai@Sun.COM } 1970*10491SRishi.Srivatsavai@Sun.COM 1971*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_forwards); 1972*10491SRishi.Srivatsavai@Sun.COM /* 1973*10491SRishi.Srivatsavai@Sun.COM * No need to bump up the link reference count, as 1974*10491SRishi.Srivatsavai@Sun.COM * the forwarding entry itself holds a reference to 1975*10491SRishi.Srivatsavai@Sun.COM * the link. 1976*10491SRishi.Srivatsavai@Sun.COM */ 1977*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) { 1978*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blpsend->bl_mh, NULL, mpsend); 1979*10491SRishi.Srivatsavai@Sun.COM } else { 1980*10491SRishi.Srivatsavai@Sun.COM KLPINCR(blpsend, bkl_xmit); 1981*10491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, 1982*10491SRishi.Srivatsavai@Sun.COM mpsend); 1983*10491SRishi.Srivatsavai@Sun.COM freemsg(mpsend); 1984*10491SRishi.Srivatsavai@Sun.COM } 1985*10491SRishi.Srivatsavai@Sun.COM } 1986*10491SRishi.Srivatsavai@Sun.COM /* 1987*10491SRishi.Srivatsavai@Sun.COM * Handle a special case: if we're transmitting to the original 1988*10491SRishi.Srivatsavai@Sun.COM * link, then check whether the localaddr flag is set. If it 1989*10491SRishi.Srivatsavai@Sun.COM * is, then receive instead. This doesn't happen with ordinary 1990*10491SRishi.Srivatsavai@Sun.COM * bridging, but does happen often with TRILL decapsulation. 1991*10491SRishi.Srivatsavai@Sun.COM */ 1992*10491SRishi.Srivatsavai@Sun.COM if (mp != NULL && is_xmit && (bfp->bf_flags & BFF_LOCALADDR)) { 1993*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, NULL, mp); 1994*10491SRishi.Srivatsavai@Sun.COM mp = NULL; 1995*10491SRishi.Srivatsavai@Sun.COM } 1996*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 1997*10491SRishi.Srivatsavai@Sun.COM } else { 1998*10491SRishi.Srivatsavai@Sun.COM /* 1999*10491SRishi.Srivatsavai@Sun.COM * TRILL has two cases to handle. If the packet is off the 2000*10491SRishi.Srivatsavai@Sun.COM * wire (not from TRILL), then we need to send up into the 2001*10491SRishi.Srivatsavai@Sun.COM * TRILL module to have the distribution tree computed. If the 2002*10491SRishi.Srivatsavai@Sun.COM * packet is from TRILL (decapsulated), then we're part of the 2003*10491SRishi.Srivatsavai@Sun.COM * distribution tree, and we need to copy the packet on member 2004*10491SRishi.Srivatsavai@Sun.COM * interfaces. 2005*10491SRishi.Srivatsavai@Sun.COM * 2006*10491SRishi.Srivatsavai@Sun.COM * Thus, the from TRILL case is identical to the STP case. 2007*10491SRishi.Srivatsavai@Sun.COM */ 2008*10491SRishi.Srivatsavai@Sun.COM if (!from_trill && blp->bl_trilldata != NULL) { 2009*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 2010*10491SRishi.Srivatsavai@Sun.COM if ((tdp = blp->bl_trilldata) != NULL) { 2011*10491SRishi.Srivatsavai@Sun.COM blp->bl_trillthreads++; 2012*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 2013*10491SRishi.Srivatsavai@Sun.COM if ((mpsend = copymsg(mp)) != NULL) { 2014*10491SRishi.Srivatsavai@Sun.COM update_header(mpsend, 2015*10491SRishi.Srivatsavai@Sun.COM hdr_info, B_FALSE); 2016*10491SRishi.Srivatsavai@Sun.COM /* 2017*10491SRishi.Srivatsavai@Sun.COM * all trill data frames have 2018*10491SRishi.Srivatsavai@Sun.COM * Inner.VLAN 2019*10491SRishi.Srivatsavai@Sun.COM */ 2020*10491SRishi.Srivatsavai@Sun.COM mpsend = reform_vlan_header(mpsend, 2021*10491SRishi.Srivatsavai@Sun.COM vlanid, tci, 0); 2022*10491SRishi.Srivatsavai@Sun.COM if (mpsend == NULL) { 2023*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 2024*10491SRishi.Srivatsavai@Sun.COM } else { 2025*10491SRishi.Srivatsavai@Sun.COM trill_encap_fn(tdp, blp, 2026*10491SRishi.Srivatsavai@Sun.COM hdr_info, mpsend, 2027*10491SRishi.Srivatsavai@Sun.COM RBRIDGE_NICKNAME_NONE); 2028*10491SRishi.Srivatsavai@Sun.COM } 2029*10491SRishi.Srivatsavai@Sun.COM } 2030*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 2031*10491SRishi.Srivatsavai@Sun.COM if (--blp->bl_trillthreads == 0 && 2032*10491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata == NULL) 2033*10491SRishi.Srivatsavai@Sun.COM cv_broadcast(&blp->bl_trillwait); 2034*10491SRishi.Srivatsavai@Sun.COM } 2035*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 2036*10491SRishi.Srivatsavai@Sun.COM } 2037*10491SRishi.Srivatsavai@Sun.COM 2038*10491SRishi.Srivatsavai@Sun.COM /* 2039*10491SRishi.Srivatsavai@Sun.COM * This is an unknown destination, so flood. 2040*10491SRishi.Srivatsavai@Sun.COM */ 2041*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 2042*10491SRishi.Srivatsavai@Sun.COM for (blpnext = list_head(&bip->bi_links); blpnext != NULL; 2043*10491SRishi.Srivatsavai@Sun.COM blpnext = list_next(&bip->bi_links, blpnext)) { 2044*10491SRishi.Srivatsavai@Sun.COM if (blpnext == blp) 2045*10491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 2046*10491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpnext, vlanid)) 2047*10491SRishi.Srivatsavai@Sun.COM break; 2048*10491SRishi.Srivatsavai@Sun.COM } 2049*10491SRishi.Srivatsavai@Sun.COM if (blpnext != NULL) 2050*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blpnext->bl_refs); 2051*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 2052*10491SRishi.Srivatsavai@Sun.COM while ((blpsend = blpnext) != NULL) { 2053*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 2054*10491SRishi.Srivatsavai@Sun.COM for (blpnext = list_next(&bip->bi_links, blpsend); 2055*10491SRishi.Srivatsavai@Sun.COM blpnext != NULL; 2056*10491SRishi.Srivatsavai@Sun.COM blpnext = list_next(&bip->bi_links, blpnext)) { 2057*10491SRishi.Srivatsavai@Sun.COM if (blpnext == blp) 2058*10491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 2059*10491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpnext, vlanid)) 2060*10491SRishi.Srivatsavai@Sun.COM break; 2061*10491SRishi.Srivatsavai@Sun.COM } 2062*10491SRishi.Srivatsavai@Sun.COM if (blpnext != NULL) 2063*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blpnext->bl_refs); 2064*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 2065*10491SRishi.Srivatsavai@Sun.COM if (blpnext == NULL && !selfseen) { 2066*10491SRishi.Srivatsavai@Sun.COM mpsend = mp; 2067*10491SRishi.Srivatsavai@Sun.COM mp = NULL; 2068*10491SRishi.Srivatsavai@Sun.COM } else { 2069*10491SRishi.Srivatsavai@Sun.COM mpsend = copymsg(mp); 2070*10491SRishi.Srivatsavai@Sun.COM } 2071*10491SRishi.Srivatsavai@Sun.COM 2072*10491SRishi.Srivatsavai@Sun.COM if (!from_trill && is_xmit) 2073*10491SRishi.Srivatsavai@Sun.COM mpsend = mac_fix_cksum(mpsend); 2074*10491SRishi.Srivatsavai@Sun.COM 2075*10491SRishi.Srivatsavai@Sun.COM mpsend = reform_vlan_header(mpsend, vlanid, tci, 2076*10491SRishi.Srivatsavai@Sun.COM blpsend->bl_pvid); 2077*10491SRishi.Srivatsavai@Sun.COM if (mpsend == NULL) { 2078*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 2079*10491SRishi.Srivatsavai@Sun.COM continue; 2080*10491SRishi.Srivatsavai@Sun.COM } 2081*10491SRishi.Srivatsavai@Sun.COM 2082*10491SRishi.Srivatsavai@Sun.COM if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST) 2083*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_unknown); 2084*10491SRishi.Srivatsavai@Sun.COM else 2085*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_mbcast); 2086*10491SRishi.Srivatsavai@Sun.COM KLPINCR(blpsend, bkl_xmit); 2087*10491SRishi.Srivatsavai@Sun.COM if ((mpcopy = copymsg(mpsend)) != NULL) 2088*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blpsend->bl_mh, NULL, mpcopy); 2089*10491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, mpsend); 2090*10491SRishi.Srivatsavai@Sun.COM freemsg(mpsend); 2091*10491SRishi.Srivatsavai@Sun.COM link_unref(blpsend); 2092*10491SRishi.Srivatsavai@Sun.COM } 2093*10491SRishi.Srivatsavai@Sun.COM } 2094*10491SRishi.Srivatsavai@Sun.COM 2095*10491SRishi.Srivatsavai@Sun.COM /* 2096*10491SRishi.Srivatsavai@Sun.COM * At this point, if np is non-NULL, it means that the caller needs to 2097*10491SRishi.Srivatsavai@Sun.COM * continue on the selected link. 2098*10491SRishi.Srivatsavai@Sun.COM */ 2099*10491SRishi.Srivatsavai@Sun.COM return (mp); 2100*10491SRishi.Srivatsavai@Sun.COM } 2101*10491SRishi.Srivatsavai@Sun.COM 2102*10491SRishi.Srivatsavai@Sun.COM /* 2103*10491SRishi.Srivatsavai@Sun.COM * Extract and validate the VLAN information for a given packet. This checks 2104*10491SRishi.Srivatsavai@Sun.COM * conformance with the rules for use of the PVID on the link, and for the 2105*10491SRishi.Srivatsavai@Sun.COM * allowed (configured) VLAN set. 2106*10491SRishi.Srivatsavai@Sun.COM * 2107*10491SRishi.Srivatsavai@Sun.COM * Returns B_TRUE if the packet passes, B_FALSE if it fails. 2108*10491SRishi.Srivatsavai@Sun.COM */ 2109*10491SRishi.Srivatsavai@Sun.COM static boolean_t 2110*10491SRishi.Srivatsavai@Sun.COM bridge_get_vlan(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, 2111*10491SRishi.Srivatsavai@Sun.COM uint16_t *vlanidp, uint16_t *tcip) 2112*10491SRishi.Srivatsavai@Sun.COM { 2113*10491SRishi.Srivatsavai@Sun.COM uint16_t tci, vlanid; 2114*10491SRishi.Srivatsavai@Sun.COM 2115*10491SRishi.Srivatsavai@Sun.COM if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) { 2116*10491SRishi.Srivatsavai@Sun.COM ptrdiff_t tpos = offsetof(struct ether_vlan_header, ether_tci); 2117*10491SRishi.Srivatsavai@Sun.COM ptrdiff_t mlen; 2118*10491SRishi.Srivatsavai@Sun.COM 2119*10491SRishi.Srivatsavai@Sun.COM /* 2120*10491SRishi.Srivatsavai@Sun.COM * Extract the VLAN ID information, regardless of alignment, 2121*10491SRishi.Srivatsavai@Sun.COM * and without a pullup. This isn't attractive, but we do this 2122*10491SRishi.Srivatsavai@Sun.COM * to avoid having to deal with the pointers stashed in 2123*10491SRishi.Srivatsavai@Sun.COM * hdr_info moving around or having the caller deal with a new 2124*10491SRishi.Srivatsavai@Sun.COM * mblk_t pointer. 2125*10491SRishi.Srivatsavai@Sun.COM */ 2126*10491SRishi.Srivatsavai@Sun.COM while (mp != NULL) { 2127*10491SRishi.Srivatsavai@Sun.COM mlen = MBLKL(mp); 2128*10491SRishi.Srivatsavai@Sun.COM if (mlen > tpos && mlen > 0) 2129*10491SRishi.Srivatsavai@Sun.COM break; 2130*10491SRishi.Srivatsavai@Sun.COM tpos -= mlen; 2131*10491SRishi.Srivatsavai@Sun.COM mp = mp->b_cont; 2132*10491SRishi.Srivatsavai@Sun.COM } 2133*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) 2134*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 2135*10491SRishi.Srivatsavai@Sun.COM tci = mp->b_rptr[tpos] << 8; 2136*10491SRishi.Srivatsavai@Sun.COM if (++tpos >= mlen) { 2137*10491SRishi.Srivatsavai@Sun.COM do { 2138*10491SRishi.Srivatsavai@Sun.COM mp = mp->b_cont; 2139*10491SRishi.Srivatsavai@Sun.COM } while (mp != NULL && MBLKL(mp) == 0); 2140*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) 2141*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 2142*10491SRishi.Srivatsavai@Sun.COM tpos = 0; 2143*10491SRishi.Srivatsavai@Sun.COM } 2144*10491SRishi.Srivatsavai@Sun.COM tci |= mp->b_rptr[tpos]; 2145*10491SRishi.Srivatsavai@Sun.COM 2146*10491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID(tci); 2147*10491SRishi.Srivatsavai@Sun.COM if (VLAN_CFI(tci) != ETHER_CFI || vlanid > VLAN_ID_MAX) 2148*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 2149*10491SRishi.Srivatsavai@Sun.COM if (vlanid == VLAN_ID_NONE || vlanid == blp->bl_pvid) 2150*10491SRishi.Srivatsavai@Sun.COM goto input_no_vlan; 2151*10491SRishi.Srivatsavai@Sun.COM if (!BRIDGE_VLAN_ISSET(blp, vlanid)) 2152*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 2153*10491SRishi.Srivatsavai@Sun.COM } else { 2154*10491SRishi.Srivatsavai@Sun.COM tci = 0xFFFF; 2155*10491SRishi.Srivatsavai@Sun.COM input_no_vlan: 2156*10491SRishi.Srivatsavai@Sun.COM /* 2157*10491SRishi.Srivatsavai@Sun.COM * If PVID is set to zero, then untagged traffic is not 2158*10491SRishi.Srivatsavai@Sun.COM * supported here. Do not learn or forward. 2159*10491SRishi.Srivatsavai@Sun.COM */ 2160*10491SRishi.Srivatsavai@Sun.COM if ((vlanid = blp->bl_pvid) == VLAN_ID_NONE) 2161*10491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 2162*10491SRishi.Srivatsavai@Sun.COM } 2163*10491SRishi.Srivatsavai@Sun.COM 2164*10491SRishi.Srivatsavai@Sun.COM *tcip = tci; 2165*10491SRishi.Srivatsavai@Sun.COM *vlanidp = vlanid; 2166*10491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 2167*10491SRishi.Srivatsavai@Sun.COM } 2168*10491SRishi.Srivatsavai@Sun.COM 2169*10491SRishi.Srivatsavai@Sun.COM /* 2170*10491SRishi.Srivatsavai@Sun.COM * Handle MAC notifications. 2171*10491SRishi.Srivatsavai@Sun.COM */ 2172*10491SRishi.Srivatsavai@Sun.COM static void 2173*10491SRishi.Srivatsavai@Sun.COM bridge_notify_cb(void *arg, mac_notify_type_t note_type) 2174*10491SRishi.Srivatsavai@Sun.COM { 2175*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = arg; 2176*10491SRishi.Srivatsavai@Sun.COM 2177*10491SRishi.Srivatsavai@Sun.COM switch (note_type) { 2178*10491SRishi.Srivatsavai@Sun.COM case MAC_NOTE_UNICST: 2179*10491SRishi.Srivatsavai@Sun.COM bridge_new_unicst(blp); 2180*10491SRishi.Srivatsavai@Sun.COM break; 2181*10491SRishi.Srivatsavai@Sun.COM 2182*10491SRishi.Srivatsavai@Sun.COM case MAC_NOTE_SDU_SIZE: { 2183*10491SRishi.Srivatsavai@Sun.COM uint_t maxsdu; 2184*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 2185*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = bip->bi_mac; 2186*10491SRishi.Srivatsavai@Sun.COM boolean_t notify = B_FALSE; 2187*10491SRishi.Srivatsavai@Sun.COM mblk_t *mlist = NULL; 2188*10491SRishi.Srivatsavai@Sun.COM 2189*10491SRishi.Srivatsavai@Sun.COM mac_sdu_get(blp->bl_mh, NULL, &maxsdu); 2190*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 2191*10491SRishi.Srivatsavai@Sun.COM if (list_prev(&bip->bi_links, blp) == NULL && 2192*10491SRishi.Srivatsavai@Sun.COM list_next(&bip->bi_links, blp) == NULL) { 2193*10491SRishi.Srivatsavai@Sun.COM notify = (maxsdu != bmp->bm_maxsdu); 2194*10491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = maxsdu; 2195*10491SRishi.Srivatsavai@Sun.COM } 2196*10491SRishi.Srivatsavai@Sun.COM blp->bl_maxsdu = maxsdu; 2197*10491SRishi.Srivatsavai@Sun.COM if (maxsdu != bmp->bm_maxsdu) 2198*10491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_TRUE, &mlist); 2199*10491SRishi.Srivatsavai@Sun.COM else if (notify) 2200*10491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 2201*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 2202*10491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 2203*10491SRishi.Srivatsavai@Sun.COM break; 2204*10491SRishi.Srivatsavai@Sun.COM } 2205*10491SRishi.Srivatsavai@Sun.COM } 2206*10491SRishi.Srivatsavai@Sun.COM } 2207*10491SRishi.Srivatsavai@Sun.COM 2208*10491SRishi.Srivatsavai@Sun.COM /* 2209*10491SRishi.Srivatsavai@Sun.COM * This is called by the MAC layer. As with the transmit side, we're right in 2210*10491SRishi.Srivatsavai@Sun.COM * the data path for all I/O on this port, so if we don't need to forward this 2211*10491SRishi.Srivatsavai@Sun.COM * packet anywhere, we have to send it upwards via mac_rx_common. 2212*10491SRishi.Srivatsavai@Sun.COM */ 2213*10491SRishi.Srivatsavai@Sun.COM static void 2214*10491SRishi.Srivatsavai@Sun.COM bridge_recv_cb(mac_handle_t mh, mac_resource_handle_t rsrc, mblk_t *mpnext) 2215*10491SRishi.Srivatsavai@Sun.COM { 2216*10491SRishi.Srivatsavai@Sun.COM mblk_t *mp, *mpcopy; 2217*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 2218*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 2219*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = bip->bi_mac; 2220*10491SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 2221*10491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, tci; 2222*10491SRishi.Srivatsavai@Sun.COM boolean_t trillmode = B_FALSE; 2223*10491SRishi.Srivatsavai@Sun.COM 2224*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_recv); 2225*10491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_recv); 2226*10491SRishi.Srivatsavai@Sun.COM 2227*10491SRishi.Srivatsavai@Sun.COM /* 2228*10491SRishi.Srivatsavai@Sun.COM * Regardless of state, check for inbound TRILL packets when TRILL is 2229*10491SRishi.Srivatsavai@Sun.COM * active. These are pulled out of band and sent for TRILL handling. 2230*10491SRishi.Srivatsavai@Sun.COM */ 2231*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_trilldata != NULL) { 2232*10491SRishi.Srivatsavai@Sun.COM void *tdp; 2233*10491SRishi.Srivatsavai@Sun.COM mblk_t *newhead; 2234*10491SRishi.Srivatsavai@Sun.COM mblk_t *tail = NULL; 2235*10491SRishi.Srivatsavai@Sun.COM 2236*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 2237*10491SRishi.Srivatsavai@Sun.COM if ((tdp = blp->bl_trilldata) != NULL) { 2238*10491SRishi.Srivatsavai@Sun.COM blp->bl_trillthreads++; 2239*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 2240*10491SRishi.Srivatsavai@Sun.COM trillmode = B_TRUE; 2241*10491SRishi.Srivatsavai@Sun.COM newhead = mpnext; 2242*10491SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 2243*10491SRishi.Srivatsavai@Sun.COM boolean_t raw_isis, bridge_group; 2244*10491SRishi.Srivatsavai@Sun.COM 2245*10491SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 2246*10491SRishi.Srivatsavai@Sun.COM 2247*10491SRishi.Srivatsavai@Sun.COM /* 2248*10491SRishi.Srivatsavai@Sun.COM * If the header isn't readable, then leave on 2249*10491SRishi.Srivatsavai@Sun.COM * the list and continue. 2250*10491SRishi.Srivatsavai@Sun.COM */ 2251*10491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, 2252*10491SRishi.Srivatsavai@Sun.COM &hdr_info) != 0) { 2253*10491SRishi.Srivatsavai@Sun.COM tail = mp; 2254*10491SRishi.Srivatsavai@Sun.COM continue; 2255*10491SRishi.Srivatsavai@Sun.COM } 2256*10491SRishi.Srivatsavai@Sun.COM 2257*10491SRishi.Srivatsavai@Sun.COM /* 2258*10491SRishi.Srivatsavai@Sun.COM * The TRILL document specifies that, on 2259*10491SRishi.Srivatsavai@Sun.COM * Ethernet alone, IS-IS packets arrive with 2260*10491SRishi.Srivatsavai@Sun.COM * LLC rather than Ethertype, and using a 2261*10491SRishi.Srivatsavai@Sun.COM * specific destination address. We must check 2262*10491SRishi.Srivatsavai@Sun.COM * for that here. Also, we need to give BPDUs 2263*10491SRishi.Srivatsavai@Sun.COM * to TRILL for processing. 2264*10491SRishi.Srivatsavai@Sun.COM */ 2265*10491SRishi.Srivatsavai@Sun.COM raw_isis = bridge_group = B_FALSE; 2266*10491SRishi.Srivatsavai@Sun.COM if (hdr_info.mhi_dsttype == 2267*10491SRishi.Srivatsavai@Sun.COM MAC_ADDRTYPE_MULTICAST) { 2268*10491SRishi.Srivatsavai@Sun.COM if (memcmp(hdr_info.mhi_daddr, 2269*10491SRishi.Srivatsavai@Sun.COM all_isis_rbridges, ETHERADDRL) == 0) 2270*10491SRishi.Srivatsavai@Sun.COM raw_isis = B_TRUE; 2271*10491SRishi.Srivatsavai@Sun.COM else if (memcmp(hdr_info.mhi_daddr, 2272*10491SRishi.Srivatsavai@Sun.COM bridge_group_address, ETHERADDRL) == 2273*10491SRishi.Srivatsavai@Sun.COM 0) 2274*10491SRishi.Srivatsavai@Sun.COM bridge_group = B_TRUE; 2275*10491SRishi.Srivatsavai@Sun.COM } 2276*10491SRishi.Srivatsavai@Sun.COM if (!raw_isis && !bridge_group && 2277*10491SRishi.Srivatsavai@Sun.COM hdr_info.mhi_bindsap != ETHERTYPE_TRILL && 2278*10491SRishi.Srivatsavai@Sun.COM (hdr_info.mhi_bindsap != ETHERTYPE_VLAN || 2279*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 2280*10491SRishi.Srivatsavai@Sun.COM ((struct ether_vlan_header *)mp->b_rptr)-> 2281*10491SRishi.Srivatsavai@Sun.COM ether_type != htons(ETHERTYPE_TRILL))) { 2282*10491SRishi.Srivatsavai@Sun.COM tail = mp; 2283*10491SRishi.Srivatsavai@Sun.COM continue; 2284*10491SRishi.Srivatsavai@Sun.COM } 2285*10491SRishi.Srivatsavai@Sun.COM 2286*10491SRishi.Srivatsavai@Sun.COM /* 2287*10491SRishi.Srivatsavai@Sun.COM * We've got TRILL input. Remove from the list 2288*10491SRishi.Srivatsavai@Sun.COM * and send up through the TRILL module. (Send 2289*10491SRishi.Srivatsavai@Sun.COM * a copy through promiscuous receive just to 2290*10491SRishi.Srivatsavai@Sun.COM * support snooping on TRILL. Order isn't 2291*10491SRishi.Srivatsavai@Sun.COM * preserved strictly, but that doesn't matter 2292*10491SRishi.Srivatsavai@Sun.COM * here.) 2293*10491SRishi.Srivatsavai@Sun.COM */ 2294*10491SRishi.Srivatsavai@Sun.COM if (tail != NULL) 2295*10491SRishi.Srivatsavai@Sun.COM tail->b_next = mpnext; 2296*10491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 2297*10491SRishi.Srivatsavai@Sun.COM if (mp == newhead) 2298*10491SRishi.Srivatsavai@Sun.COM newhead = mpnext; 2299*10491SRishi.Srivatsavai@Sun.COM mac_trill_snoop(blp->bl_mh, mp); 2300*10491SRishi.Srivatsavai@Sun.COM update_header(mp, &hdr_info, B_TRUE); 2301*10491SRishi.Srivatsavai@Sun.COM /* 2302*10491SRishi.Srivatsavai@Sun.COM * On raw IS-IS and BPDU frames, we have to 2303*10491SRishi.Srivatsavai@Sun.COM * make sure that the length is trimmed 2304*10491SRishi.Srivatsavai@Sun.COM * properly. We use origsap in order to cope 2305*10491SRishi.Srivatsavai@Sun.COM * with jumbograms for IS-IS. (Regular mac 2306*10491SRishi.Srivatsavai@Sun.COM * can't.) 2307*10491SRishi.Srivatsavai@Sun.COM */ 2308*10491SRishi.Srivatsavai@Sun.COM if (raw_isis || bridge_group) { 2309*10491SRishi.Srivatsavai@Sun.COM size_t msglen = msgdsize(mp); 2310*10491SRishi.Srivatsavai@Sun.COM 2311*10491SRishi.Srivatsavai@Sun.COM if (msglen > hdr_info.mhi_origsap) { 2312*10491SRishi.Srivatsavai@Sun.COM (void) adjmsg(mp, 2313*10491SRishi.Srivatsavai@Sun.COM hdr_info.mhi_origsap - 2314*10491SRishi.Srivatsavai@Sun.COM msglen); 2315*10491SRishi.Srivatsavai@Sun.COM } else if (msglen < 2316*10491SRishi.Srivatsavai@Sun.COM hdr_info.mhi_origsap) { 2317*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 2318*10491SRishi.Srivatsavai@Sun.COM continue; 2319*10491SRishi.Srivatsavai@Sun.COM } 2320*10491SRishi.Srivatsavai@Sun.COM } 2321*10491SRishi.Srivatsavai@Sun.COM trill_recv_fn(tdp, blp, rsrc, mp, &hdr_info); 2322*10491SRishi.Srivatsavai@Sun.COM } 2323*10491SRishi.Srivatsavai@Sun.COM mpnext = newhead; 2324*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 2325*10491SRishi.Srivatsavai@Sun.COM if (--blp->bl_trillthreads == 0 && 2326*10491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata == NULL) 2327*10491SRishi.Srivatsavai@Sun.COM cv_broadcast(&blp->bl_trillwait); 2328*10491SRishi.Srivatsavai@Sun.COM } 2329*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 2330*10491SRishi.Srivatsavai@Sun.COM if (mpnext == NULL) 2331*10491SRishi.Srivatsavai@Sun.COM return; 2332*10491SRishi.Srivatsavai@Sun.COM } 2333*10491SRishi.Srivatsavai@Sun.COM 2334*10491SRishi.Srivatsavai@Sun.COM /* 2335*10491SRishi.Srivatsavai@Sun.COM * If this is a TRILL RBridge, then just check whether this link is 2336*10491SRishi.Srivatsavai@Sun.COM * used at all for forwarding. If not, then we're done. 2337*10491SRishi.Srivatsavai@Sun.COM */ 2338*10491SRishi.Srivatsavai@Sun.COM if (trillmode) { 2339*10491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_TRILLACTIVE) || 2340*10491SRishi.Srivatsavai@Sun.COM (blp->bl_flags & BLF_SDUFAIL)) { 2341*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mpnext); 2342*10491SRishi.Srivatsavai@Sun.COM return; 2343*10491SRishi.Srivatsavai@Sun.COM } 2344*10491SRishi.Srivatsavai@Sun.COM } else { 2345*10491SRishi.Srivatsavai@Sun.COM /* 2346*10491SRishi.Srivatsavai@Sun.COM * For regular (STP) bridges, if we're in blocking or listening 2347*10491SRishi.Srivatsavai@Sun.COM * state, then do nothing. We don't learn or forward until 2348*10491SRishi.Srivatsavai@Sun.COM * told to do so. 2349*10491SRishi.Srivatsavai@Sun.COM */ 2350*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_state == BLS_BLOCKLISTEN) { 2351*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mpnext); 2352*10491SRishi.Srivatsavai@Sun.COM return; 2353*10491SRishi.Srivatsavai@Sun.COM } 2354*10491SRishi.Srivatsavai@Sun.COM } 2355*10491SRishi.Srivatsavai@Sun.COM 2356*10491SRishi.Srivatsavai@Sun.COM /* 2357*10491SRishi.Srivatsavai@Sun.COM * Send a copy of the message chain up to the observability node users. 2358*10491SRishi.Srivatsavai@Sun.COM * For TRILL, we must obey the VLAN AF rules, so we go packet-by- 2359*10491SRishi.Srivatsavai@Sun.COM * packet. 2360*10491SRishi.Srivatsavai@Sun.COM */ 2361*10491SRishi.Srivatsavai@Sun.COM if (!trillmode && blp->bl_state == BLS_FORWARDING && 2362*10491SRishi.Srivatsavai@Sun.COM (bmp->bm_flags & BMF_STARTED) && 2363*10491SRishi.Srivatsavai@Sun.COM (mp = copymsgchain(mpnext)) != NULL) { 2364*10491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mp); 2365*10491SRishi.Srivatsavai@Sun.COM } 2366*10491SRishi.Srivatsavai@Sun.COM 2367*10491SRishi.Srivatsavai@Sun.COM /* 2368*10491SRishi.Srivatsavai@Sun.COM * We must be in learning or forwarding state, or using TRILL on a link 2369*10491SRishi.Srivatsavai@Sun.COM * with one or more VLANs active. For each packet in the list, process 2370*10491SRishi.Srivatsavai@Sun.COM * the source address, and then attempt to forward. 2371*10491SRishi.Srivatsavai@Sun.COM */ 2372*10491SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 2373*10491SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 2374*10491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 2375*10491SRishi.Srivatsavai@Sun.COM 2376*10491SRishi.Srivatsavai@Sun.COM /* 2377*10491SRishi.Srivatsavai@Sun.COM * If we can't decode the header or if the header specifies a 2378*10491SRishi.Srivatsavai@Sun.COM * multicast source address (impossible!), then don't bother 2379*10491SRishi.Srivatsavai@Sun.COM * learning or forwarding, but go ahead and forward up the 2380*10491SRishi.Srivatsavai@Sun.COM * stack for subsequent processing. 2381*10491SRishi.Srivatsavai@Sun.COM */ 2382*10491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0 || 2383*10491SRishi.Srivatsavai@Sun.COM (hdr_info.mhi_saddr[0] & 1) != 0) { 2384*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 2385*10491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_drops); 2386*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 2387*10491SRishi.Srivatsavai@Sun.COM continue; 2388*10491SRishi.Srivatsavai@Sun.COM } 2389*10491SRishi.Srivatsavai@Sun.COM 2390*10491SRishi.Srivatsavai@Sun.COM /* 2391*10491SRishi.Srivatsavai@Sun.COM * Extract and validate the VLAN ID for this packet. 2392*10491SRishi.Srivatsavai@Sun.COM */ 2393*10491SRishi.Srivatsavai@Sun.COM if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) || 2394*10491SRishi.Srivatsavai@Sun.COM !BRIDGE_AF_ISSET(blp, vlanid)) { 2395*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 2396*10491SRishi.Srivatsavai@Sun.COM continue; 2397*10491SRishi.Srivatsavai@Sun.COM } 2398*10491SRishi.Srivatsavai@Sun.COM 2399*10491SRishi.Srivatsavai@Sun.COM if (trillmode) { 2400*10491SRishi.Srivatsavai@Sun.COM /* 2401*10491SRishi.Srivatsavai@Sun.COM * Special test required by TRILL document: must 2402*10491SRishi.Srivatsavai@Sun.COM * discard frames with outer address set to ESADI. 2403*10491SRishi.Srivatsavai@Sun.COM */ 2404*10491SRishi.Srivatsavai@Sun.COM if (memcmp(hdr_info.mhi_daddr, all_esadi_rbridges, 2405*10491SRishi.Srivatsavai@Sun.COM ETHERADDRL) == 0) { 2406*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 2407*10491SRishi.Srivatsavai@Sun.COM continue; 2408*10491SRishi.Srivatsavai@Sun.COM } 2409*10491SRishi.Srivatsavai@Sun.COM 2410*10491SRishi.Srivatsavai@Sun.COM /* 2411*10491SRishi.Srivatsavai@Sun.COM * If we're in TRILL mode, then the call above to get 2412*10491SRishi.Srivatsavai@Sun.COM * the VLAN ID has also checked that we're the 2413*10491SRishi.Srivatsavai@Sun.COM * appointed forwarder, so report that we're handling 2414*10491SRishi.Srivatsavai@Sun.COM * this packet to any observability node users. 2415*10491SRishi.Srivatsavai@Sun.COM */ 2416*10491SRishi.Srivatsavai@Sun.COM if ((bmp->bm_flags & BMF_STARTED) && 2417*10491SRishi.Srivatsavai@Sun.COM (mpcopy = copymsg(mp)) != NULL) 2418*10491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mpcopy); 2419*10491SRishi.Srivatsavai@Sun.COM } 2420*10491SRishi.Srivatsavai@Sun.COM 2421*10491SRishi.Srivatsavai@Sun.COM /* 2422*10491SRishi.Srivatsavai@Sun.COM * First process the source address and learn from it. For 2423*10491SRishi.Srivatsavai@Sun.COM * TRILL, we learn only if we're the appointed forwarder. 2424*10491SRishi.Srivatsavai@Sun.COM */ 2425*10491SRishi.Srivatsavai@Sun.COM bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE, 2426*10491SRishi.Srivatsavai@Sun.COM vlanid); 2427*10491SRishi.Srivatsavai@Sun.COM 2428*10491SRishi.Srivatsavai@Sun.COM /* 2429*10491SRishi.Srivatsavai@Sun.COM * Now check whether we're forwarding and look up the 2430*10491SRishi.Srivatsavai@Sun.COM * destination. If we can forward, do so. 2431*10491SRishi.Srivatsavai@Sun.COM */ 2432*10491SRishi.Srivatsavai@Sun.COM if (trillmode || blp->bl_state == BLS_FORWARDING) { 2433*10491SRishi.Srivatsavai@Sun.COM mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, 2434*10491SRishi.Srivatsavai@Sun.COM B_FALSE, B_FALSE); 2435*10491SRishi.Srivatsavai@Sun.COM } 2436*10491SRishi.Srivatsavai@Sun.COM if (mp != NULL) 2437*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 2438*10491SRishi.Srivatsavai@Sun.COM } 2439*10491SRishi.Srivatsavai@Sun.COM } 2440*10491SRishi.Srivatsavai@Sun.COM 2441*10491SRishi.Srivatsavai@Sun.COM 2442*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 2443*10491SRishi.Srivatsavai@Sun.COM static mblk_t * 2444*10491SRishi.Srivatsavai@Sun.COM bridge_xmit_cb(mac_handle_t mh, mac_ring_handle_t rh, mblk_t *mpnext) 2445*10491SRishi.Srivatsavai@Sun.COM { 2446*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 2447*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 2448*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = bip->bi_mac; 2449*10491SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 2450*10491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, tci; 2451*10491SRishi.Srivatsavai@Sun.COM mblk_t *mp, *mpcopy; 2452*10491SRishi.Srivatsavai@Sun.COM boolean_t trillmode; 2453*10491SRishi.Srivatsavai@Sun.COM 2454*10491SRishi.Srivatsavai@Sun.COM trillmode = blp->bl_trilldata != NULL; 2455*10491SRishi.Srivatsavai@Sun.COM 2456*10491SRishi.Srivatsavai@Sun.COM /* 2457*10491SRishi.Srivatsavai@Sun.COM * If we're using STP and we're in blocking or listening state, or if 2458*10491SRishi.Srivatsavai@Sun.COM * we're using TRILL and no VLANs are active, then behave as though the 2459*10491SRishi.Srivatsavai@Sun.COM * bridge isn't here at all, and send on the local link alone. 2460*10491SRishi.Srivatsavai@Sun.COM */ 2461*10491SRishi.Srivatsavai@Sun.COM if ((!trillmode && blp->bl_state == BLS_BLOCKLISTEN) || 2462*10491SRishi.Srivatsavai@Sun.COM (trillmode && 2463*10491SRishi.Srivatsavai@Sun.COM (!(blp->bl_flags & BLF_TRILLACTIVE) || 2464*10491SRishi.Srivatsavai@Sun.COM (blp->bl_flags & BLF_SDUFAIL)))) { 2465*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 2466*10491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 2467*10491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, rh, mpnext, mp); 2468*10491SRishi.Srivatsavai@Sun.COM return (mp); 2469*10491SRishi.Srivatsavai@Sun.COM } 2470*10491SRishi.Srivatsavai@Sun.COM 2471*10491SRishi.Srivatsavai@Sun.COM /* 2472*10491SRishi.Srivatsavai@Sun.COM * Send a copy of the message up to the observability node users. 2473*10491SRishi.Srivatsavai@Sun.COM * TRILL needs to check on a packet-by-packet basis. 2474*10491SRishi.Srivatsavai@Sun.COM */ 2475*10491SRishi.Srivatsavai@Sun.COM if (!trillmode && blp->bl_state == BLS_FORWARDING && 2476*10491SRishi.Srivatsavai@Sun.COM (bmp->bm_flags & BMF_STARTED) && 2477*10491SRishi.Srivatsavai@Sun.COM (mp = copymsgchain(mpnext)) != NULL) { 2478*10491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mp); 2479*10491SRishi.Srivatsavai@Sun.COM } 2480*10491SRishi.Srivatsavai@Sun.COM 2481*10491SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 2482*10491SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 2483*10491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 2484*10491SRishi.Srivatsavai@Sun.COM 2485*10491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) { 2486*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 2487*10491SRishi.Srivatsavai@Sun.COM continue; 2488*10491SRishi.Srivatsavai@Sun.COM } 2489*10491SRishi.Srivatsavai@Sun.COM 2490*10491SRishi.Srivatsavai@Sun.COM /* 2491*10491SRishi.Srivatsavai@Sun.COM * Extract and validate the VLAN ID for this packet. 2492*10491SRishi.Srivatsavai@Sun.COM */ 2493*10491SRishi.Srivatsavai@Sun.COM if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) || 2494*10491SRishi.Srivatsavai@Sun.COM !BRIDGE_AF_ISSET(blp, vlanid)) { 2495*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 2496*10491SRishi.Srivatsavai@Sun.COM continue; 2497*10491SRishi.Srivatsavai@Sun.COM } 2498*10491SRishi.Srivatsavai@Sun.COM 2499*10491SRishi.Srivatsavai@Sun.COM /* 2500*10491SRishi.Srivatsavai@Sun.COM * If we're using TRILL, then we've now validated that we're 2501*10491SRishi.Srivatsavai@Sun.COM * the forwarder for this VLAN, so go ahead and let 2502*10491SRishi.Srivatsavai@Sun.COM * observability node users know about the packet. 2503*10491SRishi.Srivatsavai@Sun.COM */ 2504*10491SRishi.Srivatsavai@Sun.COM if (trillmode && (bmp->bm_flags & BMF_STARTED) && 2505*10491SRishi.Srivatsavai@Sun.COM (mpcopy = copymsg(mp)) != NULL) { 2506*10491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mpcopy); 2507*10491SRishi.Srivatsavai@Sun.COM } 2508*10491SRishi.Srivatsavai@Sun.COM 2509*10491SRishi.Srivatsavai@Sun.COM /* 2510*10491SRishi.Srivatsavai@Sun.COM * We have to learn from our own transmitted packets, because 2511*10491SRishi.Srivatsavai@Sun.COM * there may be a Solaris DLPI raw sender (who can specify his 2512*10491SRishi.Srivatsavai@Sun.COM * own source address) using promiscuous mode for receive. The 2513*10491SRishi.Srivatsavai@Sun.COM * mac layer information won't (and can't) tell us everything 2514*10491SRishi.Srivatsavai@Sun.COM * we need to know. 2515*10491SRishi.Srivatsavai@Sun.COM */ 2516*10491SRishi.Srivatsavai@Sun.COM bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE, 2517*10491SRishi.Srivatsavai@Sun.COM vlanid); 2518*10491SRishi.Srivatsavai@Sun.COM 2519*10491SRishi.Srivatsavai@Sun.COM /* attempt forwarding */ 2520*10491SRishi.Srivatsavai@Sun.COM if (trillmode || blp->bl_state == BLS_FORWARDING) { 2521*10491SRishi.Srivatsavai@Sun.COM mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, 2522*10491SRishi.Srivatsavai@Sun.COM B_FALSE, B_TRUE); 2523*10491SRishi.Srivatsavai@Sun.COM } 2524*10491SRishi.Srivatsavai@Sun.COM if (mp != NULL) { 2525*10491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, rh, mp, mp); 2526*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 2527*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 2528*10491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 2529*10491SRishi.Srivatsavai@Sun.COM } 2530*10491SRishi.Srivatsavai@Sun.COM } 2531*10491SRishi.Srivatsavai@Sun.COM /* 2532*10491SRishi.Srivatsavai@Sun.COM * If we get stuck, then stop. Don't let the user's output 2533*10491SRishi.Srivatsavai@Sun.COM * packets get out of order. (More importantly: don't try to 2534*10491SRishi.Srivatsavai@Sun.COM * bridge the same packet multiple times if flow control is 2535*10491SRishi.Srivatsavai@Sun.COM * asserted.) 2536*10491SRishi.Srivatsavai@Sun.COM */ 2537*10491SRishi.Srivatsavai@Sun.COM if (mp != NULL) { 2538*10491SRishi.Srivatsavai@Sun.COM mp->b_next = mpnext; 2539*10491SRishi.Srivatsavai@Sun.COM break; 2540*10491SRishi.Srivatsavai@Sun.COM } 2541*10491SRishi.Srivatsavai@Sun.COM } 2542*10491SRishi.Srivatsavai@Sun.COM return (mp); 2543*10491SRishi.Srivatsavai@Sun.COM } 2544*10491SRishi.Srivatsavai@Sun.COM 2545*10491SRishi.Srivatsavai@Sun.COM /* 2546*10491SRishi.Srivatsavai@Sun.COM * This is called by TRILL when it decapsulates an packet, and we must forward 2547*10491SRishi.Srivatsavai@Sun.COM * locally. On failure, we just drop. 2548*10491SRishi.Srivatsavai@Sun.COM * 2549*10491SRishi.Srivatsavai@Sun.COM * Note that the ingress_nick reported by TRILL must not represent this local 2550*10491SRishi.Srivatsavai@Sun.COM * node. 2551*10491SRishi.Srivatsavai@Sun.COM */ 2552*10491SRishi.Srivatsavai@Sun.COM void 2553*10491SRishi.Srivatsavai@Sun.COM bridge_trill_decaps(bridge_link_t *blp, mblk_t *mp, uint16_t ingress_nick) 2554*10491SRishi.Srivatsavai@Sun.COM { 2555*10491SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 2556*10491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, tci; 2557*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; /* used by macros */ 2558*10491SRishi.Srivatsavai@Sun.COM mblk_t *mpcopy; 2559*10491SRishi.Srivatsavai@Sun.COM 2560*10491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) { 2561*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 2562*10491SRishi.Srivatsavai@Sun.COM return; 2563*10491SRishi.Srivatsavai@Sun.COM } 2564*10491SRishi.Srivatsavai@Sun.COM 2565*10491SRishi.Srivatsavai@Sun.COM /* Extract VLAN ID for this packet. */ 2566*10491SRishi.Srivatsavai@Sun.COM if (hdr_info.mhi_bindsap == ETHERTYPE_VLAN) { 2567*10491SRishi.Srivatsavai@Sun.COM struct ether_vlan_header *evhp; 2568*10491SRishi.Srivatsavai@Sun.COM 2569*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 2570*10491SRishi.Srivatsavai@Sun.COM evhp = (struct ether_vlan_header *)mp->b_rptr; 2571*10491SRishi.Srivatsavai@Sun.COM tci = ntohs(evhp->ether_tci); 2572*10491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID(tci); 2573*10491SRishi.Srivatsavai@Sun.COM } else { 2574*10491SRishi.Srivatsavai@Sun.COM /* Inner VLAN headers are required in TRILL data packets */ 2575*10491SRishi.Srivatsavai@Sun.COM DTRACE_PROBE3(bridge__trill__decaps__novlan, bridge_link_t *, 2576*10491SRishi.Srivatsavai@Sun.COM blp, mblk_t *, mp, uint16_t, ingress_nick); 2577*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 2578*10491SRishi.Srivatsavai@Sun.COM return; 2579*10491SRishi.Srivatsavai@Sun.COM } 2580*10491SRishi.Srivatsavai@Sun.COM 2581*10491SRishi.Srivatsavai@Sun.COM /* Learn the location of this sender in the RBridge network */ 2582*10491SRishi.Srivatsavai@Sun.COM bridge_learn(blp, hdr_info.mhi_saddr, ingress_nick, vlanid); 2583*10491SRishi.Srivatsavai@Sun.COM 2584*10491SRishi.Srivatsavai@Sun.COM /* attempt forwarding */ 2585*10491SRishi.Srivatsavai@Sun.COM mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, B_TRUE, B_TRUE); 2586*10491SRishi.Srivatsavai@Sun.COM if (mp != NULL) { 2587*10491SRishi.Srivatsavai@Sun.COM if (bridge_can_send(blp, vlanid)) { 2588*10491SRishi.Srivatsavai@Sun.COM /* Deliver a copy locally as well */ 2589*10491SRishi.Srivatsavai@Sun.COM if ((mpcopy = copymsg(mp)) != NULL) 2590*10491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, NULL, mpcopy); 2591*10491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, NULL, mp, mp); 2592*10491SRishi.Srivatsavai@Sun.COM } 2593*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 2594*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 2595*10491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 2596*10491SRishi.Srivatsavai@Sun.COM } else { 2597*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 2598*10491SRishi.Srivatsavai@Sun.COM } 2599*10491SRishi.Srivatsavai@Sun.COM } 2600*10491SRishi.Srivatsavai@Sun.COM } 2601*10491SRishi.Srivatsavai@Sun.COM 2602*10491SRishi.Srivatsavai@Sun.COM /* 2603*10491SRishi.Srivatsavai@Sun.COM * This function is used by TRILL _only_ to transmit TRILL-encapsulated 2604*10491SRishi.Srivatsavai@Sun.COM * packets. It sends on a single underlying link and does not bridge. 2605*10491SRishi.Srivatsavai@Sun.COM */ 2606*10491SRishi.Srivatsavai@Sun.COM mblk_t * 2607*10491SRishi.Srivatsavai@Sun.COM bridge_trill_output(bridge_link_t *blp, mblk_t *mp) 2608*10491SRishi.Srivatsavai@Sun.COM { 2609*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; /* used by macros */ 2610*10491SRishi.Srivatsavai@Sun.COM 2611*10491SRishi.Srivatsavai@Sun.COM mac_trill_snoop(blp->bl_mh, mp); 2612*10491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, NULL, mp, mp); 2613*10491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 2614*10491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 2615*10491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 2616*10491SRishi.Srivatsavai@Sun.COM } 2617*10491SRishi.Srivatsavai@Sun.COM return (mp); 2618*10491SRishi.Srivatsavai@Sun.COM } 2619*10491SRishi.Srivatsavai@Sun.COM 2620*10491SRishi.Srivatsavai@Sun.COM /* 2621*10491SRishi.Srivatsavai@Sun.COM * Set the "appointed forwarder" flag array for this link. TRILL controls 2622*10491SRishi.Srivatsavai@Sun.COM * forwarding on a VLAN basis. The "trillactive" flag is an optimization for 2623*10491SRishi.Srivatsavai@Sun.COM * the forwarder. 2624*10491SRishi.Srivatsavai@Sun.COM */ 2625*10491SRishi.Srivatsavai@Sun.COM void 2626*10491SRishi.Srivatsavai@Sun.COM bridge_trill_setvlans(bridge_link_t *blp, const uint8_t *arr) 2627*10491SRishi.Srivatsavai@Sun.COM { 2628*10491SRishi.Srivatsavai@Sun.COM int i; 2629*10491SRishi.Srivatsavai@Sun.COM uint_t newflags = 0; 2630*10491SRishi.Srivatsavai@Sun.COM 2631*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) { 2632*10491SRishi.Srivatsavai@Sun.COM if ((blp->bl_afs[i] = arr[i]) != 0) 2633*10491SRishi.Srivatsavai@Sun.COM newflags = BLF_TRILLACTIVE; 2634*10491SRishi.Srivatsavai@Sun.COM } 2635*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags = (blp->bl_flags & ~BLF_TRILLACTIVE) | newflags; 2636*10491SRishi.Srivatsavai@Sun.COM } 2637*10491SRishi.Srivatsavai@Sun.COM 2638*10491SRishi.Srivatsavai@Sun.COM void 2639*10491SRishi.Srivatsavai@Sun.COM bridge_trill_flush(bridge_link_t *blp, uint16_t vlan, boolean_t dotrill) 2640*10491SRishi.Srivatsavai@Sun.COM { 2641*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 2642*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 2643*10491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 2644*10491SRishi.Srivatsavai@Sun.COM int i; 2645*10491SRishi.Srivatsavai@Sun.COM 2646*10491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(vlan)); 2647*10491SRishi.Srivatsavai@Sun.COM 2648*10491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 2649*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 2650*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 2651*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 2652*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 2653*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 2654*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) 2655*10491SRishi.Srivatsavai@Sun.COM continue; 2656*10491SRishi.Srivatsavai@Sun.COM if (dotrill) { 2657*10491SRishi.Srivatsavai@Sun.COM /* port doesn't matter if we're flushing TRILL */ 2658*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick == RBRIDGE_NICKNAME_NONE) 2659*10491SRishi.Srivatsavai@Sun.COM continue; 2660*10491SRishi.Srivatsavai@Sun.COM } else { 2661*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) 2662*10491SRishi.Srivatsavai@Sun.COM continue; 2663*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 2664*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) 2665*10491SRishi.Srivatsavai@Sun.COM break; 2666*10491SRishi.Srivatsavai@Sun.COM } 2667*10491SRishi.Srivatsavai@Sun.COM if (i >= bfp->bf_nlinks) 2668*10491SRishi.Srivatsavai@Sun.COM continue; 2669*10491SRishi.Srivatsavai@Sun.COM } 2670*10491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 2671*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 2672*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 2673*10491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 2674*10491SRishi.Srivatsavai@Sun.COM } 2675*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 2676*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 2677*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 2678*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 2679*10491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 2680*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 2681*10491SRishi.Srivatsavai@Sun.COM } 2682*10491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 2683*10491SRishi.Srivatsavai@Sun.COM } 2684*10491SRishi.Srivatsavai@Sun.COM 2685*10491SRishi.Srivatsavai@Sun.COM /* 2686*10491SRishi.Srivatsavai@Sun.COM * Let the mac module take or drop a reference to a bridge link. When this is 2687*10491SRishi.Srivatsavai@Sun.COM * called, the mac module is holding the mi_bridge_lock, so the link cannot be 2688*10491SRishi.Srivatsavai@Sun.COM * in the process of entering or leaving a bridge. 2689*10491SRishi.Srivatsavai@Sun.COM */ 2690*10491SRishi.Srivatsavai@Sun.COM static void 2691*10491SRishi.Srivatsavai@Sun.COM bridge_ref_cb(mac_handle_t mh, boolean_t hold) 2692*10491SRishi.Srivatsavai@Sun.COM { 2693*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 2694*10491SRishi.Srivatsavai@Sun.COM 2695*10491SRishi.Srivatsavai@Sun.COM if (hold) 2696*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); 2697*10491SRishi.Srivatsavai@Sun.COM else 2698*10491SRishi.Srivatsavai@Sun.COM link_unref(blp); 2699*10491SRishi.Srivatsavai@Sun.COM } 2700*10491SRishi.Srivatsavai@Sun.COM 2701*10491SRishi.Srivatsavai@Sun.COM /* 2702*10491SRishi.Srivatsavai@Sun.COM * Handle link state changes reported by the mac layer. This acts as a filter 2703*10491SRishi.Srivatsavai@Sun.COM * for link state changes: if a link is reporting down, but there are other 2704*10491SRishi.Srivatsavai@Sun.COM * links still up on the bridge, then the state is changed to "up." When the 2705*10491SRishi.Srivatsavai@Sun.COM * last link goes down, all are marked down, and when the first link goes up, 2706*10491SRishi.Srivatsavai@Sun.COM * all are marked up. (Recursion is avoided by the use of the "redo" function.) 2707*10491SRishi.Srivatsavai@Sun.COM * 2708*10491SRishi.Srivatsavai@Sun.COM * We treat unknown as equivalent to "up." 2709*10491SRishi.Srivatsavai@Sun.COM */ 2710*10491SRishi.Srivatsavai@Sun.COM static link_state_t 2711*10491SRishi.Srivatsavai@Sun.COM bridge_ls_cb(mac_handle_t mh, link_state_t newls) 2712*10491SRishi.Srivatsavai@Sun.COM { 2713*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 2714*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blcmp; 2715*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 2716*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 2717*10491SRishi.Srivatsavai@Sun.COM 2718*10491SRishi.Srivatsavai@Sun.COM if (newls != LINK_STATE_DOWN && blp->bl_linkstate != LINK_STATE_DOWN || 2719*10491SRishi.Srivatsavai@Sun.COM (blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) { 2720*10491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = newls; 2721*10491SRishi.Srivatsavai@Sun.COM return (newls); 2722*10491SRishi.Srivatsavai@Sun.COM } 2723*10491SRishi.Srivatsavai@Sun.COM 2724*10491SRishi.Srivatsavai@Sun.COM /* 2725*10491SRishi.Srivatsavai@Sun.COM * Scan first to see if there are any other non-down links. If there 2726*10491SRishi.Srivatsavai@Sun.COM * are, then we're done. Otherwise, if all others are down, then the 2727*10491SRishi.Srivatsavai@Sun.COM * state of this link is the state of the bridge. 2728*10491SRishi.Srivatsavai@Sun.COM */ 2729*10491SRishi.Srivatsavai@Sun.COM bip = blp->bl_inst; 2730*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 2731*10491SRishi.Srivatsavai@Sun.COM for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 2732*10491SRishi.Srivatsavai@Sun.COM blcmp = list_next(&bip->bi_links, blcmp)) { 2733*10491SRishi.Srivatsavai@Sun.COM if (blcmp != blp && 2734*10491SRishi.Srivatsavai@Sun.COM !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) && 2735*10491SRishi.Srivatsavai@Sun.COM blcmp->bl_linkstate != LINK_STATE_DOWN) 2736*10491SRishi.Srivatsavai@Sun.COM break; 2737*10491SRishi.Srivatsavai@Sun.COM } 2738*10491SRishi.Srivatsavai@Sun.COM 2739*10491SRishi.Srivatsavai@Sun.COM if (blcmp != NULL) { 2740*10491SRishi.Srivatsavai@Sun.COM /* 2741*10491SRishi.Srivatsavai@Sun.COM * If there are other links that are considered up, then tell 2742*10491SRishi.Srivatsavai@Sun.COM * the caller that the link is actually still up, regardless of 2743*10491SRishi.Srivatsavai@Sun.COM * this link's underlying state. 2744*10491SRishi.Srivatsavai@Sun.COM */ 2745*10491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = newls; 2746*10491SRishi.Srivatsavai@Sun.COM newls = LINK_STATE_UP; 2747*10491SRishi.Srivatsavai@Sun.COM } else if (blp->bl_linkstate != newls) { 2748*10491SRishi.Srivatsavai@Sun.COM /* 2749*10491SRishi.Srivatsavai@Sun.COM * If we've found no other 'up' links, and this link has 2750*10491SRishi.Srivatsavai@Sun.COM * changed state, then report the new state of the bridge to 2751*10491SRishi.Srivatsavai@Sun.COM * all other clients. 2752*10491SRishi.Srivatsavai@Sun.COM */ 2753*10491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = newls; 2754*10491SRishi.Srivatsavai@Sun.COM for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 2755*10491SRishi.Srivatsavai@Sun.COM blcmp = list_next(&bip->bi_links, blcmp)) { 2756*10491SRishi.Srivatsavai@Sun.COM if (blcmp != blp && !(blcmp->bl_flags & BLF_DELETED)) 2757*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(blcmp->bl_mh, newls); 2758*10491SRishi.Srivatsavai@Sun.COM } 2759*10491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 2760*10491SRishi.Srivatsavai@Sun.COM if ((bmp->bm_linkstate = newls) != LINK_STATE_DOWN) 2761*10491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = LINK_STATE_UP; 2762*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, bmp->bm_linkstate); 2763*10491SRishi.Srivatsavai@Sun.COM } 2764*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 2765*10491SRishi.Srivatsavai@Sun.COM return (newls); 2766*10491SRishi.Srivatsavai@Sun.COM } 2767*10491SRishi.Srivatsavai@Sun.COM 2768*10491SRishi.Srivatsavai@Sun.COM static void 2769*10491SRishi.Srivatsavai@Sun.COM bridge_add_link(void *arg) 2770*10491SRishi.Srivatsavai@Sun.COM { 2771*10491SRishi.Srivatsavai@Sun.COM mblk_t *mp = arg; 2772*10491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 2773*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip, *bipt; 2774*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 2775*10491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid; 2776*10491SRishi.Srivatsavai@Sun.COM int err; 2777*10491SRishi.Srivatsavai@Sun.COM mac_handle_t mh; 2778*10491SRishi.Srivatsavai@Sun.COM uint_t maxsdu; 2779*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = NULL, *blpt; 2780*10491SRishi.Srivatsavai@Sun.COM const mac_info_t *mip; 2781*10491SRishi.Srivatsavai@Sun.COM boolean_t macopen = B_FALSE; 2782*10491SRishi.Srivatsavai@Sun.COM char linkname[MAXLINKNAMELEN]; 2783*10491SRishi.Srivatsavai@Sun.COM char kstatname[KSTAT_STRLEN]; 2784*10491SRishi.Srivatsavai@Sun.COM int i; 2785*10491SRishi.Srivatsavai@Sun.COM link_state_t linkstate; 2786*10491SRishi.Srivatsavai@Sun.COM mblk_t *mlist; 2787*10491SRishi.Srivatsavai@Sun.COM 2788*10491SRishi.Srivatsavai@Sun.COM bsp = (bridge_stream_t *)mp->b_next; 2789*10491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 2790*10491SRishi.Srivatsavai@Sun.COM bip = bsp->bs_inst; 2791*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 2792*10491SRishi.Srivatsavai@Sun.COM linkid = *(datalink_id_t *)mp->b_cont->b_rptr; 2793*10491SRishi.Srivatsavai@Sun.COM 2794*10491SRishi.Srivatsavai@Sun.COM /* 2795*10491SRishi.Srivatsavai@Sun.COM * First make sure that there is no other bridge that has this link. 2796*10491SRishi.Srivatsavai@Sun.COM * We don't want to overlap operations from two bridges; the MAC layer 2797*10491SRishi.Srivatsavai@Sun.COM * supports only one bridge on a given MAC at a time. 2798*10491SRishi.Srivatsavai@Sun.COM * 2799*10491SRishi.Srivatsavai@Sun.COM * We rely on the fact that there's just one taskq thread for the 2800*10491SRishi.Srivatsavai@Sun.COM * bridging module: once we've checked for a duplicate, we can drop the 2801*10491SRishi.Srivatsavai@Sun.COM * lock, because no other thread could possibly be adding another link 2802*10491SRishi.Srivatsavai@Sun.COM * until we're done. 2803*10491SRishi.Srivatsavai@Sun.COM */ 2804*10491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 2805*10491SRishi.Srivatsavai@Sun.COM for (bipt = list_head(&inst_list); bipt != NULL; 2806*10491SRishi.Srivatsavai@Sun.COM bipt = list_next(&inst_list, bipt)) { 2807*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bipt->bi_rwlock, RW_READER); 2808*10491SRishi.Srivatsavai@Sun.COM for (blpt = list_head(&bipt->bi_links); blpt != NULL; 2809*10491SRishi.Srivatsavai@Sun.COM blpt = list_next(&bipt->bi_links, blpt)) { 2810*10491SRishi.Srivatsavai@Sun.COM if (linkid == blpt->bl_linkid) 2811*10491SRishi.Srivatsavai@Sun.COM break; 2812*10491SRishi.Srivatsavai@Sun.COM } 2813*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bipt->bi_rwlock); 2814*10491SRishi.Srivatsavai@Sun.COM if (blpt != NULL) 2815*10491SRishi.Srivatsavai@Sun.COM break; 2816*10491SRishi.Srivatsavai@Sun.COM } 2817*10491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 2818*10491SRishi.Srivatsavai@Sun.COM if (bipt != NULL) { 2819*10491SRishi.Srivatsavai@Sun.COM err = EBUSY; 2820*10491SRishi.Srivatsavai@Sun.COM goto fail; 2821*10491SRishi.Srivatsavai@Sun.COM } 2822*10491SRishi.Srivatsavai@Sun.COM 2823*10491SRishi.Srivatsavai@Sun.COM if ((err = mac_open_by_linkid(linkid, &mh)) != 0) 2824*10491SRishi.Srivatsavai@Sun.COM goto fail; 2825*10491SRishi.Srivatsavai@Sun.COM macopen = B_TRUE; 2826*10491SRishi.Srivatsavai@Sun.COM 2827*10491SRishi.Srivatsavai@Sun.COM /* we bridge only Ethernet */ 2828*10491SRishi.Srivatsavai@Sun.COM mip = mac_info(mh); 2829*10491SRishi.Srivatsavai@Sun.COM if (mip->mi_media != DL_ETHER) { 2830*10491SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 2831*10491SRishi.Srivatsavai@Sun.COM goto fail; 2832*10491SRishi.Srivatsavai@Sun.COM } 2833*10491SRishi.Srivatsavai@Sun.COM 2834*10491SRishi.Srivatsavai@Sun.COM /* 2835*10491SRishi.Srivatsavai@Sun.COM * Get the current maximum SDU on this interface. If there are other 2836*10491SRishi.Srivatsavai@Sun.COM * links on the bridge, then this one must match, or it errors out. 2837*10491SRishi.Srivatsavai@Sun.COM * Otherwise, the first link becomes the standard for the new bridge. 2838*10491SRishi.Srivatsavai@Sun.COM */ 2839*10491SRishi.Srivatsavai@Sun.COM mac_sdu_get(mh, NULL, &maxsdu); 2840*10491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 2841*10491SRishi.Srivatsavai@Sun.COM if (list_is_empty(&bip->bi_links)) { 2842*10491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = maxsdu; 2843*10491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 2844*10491SRishi.Srivatsavai@Sun.COM } 2845*10491SRishi.Srivatsavai@Sun.COM 2846*10491SRishi.Srivatsavai@Sun.COM /* figure the kstat name; also used as the mac client name */ 2847*10491SRishi.Srivatsavai@Sun.COM i = MBLKL(mp->b_cont) - sizeof (datalink_id_t); 2848*10491SRishi.Srivatsavai@Sun.COM if (i < 0 || i >= MAXLINKNAMELEN) 2849*10491SRishi.Srivatsavai@Sun.COM i = MAXLINKNAMELEN - 1; 2850*10491SRishi.Srivatsavai@Sun.COM bcopy(mp->b_cont->b_rptr + sizeof (datalink_id_t), linkname, i); 2851*10491SRishi.Srivatsavai@Sun.COM linkname[i] = '\0'; 2852*10491SRishi.Srivatsavai@Sun.COM (void) snprintf(kstatname, sizeof (kstatname), "%s-%s", bip->bi_name, 2853*10491SRishi.Srivatsavai@Sun.COM linkname); 2854*10491SRishi.Srivatsavai@Sun.COM 2855*10491SRishi.Srivatsavai@Sun.COM if ((blp = kmem_zalloc(sizeof (*blp), KM_NOSLEEP)) == NULL) { 2856*10491SRishi.Srivatsavai@Sun.COM err = ENOMEM; 2857*10491SRishi.Srivatsavai@Sun.COM goto fail; 2858*10491SRishi.Srivatsavai@Sun.COM } 2859*10491SRishi.Srivatsavai@Sun.COM blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED); 2860*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_lfailmp == NULL) { 2861*10491SRishi.Srivatsavai@Sun.COM kmem_free(blp, sizeof (*blp)); 2862*10491SRishi.Srivatsavai@Sun.COM err = ENOMEM; 2863*10491SRishi.Srivatsavai@Sun.COM goto fail; 2864*10491SRishi.Srivatsavai@Sun.COM } 2865*10491SRishi.Srivatsavai@Sun.COM 2866*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 2867*10491SRishi.Srivatsavai@Sun.COM blp->bl_inst = bip; 2868*10491SRishi.Srivatsavai@Sun.COM blp->bl_mh = mh; 2869*10491SRishi.Srivatsavai@Sun.COM blp->bl_linkid = linkid; 2870*10491SRishi.Srivatsavai@Sun.COM blp->bl_maxsdu = maxsdu; 2871*10491SRishi.Srivatsavai@Sun.COM cv_init(&blp->bl_trillwait, NULL, CV_DRIVER, NULL); 2872*10491SRishi.Srivatsavai@Sun.COM mutex_init(&blp->bl_trilllock, NULL, MUTEX_DRIVER, NULL); 2873*10491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs)); 2874*10491SRishi.Srivatsavai@Sun.COM 2875*10491SRishi.Srivatsavai@Sun.COM err = mac_client_open(mh, &blp->bl_mch, kstatname, 0); 2876*10491SRishi.Srivatsavai@Sun.COM if (err != 0) 2877*10491SRishi.Srivatsavai@Sun.COM goto fail; 2878*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_CLIENT_OPEN; 2879*10491SRishi.Srivatsavai@Sun.COM 2880*10491SRishi.Srivatsavai@Sun.COM err = mac_margin_add(mh, &blp->bl_margin, B_TRUE); 2881*10491SRishi.Srivatsavai@Sun.COM if (err != 0) 2882*10491SRishi.Srivatsavai@Sun.COM goto fail; 2883*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_MARGIN_ADDED; 2884*10491SRishi.Srivatsavai@Sun.COM 2885*10491SRishi.Srivatsavai@Sun.COM blp->bl_mnh = mac_notify_add(mh, bridge_notify_cb, blp); 2886*10491SRishi.Srivatsavai@Sun.COM 2887*10491SRishi.Srivatsavai@Sun.COM err = mac_bridge_set(mh, (mac_handle_t)blp); 2888*10491SRishi.Srivatsavai@Sun.COM if (err != 0) 2889*10491SRishi.Srivatsavai@Sun.COM goto fail; 2890*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_SET_BRIDGE; 2891*10491SRishi.Srivatsavai@Sun.COM 2892*10491SRishi.Srivatsavai@Sun.COM err = mac_promisc_add(blp->bl_mch, MAC_CLIENT_PROMISC_ALL, NULL, 2893*10491SRishi.Srivatsavai@Sun.COM blp, &blp->bl_mphp, MAC_PROMISC_FLAGS_NO_TX_LOOP); 2894*10491SRishi.Srivatsavai@Sun.COM if (err != 0) 2895*10491SRishi.Srivatsavai@Sun.COM goto fail; 2896*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_PROM_ADDED; 2897*10491SRishi.Srivatsavai@Sun.COM 2898*10491SRishi.Srivatsavai@Sun.COM bridge_new_unicst(blp); 2899*10491SRishi.Srivatsavai@Sun.COM 2900*10491SRishi.Srivatsavai@Sun.COM blp->bl_ksp = kstat_setup((kstat_named_t *)&blp->bl_kstats, 2901*10491SRishi.Srivatsavai@Sun.COM link_kstats_list, Dim(link_kstats_list), kstatname); 2902*10491SRishi.Srivatsavai@Sun.COM 2903*10491SRishi.Srivatsavai@Sun.COM /* 2904*10491SRishi.Srivatsavai@Sun.COM * The link holds a reference to the bridge instance, so that the 2905*10491SRishi.Srivatsavai@Sun.COM * instance can't go away before the link is freed. The insertion into 2906*10491SRishi.Srivatsavai@Sun.COM * bi_links holds a reference on the link. When marking as removed 2907*10491SRishi.Srivatsavai@Sun.COM * from bi_links (BLF_DELETED), drop the reference on the link. When 2908*10491SRishi.Srivatsavai@Sun.COM * freeing the link, drop the reference on the instance. 2909*10491SRishi.Srivatsavai@Sun.COM */ 2910*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 2911*10491SRishi.Srivatsavai@Sun.COM list_insert_tail(&bip->bi_links, blp); 2912*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); 2913*10491SRishi.Srivatsavai@Sun.COM 2914*10491SRishi.Srivatsavai@Sun.COM /* 2915*10491SRishi.Srivatsavai@Sun.COM * If the new link is no good on this bridge, then let the daemon know 2916*10491SRishi.Srivatsavai@Sun.COM * about the problem. 2917*10491SRishi.Srivatsavai@Sun.COM */ 2918*10491SRishi.Srivatsavai@Sun.COM mlist = NULL; 2919*10491SRishi.Srivatsavai@Sun.COM if (maxsdu != bmp->bm_maxsdu) 2920*10491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_TRUE, &mlist); 2921*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 2922*10491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 2923*10491SRishi.Srivatsavai@Sun.COM 2924*10491SRishi.Srivatsavai@Sun.COM /* 2925*10491SRishi.Srivatsavai@Sun.COM * Trigger a link state update so that if this link is the first one 2926*10491SRishi.Srivatsavai@Sun.COM * "up" in the bridge, then we notify everyone. This triggers a trip 2927*10491SRishi.Srivatsavai@Sun.COM * through bridge_ls_cb. 2928*10491SRishi.Srivatsavai@Sun.COM */ 2929*10491SRishi.Srivatsavai@Sun.COM linkstate = mac_stat_get(mh, MAC_STAT_LOWLINK_STATE); 2930*10491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = LINK_STATE_DOWN; 2931*10491SRishi.Srivatsavai@Sun.COM mac_link_update(mh, linkstate); 2932*10491SRishi.Srivatsavai@Sun.COM 2933*10491SRishi.Srivatsavai@Sun.COM /* 2934*10491SRishi.Srivatsavai@Sun.COM * We now need to report back to the stream that invoked us, and then 2935*10491SRishi.Srivatsavai@Sun.COM * drop the reference on the stream that we're holding. 2936*10491SRishi.Srivatsavai@Sun.COM */ 2937*10491SRishi.Srivatsavai@Sun.COM miocack(bsp->bs_wq, mp, 0, 0); 2938*10491SRishi.Srivatsavai@Sun.COM stream_unref(bsp); 2939*10491SRishi.Srivatsavai@Sun.COM return; 2940*10491SRishi.Srivatsavai@Sun.COM 2941*10491SRishi.Srivatsavai@Sun.COM fail: 2942*10491SRishi.Srivatsavai@Sun.COM if (blp == NULL) { 2943*10491SRishi.Srivatsavai@Sun.COM if (macopen) 2944*10491SRishi.Srivatsavai@Sun.COM mac_close(mh); 2945*10491SRishi.Srivatsavai@Sun.COM } else { 2946*10491SRishi.Srivatsavai@Sun.COM link_shutdown(blp); 2947*10491SRishi.Srivatsavai@Sun.COM link_free(blp); 2948*10491SRishi.Srivatsavai@Sun.COM } 2949*10491SRishi.Srivatsavai@Sun.COM miocnak(bsp->bs_wq, mp, 0, err); 2950*10491SRishi.Srivatsavai@Sun.COM stream_unref(bsp); 2951*10491SRishi.Srivatsavai@Sun.COM } 2952*10491SRishi.Srivatsavai@Sun.COM 2953*10491SRishi.Srivatsavai@Sun.COM static void 2954*10491SRishi.Srivatsavai@Sun.COM bridge_rem_link(void *arg) 2955*10491SRishi.Srivatsavai@Sun.COM { 2956*10491SRishi.Srivatsavai@Sun.COM mblk_t *mp = arg; 2957*10491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 2958*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 2959*10491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 2960*10491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid; 2961*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp, *blsave; 2962*10491SRishi.Srivatsavai@Sun.COM boolean_t found; 2963*10491SRishi.Srivatsavai@Sun.COM mblk_t *mlist; 2964*10491SRishi.Srivatsavai@Sun.COM 2965*10491SRishi.Srivatsavai@Sun.COM bsp = (bridge_stream_t *)mp->b_next; 2966*10491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 2967*10491SRishi.Srivatsavai@Sun.COM bip = bsp->bs_inst; 2968*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 2969*10491SRishi.Srivatsavai@Sun.COM linkid = *(datalink_id_t *)mp->b_cont->b_rptr; 2970*10491SRishi.Srivatsavai@Sun.COM 2971*10491SRishi.Srivatsavai@Sun.COM /* 2972*10491SRishi.Srivatsavai@Sun.COM * We become reader here so that we can loop over the other links and 2973*10491SRishi.Srivatsavai@Sun.COM * deliver link up/down notification. 2974*10491SRishi.Srivatsavai@Sun.COM */ 2975*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 2976*10491SRishi.Srivatsavai@Sun.COM found = B_FALSE; 2977*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 2978*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 2979*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkid == linkid && 2980*10491SRishi.Srivatsavai@Sun.COM !(blp->bl_flags & BLF_DELETED)) { 2981*10491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_DELETED; 2982*10491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown, 2983*10491SRishi.Srivatsavai@Sun.COM blp, DDI_SLEEP); 2984*10491SRishi.Srivatsavai@Sun.COM found = B_TRUE; 2985*10491SRishi.Srivatsavai@Sun.COM break; 2986*10491SRishi.Srivatsavai@Sun.COM } 2987*10491SRishi.Srivatsavai@Sun.COM } 2988*10491SRishi.Srivatsavai@Sun.COM 2989*10491SRishi.Srivatsavai@Sun.COM /* 2990*10491SRishi.Srivatsavai@Sun.COM * Check if this link is up and the remainder of the links are all 2991*10491SRishi.Srivatsavai@Sun.COM * down. 2992*10491SRishi.Srivatsavai@Sun.COM */ 2993*10491SRishi.Srivatsavai@Sun.COM if (blp != NULL && blp->bl_linkstate != LINK_STATE_DOWN) { 2994*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 2995*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 2996*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkstate != LINK_STATE_DOWN && 2997*10491SRishi.Srivatsavai@Sun.COM !(blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) 2998*10491SRishi.Srivatsavai@Sun.COM break; 2999*10491SRishi.Srivatsavai@Sun.COM } 3000*10491SRishi.Srivatsavai@Sun.COM if (blp == NULL) { 3001*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 3002*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 3003*10491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED)) 3004*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, 3005*10491SRishi.Srivatsavai@Sun.COM LINK_STATE_DOWN); 3006*10491SRishi.Srivatsavai@Sun.COM } 3007*10491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 3008*10491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = LINK_STATE_DOWN; 3009*10491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN); 3010*10491SRishi.Srivatsavai@Sun.COM } 3011*10491SRishi.Srivatsavai@Sun.COM } 3012*10491SRishi.Srivatsavai@Sun.COM 3013*10491SRishi.Srivatsavai@Sun.COM /* 3014*10491SRishi.Srivatsavai@Sun.COM * Check if there's just one working link left on the bridge. If so, 3015*10491SRishi.Srivatsavai@Sun.COM * then that link is now authoritative for bridge MTU. 3016*10491SRishi.Srivatsavai@Sun.COM */ 3017*10491SRishi.Srivatsavai@Sun.COM blsave = NULL; 3018*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 3019*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 3020*10491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED)) { 3021*10491SRishi.Srivatsavai@Sun.COM if (blsave == NULL) 3022*10491SRishi.Srivatsavai@Sun.COM blsave = blp; 3023*10491SRishi.Srivatsavai@Sun.COM else 3024*10491SRishi.Srivatsavai@Sun.COM break; 3025*10491SRishi.Srivatsavai@Sun.COM } 3026*10491SRishi.Srivatsavai@Sun.COM } 3027*10491SRishi.Srivatsavai@Sun.COM mlist = NULL; 3028*10491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 3029*10491SRishi.Srivatsavai@Sun.COM if (blsave != NULL && blp == NULL && 3030*10491SRishi.Srivatsavai@Sun.COM blsave->bl_maxsdu != bmp->bm_maxsdu) { 3031*10491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = blsave->bl_maxsdu; 3032*10491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, blsave->bl_maxsdu); 3033*10491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blsave, B_FALSE, &mlist); 3034*10491SRishi.Srivatsavai@Sun.COM } 3035*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3036*10491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 3037*10491SRishi.Srivatsavai@Sun.COM 3038*10491SRishi.Srivatsavai@Sun.COM if (found) 3039*10491SRishi.Srivatsavai@Sun.COM miocack(bsp->bs_wq, mp, 0, 0); 3040*10491SRishi.Srivatsavai@Sun.COM else 3041*10491SRishi.Srivatsavai@Sun.COM miocnak(bsp->bs_wq, mp, 0, ENOENT); 3042*10491SRishi.Srivatsavai@Sun.COM stream_unref(bsp); 3043*10491SRishi.Srivatsavai@Sun.COM } 3044*10491SRishi.Srivatsavai@Sun.COM 3045*10491SRishi.Srivatsavai@Sun.COM /* 3046*10491SRishi.Srivatsavai@Sun.COM * This function intentionally returns with bi_rwlock held; it is intended for 3047*10491SRishi.Srivatsavai@Sun.COM * quick checks and updates. 3048*10491SRishi.Srivatsavai@Sun.COM */ 3049*10491SRishi.Srivatsavai@Sun.COM static bridge_link_t * 3050*10491SRishi.Srivatsavai@Sun.COM enter_link(bridge_inst_t *bip, datalink_id_t linkid) 3051*10491SRishi.Srivatsavai@Sun.COM { 3052*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 3053*10491SRishi.Srivatsavai@Sun.COM 3054*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 3055*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 3056*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 3057*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkid == linkid && !(blp->bl_flags & BLF_DELETED)) 3058*10491SRishi.Srivatsavai@Sun.COM break; 3059*10491SRishi.Srivatsavai@Sun.COM } 3060*10491SRishi.Srivatsavai@Sun.COM return (blp); 3061*10491SRishi.Srivatsavai@Sun.COM } 3062*10491SRishi.Srivatsavai@Sun.COM 3063*10491SRishi.Srivatsavai@Sun.COM static void 3064*10491SRishi.Srivatsavai@Sun.COM bridge_ioctl(queue_t *wq, mblk_t *mp) 3065*10491SRishi.Srivatsavai@Sun.COM { 3066*10491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp = wq->q_ptr; 3067*10491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 3068*10491SRishi.Srivatsavai@Sun.COM struct iocblk *iop; 3069*10491SRishi.Srivatsavai@Sun.COM int rc = EINVAL; 3070*10491SRishi.Srivatsavai@Sun.COM int len = 0; 3071*10491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 3072*10491SRishi.Srivatsavai@Sun.COM cred_t *cr; 3073*10491SRishi.Srivatsavai@Sun.COM 3074*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3075*10491SRishi.Srivatsavai@Sun.COM iop = (struct iocblk *)mp->b_rptr; 3076*10491SRishi.Srivatsavai@Sun.COM 3077*10491SRishi.Srivatsavai@Sun.COM /* 3078*10491SRishi.Srivatsavai@Sun.COM * For now, all of the bridge ioctls are privileged. 3079*10491SRishi.Srivatsavai@Sun.COM */ 3080*10491SRishi.Srivatsavai@Sun.COM if ((cr = msg_getcred(mp, NULL)) == NULL) 3081*10491SRishi.Srivatsavai@Sun.COM cr = iop->ioc_cr; 3082*10491SRishi.Srivatsavai@Sun.COM if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0) { 3083*10491SRishi.Srivatsavai@Sun.COM miocnak(wq, mp, 0, EPERM); 3084*10491SRishi.Srivatsavai@Sun.COM return; 3085*10491SRishi.Srivatsavai@Sun.COM } 3086*10491SRishi.Srivatsavai@Sun.COM 3087*10491SRishi.Srivatsavai@Sun.COM switch (iop->ioc_cmd) { 3088*10491SRishi.Srivatsavai@Sun.COM case BRIOC_NEWBRIDGE: { 3089*10491SRishi.Srivatsavai@Sun.COM bridge_newbridge_t *bnb; 3090*10491SRishi.Srivatsavai@Sun.COM 3091*10491SRishi.Srivatsavai@Sun.COM if (bsp->bs_inst != NULL || 3092*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (bridge_newbridge_t))) != 0) 3093*10491SRishi.Srivatsavai@Sun.COM break; 3094*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3095*10491SRishi.Srivatsavai@Sun.COM bnb = (bridge_newbridge_t *)mp->b_cont->b_rptr; 3096*10491SRishi.Srivatsavai@Sun.COM bnb->bnb_name[MAXNAMELEN-1] = '\0'; 3097*10491SRishi.Srivatsavai@Sun.COM if ((rc = bridge_create(bnb->bnb_linkid, 3098*10491SRishi.Srivatsavai@Sun.COM bnb->bnb_name, &bip)) != 0) 3099*10491SRishi.Srivatsavai@Sun.COM break; 3100*10491SRishi.Srivatsavai@Sun.COM 3101*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 3102*10491SRishi.Srivatsavai@Sun.COM if (bip->bi_control != NULL) { 3103*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3104*10491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 3105*10491SRishi.Srivatsavai@Sun.COM rc = EBUSY; 3106*10491SRishi.Srivatsavai@Sun.COM } else { 3107*10491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 3108*10491SRishi.Srivatsavai@Sun.COM bsp->bs_inst = bip; /* stream holds reference */ 3109*10491SRishi.Srivatsavai@Sun.COM bip->bi_control = bsp; 3110*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3111*10491SRishi.Srivatsavai@Sun.COM rc = 0; 3112*10491SRishi.Srivatsavai@Sun.COM } 3113*10491SRishi.Srivatsavai@Sun.COM break; 3114*10491SRishi.Srivatsavai@Sun.COM } 3115*10491SRishi.Srivatsavai@Sun.COM 3116*10491SRishi.Srivatsavai@Sun.COM case BRIOC_ADDLINK: 3117*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3118*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0) 3119*10491SRishi.Srivatsavai@Sun.COM break; 3120*10491SRishi.Srivatsavai@Sun.COM /* 3121*10491SRishi.Srivatsavai@Sun.COM * We cannot perform the action in this thread, because we're 3122*10491SRishi.Srivatsavai@Sun.COM * not in process context, and we may already be holding 3123*10491SRishi.Srivatsavai@Sun.COM * MAC-related locks. Place the request on taskq. 3124*10491SRishi.Srivatsavai@Sun.COM */ 3125*10491SRishi.Srivatsavai@Sun.COM mp->b_next = (mblk_t *)bsp; 3126*10491SRishi.Srivatsavai@Sun.COM stream_ref(bsp); 3127*10491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, bridge_add_link, mp, 3128*10491SRishi.Srivatsavai@Sun.COM DDI_SLEEP); 3129*10491SRishi.Srivatsavai@Sun.COM return; 3130*10491SRishi.Srivatsavai@Sun.COM 3131*10491SRishi.Srivatsavai@Sun.COM case BRIOC_REMLINK: 3132*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3133*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0) 3134*10491SRishi.Srivatsavai@Sun.COM break; 3135*10491SRishi.Srivatsavai@Sun.COM /* 3136*10491SRishi.Srivatsavai@Sun.COM * We cannot perform the action in this thread, because we're 3137*10491SRishi.Srivatsavai@Sun.COM * not in process context, and we may already be holding 3138*10491SRishi.Srivatsavai@Sun.COM * MAC-related locks. Place the request on taskq. 3139*10491SRishi.Srivatsavai@Sun.COM */ 3140*10491SRishi.Srivatsavai@Sun.COM mp->b_next = (mblk_t *)bsp; 3141*10491SRishi.Srivatsavai@Sun.COM stream_ref(bsp); 3142*10491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, bridge_rem_link, mp, 3143*10491SRishi.Srivatsavai@Sun.COM DDI_SLEEP); 3144*10491SRishi.Srivatsavai@Sun.COM return; 3145*10491SRishi.Srivatsavai@Sun.COM 3146*10491SRishi.Srivatsavai@Sun.COM case BRIOC_SETSTATE: { 3147*10491SRishi.Srivatsavai@Sun.COM bridge_setstate_t *bss; 3148*10491SRishi.Srivatsavai@Sun.COM 3149*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3150*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bss))) != 0) 3151*10491SRishi.Srivatsavai@Sun.COM break; 3152*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3153*10491SRishi.Srivatsavai@Sun.COM bss = (bridge_setstate_t *)mp->b_cont->b_rptr; 3154*10491SRishi.Srivatsavai@Sun.COM if ((blp = enter_link(bip, bss->bss_linkid)) == NULL) { 3155*10491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 3156*10491SRishi.Srivatsavai@Sun.COM } else { 3157*10491SRishi.Srivatsavai@Sun.COM rc = 0; 3158*10491SRishi.Srivatsavai@Sun.COM blp->bl_state = bss->bss_state; 3159*10491SRishi.Srivatsavai@Sun.COM } 3160*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3161*10491SRishi.Srivatsavai@Sun.COM break; 3162*10491SRishi.Srivatsavai@Sun.COM } 3163*10491SRishi.Srivatsavai@Sun.COM 3164*10491SRishi.Srivatsavai@Sun.COM case BRIOC_SETPVID: { 3165*10491SRishi.Srivatsavai@Sun.COM bridge_setpvid_t *bsv; 3166*10491SRishi.Srivatsavai@Sun.COM 3167*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3168*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bsv))) != 0) 3169*10491SRishi.Srivatsavai@Sun.COM break; 3170*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3171*10491SRishi.Srivatsavai@Sun.COM bsv = (bridge_setpvid_t *)mp->b_cont->b_rptr; 3172*10491SRishi.Srivatsavai@Sun.COM if (bsv->bsv_vlan > VLAN_ID_MAX) 3173*10491SRishi.Srivatsavai@Sun.COM break; 3174*10491SRishi.Srivatsavai@Sun.COM if ((blp = enter_link(bip, bsv->bsv_linkid)) == NULL) { 3175*10491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 3176*10491SRishi.Srivatsavai@Sun.COM } else if (blp->bl_pvid == bsv->bsv_vlan) { 3177*10491SRishi.Srivatsavai@Sun.COM rc = 0; 3178*10491SRishi.Srivatsavai@Sun.COM } else { 3179*10491SRishi.Srivatsavai@Sun.COM rc = 0; 3180*10491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_CLR(blp, blp->bl_pvid); 3181*10491SRishi.Srivatsavai@Sun.COM blp->bl_pvid = bsv->bsv_vlan; 3182*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_pvid != 0) 3183*10491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_SET(blp, blp->bl_pvid); 3184*10491SRishi.Srivatsavai@Sun.COM } 3185*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3186*10491SRishi.Srivatsavai@Sun.COM break; 3187*10491SRishi.Srivatsavai@Sun.COM } 3188*10491SRishi.Srivatsavai@Sun.COM 3189*10491SRishi.Srivatsavai@Sun.COM case BRIOC_VLANENAB: { 3190*10491SRishi.Srivatsavai@Sun.COM bridge_vlanenab_t *bve; 3191*10491SRishi.Srivatsavai@Sun.COM 3192*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3193*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bve))) != 0) 3194*10491SRishi.Srivatsavai@Sun.COM break; 3195*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3196*10491SRishi.Srivatsavai@Sun.COM bve = (bridge_vlanenab_t *)mp->b_cont->b_rptr; 3197*10491SRishi.Srivatsavai@Sun.COM if (bve->bve_vlan > VLAN_ID_MAX) 3198*10491SRishi.Srivatsavai@Sun.COM break; 3199*10491SRishi.Srivatsavai@Sun.COM if ((blp = enter_link(bip, bve->bve_linkid)) == NULL) { 3200*10491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 3201*10491SRishi.Srivatsavai@Sun.COM } else { 3202*10491SRishi.Srivatsavai@Sun.COM rc = 0; 3203*10491SRishi.Srivatsavai@Sun.COM /* special case: vlan 0 means "all" */ 3204*10491SRishi.Srivatsavai@Sun.COM if (bve->bve_vlan == 0) { 3205*10491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_vlans, 3206*10491SRishi.Srivatsavai@Sun.COM bve->bve_onoff ? ~0 : 0, 3207*10491SRishi.Srivatsavai@Sun.COM sizeof (blp->bl_vlans)); 3208*10491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_CLR(blp, 0); 3209*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_pvid != 0) 3210*10491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_SET(blp, blp->bl_pvid); 3211*10491SRishi.Srivatsavai@Sun.COM } else if (bve->bve_vlan == blp->bl_pvid) { 3212*10491SRishi.Srivatsavai@Sun.COM rc = EINVAL; 3213*10491SRishi.Srivatsavai@Sun.COM } else if (bve->bve_onoff) { 3214*10491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_SET(blp, bve->bve_vlan); 3215*10491SRishi.Srivatsavai@Sun.COM } else { 3216*10491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_CLR(blp, bve->bve_vlan); 3217*10491SRishi.Srivatsavai@Sun.COM } 3218*10491SRishi.Srivatsavai@Sun.COM } 3219*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3220*10491SRishi.Srivatsavai@Sun.COM break; 3221*10491SRishi.Srivatsavai@Sun.COM } 3222*10491SRishi.Srivatsavai@Sun.COM 3223*10491SRishi.Srivatsavai@Sun.COM case BRIOC_FLUSHFWD: { 3224*10491SRishi.Srivatsavai@Sun.COM bridge_flushfwd_t *bff; 3225*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 3226*10491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 3227*10491SRishi.Srivatsavai@Sun.COM int i; 3228*10491SRishi.Srivatsavai@Sun.COM 3229*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3230*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bff))) != 0) 3231*10491SRishi.Srivatsavai@Sun.COM break; 3232*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3233*10491SRishi.Srivatsavai@Sun.COM bff = (bridge_flushfwd_t *)mp->b_cont->b_rptr; 3234*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 3235*10491SRishi.Srivatsavai@Sun.COM /* This case means "all" */ 3236*10491SRishi.Srivatsavai@Sun.COM if (bff->bff_linkid == DATALINK_INVALID_LINKID) { 3237*10491SRishi.Srivatsavai@Sun.COM blp = NULL; 3238*10491SRishi.Srivatsavai@Sun.COM } else { 3239*10491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 3240*10491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 3241*10491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkid == bff->bff_linkid && 3242*10491SRishi.Srivatsavai@Sun.COM !(blp->bl_flags & BLF_DELETED)) 3243*10491SRishi.Srivatsavai@Sun.COM break; 3244*10491SRishi.Srivatsavai@Sun.COM } 3245*10491SRishi.Srivatsavai@Sun.COM if (blp == NULL) { 3246*10491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 3247*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3248*10491SRishi.Srivatsavai@Sun.COM break; 3249*10491SRishi.Srivatsavai@Sun.COM } 3250*10491SRishi.Srivatsavai@Sun.COM } 3251*10491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 3252*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 3253*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 3254*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 3255*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 3256*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) 3257*10491SRishi.Srivatsavai@Sun.COM continue; 3258*10491SRishi.Srivatsavai@Sun.COM if (blp != NULL) { 3259*10491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_maxlinks; i++) { 3260*10491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) 3261*10491SRishi.Srivatsavai@Sun.COM break; 3262*10491SRishi.Srivatsavai@Sun.COM } 3263*10491SRishi.Srivatsavai@Sun.COM /* 3264*10491SRishi.Srivatsavai@Sun.COM * If the link is there and we're excluding, 3265*10491SRishi.Srivatsavai@Sun.COM * then skip. If the link is not there and 3266*10491SRishi.Srivatsavai@Sun.COM * we're doing only that link, then skip. 3267*10491SRishi.Srivatsavai@Sun.COM */ 3268*10491SRishi.Srivatsavai@Sun.COM if ((i < bfp->bf_maxlinks) == bff->bff_exclude) 3269*10491SRishi.Srivatsavai@Sun.COM continue; 3270*10491SRishi.Srivatsavai@Sun.COM } 3271*10491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 3272*10491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 3273*10491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 3274*10491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 3275*10491SRishi.Srivatsavai@Sun.COM } 3276*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 3277*10491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 3278*10491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 3279*10491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 3280*10491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 3281*10491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* drop tree reference */ 3282*10491SRishi.Srivatsavai@Sun.COM } 3283*10491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 3284*10491SRishi.Srivatsavai@Sun.COM break; 3285*10491SRishi.Srivatsavai@Sun.COM } 3286*10491SRishi.Srivatsavai@Sun.COM 3287*10491SRishi.Srivatsavai@Sun.COM case BRIOC_TABLEMAX: 3288*10491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 3289*10491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (uint32_t))) != 0) 3290*10491SRishi.Srivatsavai@Sun.COM break; 3291*10491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 3292*10491SRishi.Srivatsavai@Sun.COM bip->bi_tablemax = *(uint32_t *)mp->b_cont->b_rptr; 3293*10491SRishi.Srivatsavai@Sun.COM break; 3294*10491SRishi.Srivatsavai@Sun.COM } 3295*10491SRishi.Srivatsavai@Sun.COM 3296*10491SRishi.Srivatsavai@Sun.COM if (rc == 0) 3297*10491SRishi.Srivatsavai@Sun.COM miocack(wq, mp, len, 0); 3298*10491SRishi.Srivatsavai@Sun.COM else 3299*10491SRishi.Srivatsavai@Sun.COM miocnak(wq, mp, 0, rc); 3300*10491SRishi.Srivatsavai@Sun.COM } 3301*10491SRishi.Srivatsavai@Sun.COM 3302*10491SRishi.Srivatsavai@Sun.COM static void 3303*10491SRishi.Srivatsavai@Sun.COM bridge_wput(queue_t *wq, mblk_t *mp) 3304*10491SRishi.Srivatsavai@Sun.COM { 3305*10491SRishi.Srivatsavai@Sun.COM switch (DB_TYPE(mp)) { 3306*10491SRishi.Srivatsavai@Sun.COM case M_IOCTL: 3307*10491SRishi.Srivatsavai@Sun.COM bridge_ioctl(wq, mp); 3308*10491SRishi.Srivatsavai@Sun.COM break; 3309*10491SRishi.Srivatsavai@Sun.COM case M_FLUSH: 3310*10491SRishi.Srivatsavai@Sun.COM if (*mp->b_rptr & FLUSHW) 3311*10491SRishi.Srivatsavai@Sun.COM *mp->b_rptr &= ~FLUSHW; 3312*10491SRishi.Srivatsavai@Sun.COM if (*mp->b_rptr & FLUSHR) 3313*10491SRishi.Srivatsavai@Sun.COM qreply(wq, mp); 3314*10491SRishi.Srivatsavai@Sun.COM else 3315*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 3316*10491SRishi.Srivatsavai@Sun.COM break; 3317*10491SRishi.Srivatsavai@Sun.COM default: 3318*10491SRishi.Srivatsavai@Sun.COM freemsg(mp); 3319*10491SRishi.Srivatsavai@Sun.COM break; 3320*10491SRishi.Srivatsavai@Sun.COM } 3321*10491SRishi.Srivatsavai@Sun.COM } 3322*10491SRishi.Srivatsavai@Sun.COM 3323*10491SRishi.Srivatsavai@Sun.COM /* 3324*10491SRishi.Srivatsavai@Sun.COM * This function allocates the main data structures for the bridge driver and 3325*10491SRishi.Srivatsavai@Sun.COM * connects us into devfs. 3326*10491SRishi.Srivatsavai@Sun.COM */ 3327*10491SRishi.Srivatsavai@Sun.COM static void 3328*10491SRishi.Srivatsavai@Sun.COM bridge_inst_init(void) 3329*10491SRishi.Srivatsavai@Sun.COM { 3330*10491SRishi.Srivatsavai@Sun.COM bridge_scan_interval = 5 * drv_usectohz(1000000); 3331*10491SRishi.Srivatsavai@Sun.COM bridge_fwd_age = 25 * drv_usectohz(1000000); 3332*10491SRishi.Srivatsavai@Sun.COM 3333*10491SRishi.Srivatsavai@Sun.COM rw_init(&bmac_rwlock, NULL, RW_DRIVER, NULL); 3334*10491SRishi.Srivatsavai@Sun.COM list_create(&bmac_list, sizeof (bridge_mac_t), 3335*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_mac_t, bm_node)); 3336*10491SRishi.Srivatsavai@Sun.COM list_create(&inst_list, sizeof (bridge_inst_t), 3337*10491SRishi.Srivatsavai@Sun.COM offsetof(bridge_inst_t, bi_node)); 3338*10491SRishi.Srivatsavai@Sun.COM cv_init(&inst_cv, NULL, CV_DRIVER, NULL); 3339*10491SRishi.Srivatsavai@Sun.COM mutex_init(&inst_lock, NULL, MUTEX_DRIVER, NULL); 3340*10491SRishi.Srivatsavai@Sun.COM cv_init(&stream_ref_cv, NULL, CV_DRIVER, NULL); 3341*10491SRishi.Srivatsavai@Sun.COM mutex_init(&stream_ref_lock, NULL, MUTEX_DRIVER, NULL); 3342*10491SRishi.Srivatsavai@Sun.COM 3343*10491SRishi.Srivatsavai@Sun.COM mac_bridge_vectors(bridge_xmit_cb, bridge_recv_cb, bridge_ref_cb, 3344*10491SRishi.Srivatsavai@Sun.COM bridge_ls_cb); 3345*10491SRishi.Srivatsavai@Sun.COM } 3346*10491SRishi.Srivatsavai@Sun.COM 3347*10491SRishi.Srivatsavai@Sun.COM /* 3348*10491SRishi.Srivatsavai@Sun.COM * This function disconnects from devfs and destroys all data structures in 3349*10491SRishi.Srivatsavai@Sun.COM * preparation for unload. It's assumed that there are no active bridge 3350*10491SRishi.Srivatsavai@Sun.COM * references left at this point. 3351*10491SRishi.Srivatsavai@Sun.COM */ 3352*10491SRishi.Srivatsavai@Sun.COM static void 3353*10491SRishi.Srivatsavai@Sun.COM bridge_inst_fini(void) 3354*10491SRishi.Srivatsavai@Sun.COM { 3355*10491SRishi.Srivatsavai@Sun.COM mac_bridge_vectors(NULL, NULL, NULL, NULL); 3356*10491SRishi.Srivatsavai@Sun.COM if (bridge_timerid != 0) 3357*10491SRishi.Srivatsavai@Sun.COM (void) untimeout(bridge_timerid); 3358*10491SRishi.Srivatsavai@Sun.COM rw_destroy(&bmac_rwlock); 3359*10491SRishi.Srivatsavai@Sun.COM list_destroy(&bmac_list); 3360*10491SRishi.Srivatsavai@Sun.COM list_destroy(&inst_list); 3361*10491SRishi.Srivatsavai@Sun.COM cv_destroy(&inst_cv); 3362*10491SRishi.Srivatsavai@Sun.COM mutex_destroy(&inst_lock); 3363*10491SRishi.Srivatsavai@Sun.COM cv_destroy(&stream_ref_cv); 3364*10491SRishi.Srivatsavai@Sun.COM mutex_destroy(&stream_ref_lock); 3365*10491SRishi.Srivatsavai@Sun.COM } 3366*10491SRishi.Srivatsavai@Sun.COM 3367*10491SRishi.Srivatsavai@Sun.COM /* 3368*10491SRishi.Srivatsavai@Sun.COM * bridge_attach() 3369*10491SRishi.Srivatsavai@Sun.COM * 3370*10491SRishi.Srivatsavai@Sun.COM * Description: 3371*10491SRishi.Srivatsavai@Sun.COM * Attach bridge driver to the system. 3372*10491SRishi.Srivatsavai@Sun.COM */ 3373*10491SRishi.Srivatsavai@Sun.COM static int 3374*10491SRishi.Srivatsavai@Sun.COM bridge_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3375*10491SRishi.Srivatsavai@Sun.COM { 3376*10491SRishi.Srivatsavai@Sun.COM if (cmd != DDI_ATTACH) 3377*10491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 3378*10491SRishi.Srivatsavai@Sun.COM 3379*10491SRishi.Srivatsavai@Sun.COM if (ddi_create_minor_node(dip, BRIDGE_CTL, S_IFCHR, 0, DDI_PSEUDO, 3380*10491SRishi.Srivatsavai@Sun.COM CLONE_DEV) == DDI_FAILURE) { 3381*10491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 3382*10491SRishi.Srivatsavai@Sun.COM } 3383*10491SRishi.Srivatsavai@Sun.COM 3384*10491SRishi.Srivatsavai@Sun.COM if (dld_ioc_register(BRIDGE_IOC, bridge_ioc_list, 3385*10491SRishi.Srivatsavai@Sun.COM DLDIOCCNT(bridge_ioc_list)) != 0) { 3386*10491SRishi.Srivatsavai@Sun.COM ddi_remove_minor_node(dip, BRIDGE_CTL); 3387*10491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 3388*10491SRishi.Srivatsavai@Sun.COM } 3389*10491SRishi.Srivatsavai@Sun.COM 3390*10491SRishi.Srivatsavai@Sun.COM bridge_dev_info = dip; 3391*10491SRishi.Srivatsavai@Sun.COM bridge_major = ddi_driver_major(dip); 3392*10491SRishi.Srivatsavai@Sun.COM bridge_taskq = ddi_taskq_create(dip, "bridge", 1, TASKQ_DEFAULTPRI, 0); 3393*10491SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 3394*10491SRishi.Srivatsavai@Sun.COM } 3395*10491SRishi.Srivatsavai@Sun.COM 3396*10491SRishi.Srivatsavai@Sun.COM /* 3397*10491SRishi.Srivatsavai@Sun.COM * bridge_detach() 3398*10491SRishi.Srivatsavai@Sun.COM * 3399*10491SRishi.Srivatsavai@Sun.COM * Description: 3400*10491SRishi.Srivatsavai@Sun.COM * Detach an interface to the system. 3401*10491SRishi.Srivatsavai@Sun.COM */ 3402*10491SRishi.Srivatsavai@Sun.COM static int 3403*10491SRishi.Srivatsavai@Sun.COM bridge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3404*10491SRishi.Srivatsavai@Sun.COM { 3405*10491SRishi.Srivatsavai@Sun.COM if (cmd != DDI_DETACH) 3406*10491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 3407*10491SRishi.Srivatsavai@Sun.COM 3408*10491SRishi.Srivatsavai@Sun.COM ddi_remove_minor_node(dip, NULL); 3409*10491SRishi.Srivatsavai@Sun.COM ddi_taskq_destroy(bridge_taskq); 3410*10491SRishi.Srivatsavai@Sun.COM bridge_dev_info = NULL; 3411*10491SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 3412*10491SRishi.Srivatsavai@Sun.COM } 3413*10491SRishi.Srivatsavai@Sun.COM 3414*10491SRishi.Srivatsavai@Sun.COM /* 3415*10491SRishi.Srivatsavai@Sun.COM * bridge_info() 3416*10491SRishi.Srivatsavai@Sun.COM * 3417*10491SRishi.Srivatsavai@Sun.COM * Description: 3418*10491SRishi.Srivatsavai@Sun.COM * Translate "dev_t" to a pointer to the associated "dev_info_t". 3419*10491SRishi.Srivatsavai@Sun.COM */ 3420*10491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 3421*10491SRishi.Srivatsavai@Sun.COM static int 3422*10491SRishi.Srivatsavai@Sun.COM bridge_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 3423*10491SRishi.Srivatsavai@Sun.COM void **result) 3424*10491SRishi.Srivatsavai@Sun.COM { 3425*10491SRishi.Srivatsavai@Sun.COM int rc; 3426*10491SRishi.Srivatsavai@Sun.COM 3427*10491SRishi.Srivatsavai@Sun.COM switch (infocmd) { 3428*10491SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2DEVINFO: 3429*10491SRishi.Srivatsavai@Sun.COM if (bridge_dev_info == NULL) { 3430*10491SRishi.Srivatsavai@Sun.COM rc = DDI_FAILURE; 3431*10491SRishi.Srivatsavai@Sun.COM } else { 3432*10491SRishi.Srivatsavai@Sun.COM *result = (void *)bridge_dev_info; 3433*10491SRishi.Srivatsavai@Sun.COM rc = DDI_SUCCESS; 3434*10491SRishi.Srivatsavai@Sun.COM } 3435*10491SRishi.Srivatsavai@Sun.COM break; 3436*10491SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2INSTANCE: 3437*10491SRishi.Srivatsavai@Sun.COM *result = NULL; 3438*10491SRishi.Srivatsavai@Sun.COM rc = DDI_SUCCESS; 3439*10491SRishi.Srivatsavai@Sun.COM break; 3440*10491SRishi.Srivatsavai@Sun.COM default: 3441*10491SRishi.Srivatsavai@Sun.COM rc = DDI_FAILURE; 3442*10491SRishi.Srivatsavai@Sun.COM break; 3443*10491SRishi.Srivatsavai@Sun.COM } 3444*10491SRishi.Srivatsavai@Sun.COM return (rc); 3445*10491SRishi.Srivatsavai@Sun.COM } 3446*10491SRishi.Srivatsavai@Sun.COM 3447*10491SRishi.Srivatsavai@Sun.COM static struct module_info bridge_modinfo = { 3448*10491SRishi.Srivatsavai@Sun.COM 2105, /* mi_idnum */ 3449*10491SRishi.Srivatsavai@Sun.COM "bridge", /* mi_idname */ 3450*10491SRishi.Srivatsavai@Sun.COM 0, /* mi_minpsz */ 3451*10491SRishi.Srivatsavai@Sun.COM 16384, /* mi_maxpsz */ 3452*10491SRishi.Srivatsavai@Sun.COM 65536, /* mi_hiwat */ 3453*10491SRishi.Srivatsavai@Sun.COM 128 /* mi_lowat */ 3454*10491SRishi.Srivatsavai@Sun.COM }; 3455*10491SRishi.Srivatsavai@Sun.COM 3456*10491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_rinit = { 3457*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_putp */ 3458*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_srvp */ 3459*10491SRishi.Srivatsavai@Sun.COM bridge_open, /* qi_qopen */ 3460*10491SRishi.Srivatsavai@Sun.COM bridge_close, /* qi_qclose */ 3461*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 3462*10491SRishi.Srivatsavai@Sun.COM &bridge_modinfo, /* qi_minfo */ 3463*10491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 3464*10491SRishi.Srivatsavai@Sun.COM }; 3465*10491SRishi.Srivatsavai@Sun.COM 3466*10491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_winit = { 3467*10491SRishi.Srivatsavai@Sun.COM (int (*)())bridge_wput, /* qi_putp */ 3468*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_srvp */ 3469*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qopen */ 3470*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qclose */ 3471*10491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 3472*10491SRishi.Srivatsavai@Sun.COM &bridge_modinfo, /* qi_minfo */ 3473*10491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 3474*10491SRishi.Srivatsavai@Sun.COM }; 3475*10491SRishi.Srivatsavai@Sun.COM 3476*10491SRishi.Srivatsavai@Sun.COM static struct streamtab bridge_tab = { 3477*10491SRishi.Srivatsavai@Sun.COM &bridge_rinit, /* st_rdinit */ 3478*10491SRishi.Srivatsavai@Sun.COM &bridge_winit /* st_wrinit */ 3479*10491SRishi.Srivatsavai@Sun.COM }; 3480*10491SRishi.Srivatsavai@Sun.COM 3481*10491SRishi.Srivatsavai@Sun.COM /* No STREAMS perimeters; we do all our own locking */ 3482*10491SRishi.Srivatsavai@Sun.COM DDI_DEFINE_STREAM_OPS(bridge_ops, nulldev, nulldev, bridge_attach, 3483*10491SRishi.Srivatsavai@Sun.COM bridge_detach, nodev, bridge_info, D_NEW | D_MP, &bridge_tab, 3484*10491SRishi.Srivatsavai@Sun.COM ddi_quiesce_not_supported); 3485*10491SRishi.Srivatsavai@Sun.COM 3486*10491SRishi.Srivatsavai@Sun.COM static struct modldrv modldrv = { 3487*10491SRishi.Srivatsavai@Sun.COM &mod_driverops, 3488*10491SRishi.Srivatsavai@Sun.COM "bridging driver", 3489*10491SRishi.Srivatsavai@Sun.COM &bridge_ops 3490*10491SRishi.Srivatsavai@Sun.COM }; 3491*10491SRishi.Srivatsavai@Sun.COM 3492*10491SRishi.Srivatsavai@Sun.COM static struct modlinkage modlinkage = { 3493*10491SRishi.Srivatsavai@Sun.COM MODREV_1, 3494*10491SRishi.Srivatsavai@Sun.COM (void *)&modldrv, 3495*10491SRishi.Srivatsavai@Sun.COM NULL 3496*10491SRishi.Srivatsavai@Sun.COM }; 3497*10491SRishi.Srivatsavai@Sun.COM 3498*10491SRishi.Srivatsavai@Sun.COM int 3499*10491SRishi.Srivatsavai@Sun.COM _init(void) 3500*10491SRishi.Srivatsavai@Sun.COM { 3501*10491SRishi.Srivatsavai@Sun.COM int retv; 3502*10491SRishi.Srivatsavai@Sun.COM 3503*10491SRishi.Srivatsavai@Sun.COM bridge_inst_init(); 3504*10491SRishi.Srivatsavai@Sun.COM if ((retv = mod_install(&modlinkage)) != 0) 3505*10491SRishi.Srivatsavai@Sun.COM bridge_inst_fini(); 3506*10491SRishi.Srivatsavai@Sun.COM return (retv); 3507*10491SRishi.Srivatsavai@Sun.COM } 3508*10491SRishi.Srivatsavai@Sun.COM 3509*10491SRishi.Srivatsavai@Sun.COM int 3510*10491SRishi.Srivatsavai@Sun.COM _fini(void) 3511*10491SRishi.Srivatsavai@Sun.COM { 3512*10491SRishi.Srivatsavai@Sun.COM int retv; 3513*10491SRishi.Srivatsavai@Sun.COM 3514*10491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_READER); 3515*10491SRishi.Srivatsavai@Sun.COM retv = list_is_empty(&bmac_list) ? 0 : EBUSY; 3516*10491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 3517*10491SRishi.Srivatsavai@Sun.COM if (retv == 0 && 3518*10491SRishi.Srivatsavai@Sun.COM (retv = mod_remove(&modlinkage)) == 0) 3519*10491SRishi.Srivatsavai@Sun.COM bridge_inst_fini(); 3520*10491SRishi.Srivatsavai@Sun.COM return (retv); 3521*10491SRishi.Srivatsavai@Sun.COM } 3522*10491SRishi.Srivatsavai@Sun.COM 3523*10491SRishi.Srivatsavai@Sun.COM int 3524*10491SRishi.Srivatsavai@Sun.COM _info(struct modinfo *modinfop) 3525*10491SRishi.Srivatsavai@Sun.COM { 3526*10491SRishi.Srivatsavai@Sun.COM return (mod_info(&modlinkage, modinfop)); 3527*10491SRishi.Srivatsavai@Sun.COM } 3528