14eaa4710SRishi Srivatsavai /* 24eaa4710SRishi Srivatsavai * CDDL HEADER START 34eaa4710SRishi Srivatsavai * 44eaa4710SRishi Srivatsavai * The contents of this file are subject to the terms of the 54eaa4710SRishi Srivatsavai * Common Development and Distribution License (the "License"). 64eaa4710SRishi Srivatsavai * You may not use this file except in compliance with the License. 74eaa4710SRishi Srivatsavai * 84eaa4710SRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94eaa4710SRishi Srivatsavai * or http://www.opensolaris.org/os/licensing. 104eaa4710SRishi Srivatsavai * See the License for the specific language governing permissions 114eaa4710SRishi Srivatsavai * and limitations under the License. 124eaa4710SRishi Srivatsavai * 134eaa4710SRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each 144eaa4710SRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154eaa4710SRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the 164eaa4710SRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying 174eaa4710SRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner] 184eaa4710SRishi Srivatsavai * 194eaa4710SRishi Srivatsavai * CDDL HEADER END 204eaa4710SRishi Srivatsavai */ 214eaa4710SRishi Srivatsavai 224eaa4710SRishi Srivatsavai /* 234eaa4710SRishi Srivatsavai * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 244eaa4710SRishi Srivatsavai * Use is subject to license terms. 254eaa4710SRishi Srivatsavai */ 264eaa4710SRishi Srivatsavai 274eaa4710SRishi Srivatsavai /* 284eaa4710SRishi Srivatsavai * This module implements a STREAMS driver that provides layer-two (Ethernet) 294eaa4710SRishi Srivatsavai * bridging functionality. The STREAMS interface is used to provide 304eaa4710SRishi Srivatsavai * observability (snoop/wireshark) and control, but not for interface plumbing. 314eaa4710SRishi Srivatsavai */ 324eaa4710SRishi Srivatsavai 334eaa4710SRishi Srivatsavai #include <sys/types.h> 344eaa4710SRishi Srivatsavai #include <sys/bitmap.h> 354eaa4710SRishi Srivatsavai #include <sys/cmn_err.h> 364eaa4710SRishi Srivatsavai #include <sys/conf.h> 374eaa4710SRishi Srivatsavai #include <sys/ddi.h> 384eaa4710SRishi Srivatsavai #include <sys/errno.h> 394eaa4710SRishi Srivatsavai #include <sys/kstat.h> 404eaa4710SRishi Srivatsavai #include <sys/modctl.h> 414eaa4710SRishi Srivatsavai #include <sys/note.h> 424eaa4710SRishi Srivatsavai #include <sys/param.h> 434eaa4710SRishi Srivatsavai #include <sys/policy.h> 444eaa4710SRishi Srivatsavai #include <sys/sdt.h> 454eaa4710SRishi Srivatsavai #include <sys/stat.h> 464eaa4710SRishi Srivatsavai #include <sys/stream.h> 474eaa4710SRishi Srivatsavai #include <sys/stropts.h> 484eaa4710SRishi Srivatsavai #include <sys/strsun.h> 494eaa4710SRishi Srivatsavai #include <sys/sunddi.h> 504eaa4710SRishi Srivatsavai #include <sys/sysmacros.h> 514eaa4710SRishi Srivatsavai #include <sys/systm.h> 524eaa4710SRishi Srivatsavai #include <sys/time.h> 534eaa4710SRishi Srivatsavai #include <sys/dlpi.h> 544eaa4710SRishi Srivatsavai #include <sys/dls.h> 554eaa4710SRishi Srivatsavai #include <sys/mac_ether.h> 564eaa4710SRishi Srivatsavai #include <sys/mac_provider.h> 574eaa4710SRishi Srivatsavai #include <sys/mac_client_priv.h> 584eaa4710SRishi Srivatsavai #include <sys/mac_impl.h> 594eaa4710SRishi Srivatsavai #include <sys/vlan.h> 604eaa4710SRishi Srivatsavai #include <net/bridge.h> 614eaa4710SRishi Srivatsavai #include <net/bridge_impl.h> 624eaa4710SRishi Srivatsavai #include <net/trill.h> 634eaa4710SRishi Srivatsavai 644eaa4710SRishi Srivatsavai /* 654eaa4710SRishi Srivatsavai * Locks and reference counts: object lifetime and design. 664eaa4710SRishi Srivatsavai * 674eaa4710SRishi Srivatsavai * bridge_mac_t 684eaa4710SRishi Srivatsavai * Bridge mac (snoop) instances are in bmac_list, which is protected by 694eaa4710SRishi Srivatsavai * bmac_rwlock. They're allocated by bmac_alloc and freed by bridge_timer(). 704eaa4710SRishi Srivatsavai * Every bridge_inst_t has a single bridge_mac_t, but when bridge_inst_t goes 714eaa4710SRishi Srivatsavai * away, the bridge_mac_t remains until either all of the users go away 724eaa4710SRishi Srivatsavai * (detected by a timer) or until the instance is picked up again by the same 734eaa4710SRishi Srivatsavai * bridge starting back up. 744eaa4710SRishi Srivatsavai * 754eaa4710SRishi Srivatsavai * bridge_inst_t 764eaa4710SRishi Srivatsavai * Bridge instances are in inst_list, which is protected by inst_lock. 774eaa4710SRishi Srivatsavai * They're allocated by inst_alloc() and freed by inst_free(). After 784eaa4710SRishi Srivatsavai * allocation, an instance is placed in inst_list, and the reference count is 794eaa4710SRishi Srivatsavai * incremented to represent this. That reference is decremented when the 804eaa4710SRishi Srivatsavai * BIF_SHUTDOWN flag is set, and no new increments may occur. When the last 814eaa4710SRishi Srivatsavai * reference is freed, the instance is removed from the list. 824eaa4710SRishi Srivatsavai * 834eaa4710SRishi Srivatsavai * Bridge instances have lists of links and an AVL tree of forwarding 844eaa4710SRishi Srivatsavai * entries. Each of these structures holds one reference on the bridge 854eaa4710SRishi Srivatsavai * instance. These lists and tree are protected by bi_rwlock. 864eaa4710SRishi Srivatsavai * 874eaa4710SRishi Srivatsavai * bridge_stream_t 884eaa4710SRishi Srivatsavai * Bridge streams are allocated by stream_alloc() and freed by stream_free(). 894eaa4710SRishi Srivatsavai * These streams are created when "bridged" opens /dev/bridgectl, and are 904eaa4710SRishi Srivatsavai * used to create new bridge instances (via BRIOC_NEWBRIDGE) and control the 914eaa4710SRishi Srivatsavai * links on the bridge. When a stream closes, the bridge instance created is 924eaa4710SRishi Srivatsavai * destroyed. There's at most one bridge instance for a given control 934eaa4710SRishi Srivatsavai * stream. 944eaa4710SRishi Srivatsavai * 954eaa4710SRishi Srivatsavai * bridge_link_t 964eaa4710SRishi Srivatsavai * Links are allocated by bridge_add_link() and freed by link_free(). The 974eaa4710SRishi Srivatsavai * bi_links list holds a reference to the link. When the BLF_DELETED flag is 984eaa4710SRishi Srivatsavai * set, that reference is dropped. The link isn't removed from the list 994eaa4710SRishi Srivatsavai * until the last reference drops. Each forwarding entry that uses a given 1004eaa4710SRishi Srivatsavai * link holds a reference, as does each thread transmitting a packet via the 1014eaa4710SRishi Srivatsavai * link. The MAC layer calls in via bridge_ref_cb() to hold a reference on 1024eaa4710SRishi Srivatsavai * a link when transmitting. 1034eaa4710SRishi Srivatsavai * 1044eaa4710SRishi Srivatsavai * It's important that once BLF_DELETED is set, there's no way for the 1054eaa4710SRishi Srivatsavai * reference count to increase again. If it can, then the link may be 1064eaa4710SRishi Srivatsavai * double-freed. The BLF_FREED flag is intended for use with assertions to 1074eaa4710SRishi Srivatsavai * guard against this in testing. 1084eaa4710SRishi Srivatsavai * 1094eaa4710SRishi Srivatsavai * bridge_fwd_t 1104eaa4710SRishi Srivatsavai * Bridge forwarding entries are allocated by bridge_recv_cb() and freed by 1114eaa4710SRishi Srivatsavai * fwd_free(). The bi_fwd AVL tree holds one reference to the entry. Unlike 1124eaa4710SRishi Srivatsavai * other data structures, the reference is dropped when the entry is removed 1134eaa4710SRishi Srivatsavai * from the tree by fwd_delete(), and the BFF_INTREE flag is removed. Each 1144eaa4710SRishi Srivatsavai * thread that's forwarding a packet to a known destination holds a reference 1154eaa4710SRishi Srivatsavai * to a forwarding entry. 1164eaa4710SRishi Srivatsavai * 1174eaa4710SRishi Srivatsavai * TRILL notes: 1184eaa4710SRishi Srivatsavai * 1194eaa4710SRishi Srivatsavai * The TRILL module does all of its I/O through bridging. It uses references 1204eaa4710SRishi Srivatsavai * on the bridge_inst_t and bridge_link_t structures, and has seven entry 1214eaa4710SRishi Srivatsavai * points and four callbacks. One entry point is for setting the callbacks 1224eaa4710SRishi Srivatsavai * (bridge_trill_register_cb). There are four entry points for taking bridge 1234eaa4710SRishi Srivatsavai * and link references (bridge_trill_{br,ln}{ref,unref}). The final two 1244eaa4710SRishi Srivatsavai * entry points are for decapsulated packets from TRILL (bridge_trill_decaps) 1254eaa4710SRishi Srivatsavai * that need to be bridged locally, and for TRILL-encapsulated output packets 1264eaa4710SRishi Srivatsavai * (bridge_trill_output). 1274eaa4710SRishi Srivatsavai * 1284eaa4710SRishi Srivatsavai * The four callbacks comprise two notification functions for bridges and 1294eaa4710SRishi Srivatsavai * links being deleted, one function for raw received TRILL packets, and one 1304eaa4710SRishi Srivatsavai * for bridge output to non-local TRILL destinations (tunnel entry). 1314eaa4710SRishi Srivatsavai */ 1324eaa4710SRishi Srivatsavai 1334eaa4710SRishi Srivatsavai /* 1344eaa4710SRishi Srivatsavai * Ethernet reserved multicast addresses for TRILL; used also in TRILL module. 1354eaa4710SRishi Srivatsavai */ 1364eaa4710SRishi Srivatsavai const uint8_t all_isis_rbridges[] = ALL_ISIS_RBRIDGES; 1374eaa4710SRishi Srivatsavai static const uint8_t all_esadi_rbridges[] = ALL_ESADI_RBRIDGES; 1384eaa4710SRishi Srivatsavai const uint8_t bridge_group_address[] = BRIDGE_GROUP_ADDRESS; 1394eaa4710SRishi Srivatsavai 1404eaa4710SRishi Srivatsavai static const char *inst_kstats_list[] = { KSINST_NAMES }; 1414eaa4710SRishi Srivatsavai static const char *link_kstats_list[] = { KSLINK_NAMES }; 1424eaa4710SRishi Srivatsavai 1434eaa4710SRishi Srivatsavai #define KREF(p, m, vn) p->m.vn.value.ui64 1444eaa4710SRishi Srivatsavai #define KINCR(p, m, vn) ++KREF(p, m, vn) 1454eaa4710SRishi Srivatsavai #define KDECR(p, m, vn) --KREF(p, m, vn) 1464eaa4710SRishi Srivatsavai 1474eaa4710SRishi Srivatsavai #define KIPINCR(p, vn) KINCR(p, bi_kstats, vn) 1484eaa4710SRishi Srivatsavai #define KIPDECR(p, vn) KDECR(p, bi_kstats, vn) 1494eaa4710SRishi Srivatsavai #define KLPINCR(p, vn) KINCR(p, bl_kstats, vn) 1504eaa4710SRishi Srivatsavai 1514eaa4710SRishi Srivatsavai #define KIINCR(vn) KIPINCR(bip, vn) 1524eaa4710SRishi Srivatsavai #define KIDECR(vn) KIPDECR(bip, vn) 1534eaa4710SRishi Srivatsavai #define KLINCR(vn) KLPINCR(blp, vn) 1544eaa4710SRishi Srivatsavai 1554eaa4710SRishi Srivatsavai #define Dim(x) (sizeof (x) / sizeof (*(x))) 1564eaa4710SRishi Srivatsavai 1574eaa4710SRishi Srivatsavai /* Amount of overhead added when encapsulating with VLAN headers */ 1584eaa4710SRishi Srivatsavai #define VLAN_INCR (sizeof (struct ether_vlan_header) - \ 1594eaa4710SRishi Srivatsavai sizeof (struct ether_header)) 1604eaa4710SRishi Srivatsavai 1614eaa4710SRishi Srivatsavai static dev_info_t *bridge_dev_info; 1624eaa4710SRishi Srivatsavai static major_t bridge_major; 1634eaa4710SRishi Srivatsavai static ddi_taskq_t *bridge_taskq; 1644eaa4710SRishi Srivatsavai 1654eaa4710SRishi Srivatsavai /* 1664eaa4710SRishi Srivatsavai * These are the bridge instance management data structures. The mutex lock 1674eaa4710SRishi Srivatsavai * protects the list of bridge instances. A reference count is then used on 1684eaa4710SRishi Srivatsavai * each instance to determine when to free it. We use mac_minor_hold() to 1694eaa4710SRishi Srivatsavai * allocate minor_t values, which are used both for self-cloning /dev/net/ 1704eaa4710SRishi Srivatsavai * device nodes as well as client streams. Minor node 0 is reserved for the 1714eaa4710SRishi Srivatsavai * allocation control node. 1724eaa4710SRishi Srivatsavai */ 1734eaa4710SRishi Srivatsavai static list_t inst_list; 1744eaa4710SRishi Srivatsavai static kcondvar_t inst_cv; /* Allows us to wait for shutdown */ 1754eaa4710SRishi Srivatsavai static kmutex_t inst_lock; 1764eaa4710SRishi Srivatsavai 1774eaa4710SRishi Srivatsavai static krwlock_t bmac_rwlock; 1784eaa4710SRishi Srivatsavai static list_t bmac_list; 1794eaa4710SRishi Srivatsavai 1804eaa4710SRishi Srivatsavai /* Wait for taskq entries that use STREAMS */ 1814eaa4710SRishi Srivatsavai static kcondvar_t stream_ref_cv; 1824eaa4710SRishi Srivatsavai static kmutex_t stream_ref_lock; 1834eaa4710SRishi Srivatsavai 1844eaa4710SRishi Srivatsavai static timeout_id_t bridge_timerid; 1854eaa4710SRishi Srivatsavai static clock_t bridge_scan_interval; 1864eaa4710SRishi Srivatsavai static clock_t bridge_fwd_age; 1874eaa4710SRishi Srivatsavai 1884eaa4710SRishi Srivatsavai static bridge_inst_t *bridge_find_name(const char *); 1894eaa4710SRishi Srivatsavai static void bridge_timer(void *); 1904eaa4710SRishi Srivatsavai static void bridge_unref(bridge_inst_t *); 1914eaa4710SRishi Srivatsavai 1924eaa4710SRishi Srivatsavai static const uint8_t zero_addr[ETHERADDRL] = { 0 }; 1934eaa4710SRishi Srivatsavai 1944eaa4710SRishi Srivatsavai /* Global TRILL linkage */ 1954eaa4710SRishi Srivatsavai static trill_recv_pkt_t trill_recv_fn; 1964eaa4710SRishi Srivatsavai static trill_encap_pkt_t trill_encap_fn; 1974eaa4710SRishi Srivatsavai static trill_br_dstr_t trill_brdstr_fn; 1984eaa4710SRishi Srivatsavai static trill_ln_dstr_t trill_lndstr_fn; 1994eaa4710SRishi Srivatsavai 2004eaa4710SRishi Srivatsavai /* special settings to accommodate DLD flow control; see dld_str.c */ 2014eaa4710SRishi Srivatsavai static struct module_info bridge_dld_modinfo = { 2024eaa4710SRishi Srivatsavai 0, /* mi_idnum */ 2034eaa4710SRishi Srivatsavai "bridge", /* mi_idname */ 2044eaa4710SRishi Srivatsavai 0, /* mi_minpsz */ 2054eaa4710SRishi Srivatsavai INFPSZ, /* mi_maxpsz */ 2064eaa4710SRishi Srivatsavai 1, /* mi_hiwat */ 2074eaa4710SRishi Srivatsavai 0 /* mi_lowat */ 2084eaa4710SRishi Srivatsavai }; 2094eaa4710SRishi Srivatsavai 2104eaa4710SRishi Srivatsavai static struct qinit bridge_dld_rinit = { 2114eaa4710SRishi Srivatsavai NULL, /* qi_putp */ 2124eaa4710SRishi Srivatsavai NULL, /* qi_srvp */ 2134eaa4710SRishi Srivatsavai dld_open, /* qi_qopen */ 2144eaa4710SRishi Srivatsavai dld_close, /* qi_qclose */ 2154eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */ 2164eaa4710SRishi Srivatsavai &bridge_dld_modinfo, /* qi_minfo */ 2174eaa4710SRishi Srivatsavai NULL /* qi_mstat */ 2184eaa4710SRishi Srivatsavai }; 2194eaa4710SRishi Srivatsavai 2204eaa4710SRishi Srivatsavai static struct qinit bridge_dld_winit = { 2214eaa4710SRishi Srivatsavai (int (*)())dld_wput, /* qi_putp */ 2224eaa4710SRishi Srivatsavai (int (*)())dld_wsrv, /* qi_srvp */ 2234eaa4710SRishi Srivatsavai NULL, /* qi_qopen */ 2244eaa4710SRishi Srivatsavai NULL, /* qi_qclose */ 2254eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */ 2264eaa4710SRishi Srivatsavai &bridge_dld_modinfo, /* qi_minfo */ 2274eaa4710SRishi Srivatsavai NULL /* qi_mstat */ 2284eaa4710SRishi Srivatsavai }; 2294eaa4710SRishi Srivatsavai 2304eaa4710SRishi Srivatsavai static int bridge_ioc_listfwd(void *, intptr_t, int, cred_t *, int *); 2314eaa4710SRishi Srivatsavai 2324eaa4710SRishi Srivatsavai /* GLDv3 control ioctls used by Bridging */ 2334eaa4710SRishi Srivatsavai static dld_ioc_info_t bridge_ioc_list[] = { 2344eaa4710SRishi Srivatsavai {BRIDGE_IOC_LISTFWD, DLDCOPYINOUT, sizeof (bridge_listfwd_t), 2354eaa4710SRishi Srivatsavai bridge_ioc_listfwd, NULL}, 2364eaa4710SRishi Srivatsavai }; 2374eaa4710SRishi Srivatsavai 2384eaa4710SRishi Srivatsavai /* 2394eaa4710SRishi Srivatsavai * Given a bridge mac pointer, get a ref-held pointer to the corresponding 2404eaa4710SRishi Srivatsavai * bridge instance, if any. We must hold the global bmac_rwlock so that 2414eaa4710SRishi Srivatsavai * bm_inst doesn't slide out from under us. 2424eaa4710SRishi Srivatsavai */ 2434eaa4710SRishi Srivatsavai static bridge_inst_t * 2444eaa4710SRishi Srivatsavai mac_to_inst(const bridge_mac_t *bmp) 2454eaa4710SRishi Srivatsavai { 2464eaa4710SRishi Srivatsavai bridge_inst_t *bip; 2474eaa4710SRishi Srivatsavai 2484eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_READER); 2494eaa4710SRishi Srivatsavai if ((bip = bmp->bm_inst) != NULL) 2504eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs); 2514eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 2524eaa4710SRishi Srivatsavai return (bip); 2534eaa4710SRishi Srivatsavai } 2544eaa4710SRishi Srivatsavai 2554eaa4710SRishi Srivatsavai static void 2564eaa4710SRishi Srivatsavai link_sdu_fail(bridge_link_t *blp, boolean_t failed, mblk_t **mlist) 2574eaa4710SRishi Srivatsavai { 2584eaa4710SRishi Srivatsavai mblk_t *mp; 2594eaa4710SRishi Srivatsavai bridge_ctl_t *bcp; 2604eaa4710SRishi Srivatsavai bridge_link_t *blcmp; 2614eaa4710SRishi Srivatsavai bridge_inst_t *bip; 2624eaa4710SRishi Srivatsavai bridge_mac_t *bmp; 2634eaa4710SRishi Srivatsavai 2644eaa4710SRishi Srivatsavai if (failed) { 2654eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_SDUFAIL) 2664eaa4710SRishi Srivatsavai return; 2674eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_SDUFAIL; 2684eaa4710SRishi Srivatsavai } else { 2694eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_SDUFAIL)) 2704eaa4710SRishi Srivatsavai return; 2714eaa4710SRishi Srivatsavai blp->bl_flags &= ~BLF_SDUFAIL; 2724eaa4710SRishi Srivatsavai } 2734eaa4710SRishi Srivatsavai 2744eaa4710SRishi Srivatsavai /* 2754eaa4710SRishi Srivatsavai * If this link is otherwise up, then check if there are any other 2764eaa4710SRishi Srivatsavai * non-failed non-down links. If not, then we control the state of the 2774eaa4710SRishi Srivatsavai * whole bridge. 2784eaa4710SRishi Srivatsavai */ 2794eaa4710SRishi Srivatsavai bip = blp->bl_inst; 2804eaa4710SRishi Srivatsavai bmp = bip->bi_mac; 2814eaa4710SRishi Srivatsavai if (blp->bl_linkstate != LINK_STATE_DOWN) { 2824eaa4710SRishi Srivatsavai for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 2834eaa4710SRishi Srivatsavai blcmp = list_next(&bip->bi_links, blcmp)) { 2844eaa4710SRishi Srivatsavai if (blp != blcmp && 2854eaa4710SRishi Srivatsavai !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) && 2864eaa4710SRishi Srivatsavai blcmp->bl_linkstate != LINK_STATE_DOWN) 2874eaa4710SRishi Srivatsavai break; 2884eaa4710SRishi Srivatsavai } 2894eaa4710SRishi Srivatsavai if (blcmp == NULL) { 2904eaa4710SRishi Srivatsavai bmp->bm_linkstate = failed ? LINK_STATE_DOWN : 2914eaa4710SRishi Srivatsavai LINK_STATE_UP; 2924eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, bmp->bm_linkstate); 2934eaa4710SRishi Srivatsavai } 2944eaa4710SRishi Srivatsavai } 2954eaa4710SRishi Srivatsavai 2964eaa4710SRishi Srivatsavai /* 2974eaa4710SRishi Srivatsavai * If we're becoming failed, then the link's current true state needs 2984eaa4710SRishi Srivatsavai * to be reflected upwards to this link's clients. If we're becoming 2994eaa4710SRishi Srivatsavai * unfailed, then we get the state of the bridge instead on all 3004eaa4710SRishi Srivatsavai * clients. 3014eaa4710SRishi Srivatsavai */ 3024eaa4710SRishi Srivatsavai if (failed) { 3034eaa4710SRishi Srivatsavai if (bmp->bm_linkstate != blp->bl_linkstate) 3044eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh, blp->bl_linkstate); 3054eaa4710SRishi Srivatsavai } else { 3064eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh, bmp->bm_linkstate); 3074eaa4710SRishi Srivatsavai } 3084eaa4710SRishi Srivatsavai 3094eaa4710SRishi Srivatsavai /* get the current mblk we're going to send up */ 3104eaa4710SRishi Srivatsavai if ((mp = blp->bl_lfailmp) == NULL && 3114eaa4710SRishi Srivatsavai (mp = allocb(sizeof (bridge_ctl_t), BPRI_MED)) == NULL) 3124eaa4710SRishi Srivatsavai return; 3134eaa4710SRishi Srivatsavai 3144eaa4710SRishi Srivatsavai /* get a new one for next time */ 3154eaa4710SRishi Srivatsavai blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED); 3164eaa4710SRishi Srivatsavai 3174eaa4710SRishi Srivatsavai /* if none for next time, then report only failures */ 3184eaa4710SRishi Srivatsavai if (blp->bl_lfailmp == NULL && !failed) { 3194eaa4710SRishi Srivatsavai blp->bl_lfailmp = mp; 3204eaa4710SRishi Srivatsavai return; 3214eaa4710SRishi Srivatsavai } 3224eaa4710SRishi Srivatsavai 3234eaa4710SRishi Srivatsavai /* LINTED: alignment */ 3244eaa4710SRishi Srivatsavai bcp = (bridge_ctl_t *)mp->b_rptr; 3254eaa4710SRishi Srivatsavai bcp->bc_linkid = blp->bl_linkid; 3264eaa4710SRishi Srivatsavai bcp->bc_failed = failed; 3274eaa4710SRishi Srivatsavai mp->b_wptr = (uchar_t *)(bcp + 1); 3284eaa4710SRishi Srivatsavai mp->b_next = *mlist; 3294eaa4710SRishi Srivatsavai *mlist = mp; 3304eaa4710SRishi Srivatsavai } 3314eaa4710SRishi Srivatsavai 3324eaa4710SRishi Srivatsavai /* 3334eaa4710SRishi Srivatsavai * Send control messages (link SDU changes) using the stream to the 3344eaa4710SRishi Srivatsavai * bridge instance daemon. 3354eaa4710SRishi Srivatsavai */ 3364eaa4710SRishi Srivatsavai static void 3374eaa4710SRishi Srivatsavai send_up_messages(bridge_inst_t *bip, mblk_t *mp) 3384eaa4710SRishi Srivatsavai { 3394eaa4710SRishi Srivatsavai mblk_t *mnext; 3404eaa4710SRishi Srivatsavai queue_t *rq; 3414eaa4710SRishi Srivatsavai 3424eaa4710SRishi Srivatsavai rq = bip->bi_control->bs_wq; 3434eaa4710SRishi Srivatsavai rq = OTHERQ(rq); 3444eaa4710SRishi Srivatsavai while (mp != NULL) { 3454eaa4710SRishi Srivatsavai mnext = mp->b_next; 3464eaa4710SRishi Srivatsavai mp->b_next = NULL; 3474eaa4710SRishi Srivatsavai putnext(rq, mp); 3484eaa4710SRishi Srivatsavai mp = mnext; 3494eaa4710SRishi Srivatsavai } 3504eaa4710SRishi Srivatsavai } 3514eaa4710SRishi Srivatsavai 3524eaa4710SRishi Srivatsavai /* ARGSUSED */ 3534eaa4710SRishi Srivatsavai static int 3544eaa4710SRishi Srivatsavai bridge_m_getstat(void *arg, uint_t stat, uint64_t *val) 3554eaa4710SRishi Srivatsavai { 3564eaa4710SRishi Srivatsavai return (ENOTSUP); 3574eaa4710SRishi Srivatsavai } 3584eaa4710SRishi Srivatsavai 3594eaa4710SRishi Srivatsavai static int 3604eaa4710SRishi Srivatsavai bridge_m_start(void *arg) 3614eaa4710SRishi Srivatsavai { 3624eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg; 3634eaa4710SRishi Srivatsavai 3644eaa4710SRishi Srivatsavai bmp->bm_flags |= BMF_STARTED; 3654eaa4710SRishi Srivatsavai return (0); 3664eaa4710SRishi Srivatsavai } 3674eaa4710SRishi Srivatsavai 3684eaa4710SRishi Srivatsavai static void 3694eaa4710SRishi Srivatsavai bridge_m_stop(void *arg) 3704eaa4710SRishi Srivatsavai { 3714eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg; 3724eaa4710SRishi Srivatsavai 3734eaa4710SRishi Srivatsavai bmp->bm_flags &= ~BMF_STARTED; 3744eaa4710SRishi Srivatsavai } 3754eaa4710SRishi Srivatsavai 3764eaa4710SRishi Srivatsavai /* ARGSUSED */ 3774eaa4710SRishi Srivatsavai static int 3784eaa4710SRishi Srivatsavai bridge_m_setpromisc(void *arg, boolean_t on) 3794eaa4710SRishi Srivatsavai { 3804eaa4710SRishi Srivatsavai return (0); 3814eaa4710SRishi Srivatsavai } 3824eaa4710SRishi Srivatsavai 3834eaa4710SRishi Srivatsavai /* ARGSUSED */ 3844eaa4710SRishi Srivatsavai static int 3854eaa4710SRishi Srivatsavai bridge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 3864eaa4710SRishi Srivatsavai { 3874eaa4710SRishi Srivatsavai return (0); 3884eaa4710SRishi Srivatsavai } 3894eaa4710SRishi Srivatsavai 3904eaa4710SRishi Srivatsavai /* ARGSUSED */ 3914eaa4710SRishi Srivatsavai static int 3924eaa4710SRishi Srivatsavai bridge_m_unicst(void *arg, const uint8_t *macaddr) 3934eaa4710SRishi Srivatsavai { 3944eaa4710SRishi Srivatsavai return (ENOTSUP); 3954eaa4710SRishi Srivatsavai } 3964eaa4710SRishi Srivatsavai 3974eaa4710SRishi Srivatsavai static mblk_t * 3984eaa4710SRishi Srivatsavai bridge_m_tx(void *arg, mblk_t *mp) 3994eaa4710SRishi Srivatsavai { 4004eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(arg)); 4014eaa4710SRishi Srivatsavai freemsgchain(mp); 4024eaa4710SRishi Srivatsavai return (NULL); 4034eaa4710SRishi Srivatsavai } 4044eaa4710SRishi Srivatsavai 4054eaa4710SRishi Srivatsavai /* ARGSUSED */ 4064eaa4710SRishi Srivatsavai static int 4074eaa4710SRishi Srivatsavai bridge_ioc_listfwd(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 4084eaa4710SRishi Srivatsavai { 4094eaa4710SRishi Srivatsavai bridge_listfwd_t *blf = karg; 4104eaa4710SRishi Srivatsavai bridge_inst_t *bip; 4114eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, match; 4124eaa4710SRishi Srivatsavai avl_index_t where; 4134eaa4710SRishi Srivatsavai 4144eaa4710SRishi Srivatsavai bip = bridge_find_name(blf->blf_name); 4154eaa4710SRishi Srivatsavai if (bip == NULL) 4164eaa4710SRishi Srivatsavai return (ENOENT); 4174eaa4710SRishi Srivatsavai 4184eaa4710SRishi Srivatsavai bcopy(blf->blf_dest, match.bf_dest, ETHERADDRL); 4194eaa4710SRishi Srivatsavai match.bf_flags |= BFF_VLANLOCAL; 4204eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 4214eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, &where)) == NULL) 4224eaa4710SRishi Srivatsavai bfp = avl_nearest(&bip->bi_fwd, where, AVL_AFTER); 4234eaa4710SRishi Srivatsavai else 4244eaa4710SRishi Srivatsavai bfp = AVL_NEXT(&bip->bi_fwd, bfp); 4254eaa4710SRishi Srivatsavai if (bfp == NULL) { 4264eaa4710SRishi Srivatsavai bzero(blf, sizeof (*blf)); 4274eaa4710SRishi Srivatsavai } else { 4284eaa4710SRishi Srivatsavai bcopy(bfp->bf_dest, blf->blf_dest, ETHERADDRL); 4294eaa4710SRishi Srivatsavai blf->blf_trill_nick = bfp->bf_trill_nick; 4304eaa4710SRishi Srivatsavai blf->blf_ms_age = 4314eaa4710SRishi Srivatsavai drv_hztousec(lbolt - bfp->bf_lastheard) / 1000; 4324eaa4710SRishi Srivatsavai blf->blf_is_local = 4334eaa4710SRishi Srivatsavai (bfp->bf_flags & BFF_LOCALADDR) != 0; 4344eaa4710SRishi Srivatsavai blf->blf_linkid = bfp->bf_links[0]->bl_linkid; 4354eaa4710SRishi Srivatsavai } 4364eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 4374eaa4710SRishi Srivatsavai bridge_unref(bip); 4384eaa4710SRishi Srivatsavai return (0); 4394eaa4710SRishi Srivatsavai } 4404eaa4710SRishi Srivatsavai 4414eaa4710SRishi Srivatsavai static int 4424eaa4710SRishi Srivatsavai bridge_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 4434eaa4710SRishi Srivatsavai uint_t pr_valsize, const void *pr_val) 4444eaa4710SRishi Srivatsavai { 4454eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg; 4464eaa4710SRishi Srivatsavai bridge_inst_t *bip; 4474eaa4710SRishi Srivatsavai bridge_link_t *blp; 4484eaa4710SRishi Srivatsavai int err; 4494eaa4710SRishi Srivatsavai uint_t maxsdu; 4504eaa4710SRishi Srivatsavai mblk_t *mlist; 4514eaa4710SRishi Srivatsavai 4524eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(pr_name)); 4534eaa4710SRishi Srivatsavai switch (pr_num) { 4544eaa4710SRishi Srivatsavai case MAC_PROP_MTU: 4554eaa4710SRishi Srivatsavai if (pr_valsize < sizeof (bmp->bm_maxsdu)) { 4564eaa4710SRishi Srivatsavai err = EINVAL; 4574eaa4710SRishi Srivatsavai break; 4584eaa4710SRishi Srivatsavai } 4594eaa4710SRishi Srivatsavai (void) bcopy(pr_val, &maxsdu, sizeof (maxsdu)); 4604eaa4710SRishi Srivatsavai if (maxsdu == bmp->bm_maxsdu) { 4614eaa4710SRishi Srivatsavai err = 0; 4624eaa4710SRishi Srivatsavai } else if ((bip = mac_to_inst(bmp)) == NULL) { 4634eaa4710SRishi Srivatsavai err = ENXIO; 4644eaa4710SRishi Srivatsavai } else { 4654eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 4664eaa4710SRishi Srivatsavai mlist = NULL; 4674eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 4684eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 4694eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_DELETED) 4704eaa4710SRishi Srivatsavai continue; 4714eaa4710SRishi Srivatsavai if (blp->bl_maxsdu == maxsdu) 4724eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_FALSE, &mlist); 4734eaa4710SRishi Srivatsavai else if (blp->bl_maxsdu == bmp->bm_maxsdu) 4744eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_TRUE, &mlist); 4754eaa4710SRishi Srivatsavai } 4764eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 4774eaa4710SRishi Srivatsavai bmp->bm_maxsdu = maxsdu; 4784eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 4794eaa4710SRishi Srivatsavai send_up_messages(bip, mlist); 4804eaa4710SRishi Srivatsavai bridge_unref(bip); 4814eaa4710SRishi Srivatsavai err = 0; 4824eaa4710SRishi Srivatsavai } 4834eaa4710SRishi Srivatsavai break; 4844eaa4710SRishi Srivatsavai 4854eaa4710SRishi Srivatsavai default: 4864eaa4710SRishi Srivatsavai err = ENOTSUP; 4874eaa4710SRishi Srivatsavai break; 4884eaa4710SRishi Srivatsavai } 4894eaa4710SRishi Srivatsavai return (err); 4904eaa4710SRishi Srivatsavai } 4914eaa4710SRishi Srivatsavai 4924eaa4710SRishi Srivatsavai static int 4934eaa4710SRishi Srivatsavai bridge_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 4944eaa4710SRishi Srivatsavai uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 4954eaa4710SRishi Srivatsavai { 4964eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg; 4974eaa4710SRishi Srivatsavai int err = 0; 4984eaa4710SRishi Srivatsavai 4994eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(pr_name)); 5004eaa4710SRishi Srivatsavai switch (pr_num) { 5014eaa4710SRishi Srivatsavai case MAC_PROP_MTU: { 5024eaa4710SRishi Srivatsavai mac_propval_range_t range; 5034eaa4710SRishi Srivatsavai 5044eaa4710SRishi Srivatsavai if (!(pr_flags & MAC_PROP_POSSIBLE)) 5054eaa4710SRishi Srivatsavai return (ENOTSUP); 5064eaa4710SRishi Srivatsavai if (pr_valsize < sizeof (mac_propval_range_t)) 5074eaa4710SRishi Srivatsavai return (EINVAL); 5084eaa4710SRishi Srivatsavai range.mpr_count = 1; 5094eaa4710SRishi Srivatsavai range.mpr_type = MAC_PROPVAL_UINT32; 5104eaa4710SRishi Srivatsavai range.range_uint32[0].mpur_min = 5114eaa4710SRishi Srivatsavai range.range_uint32[0].mpur_max = bmp->bm_maxsdu; 5124eaa4710SRishi Srivatsavai bcopy(&range, pr_val, sizeof (range)); 5134eaa4710SRishi Srivatsavai *perm = MAC_PROP_PERM_RW; 5144eaa4710SRishi Srivatsavai break; 5154eaa4710SRishi Srivatsavai } 5164eaa4710SRishi Srivatsavai case MAC_PROP_STATUS: 5174eaa4710SRishi Srivatsavai if (pr_valsize < sizeof (bmp->bm_linkstate)) { 5184eaa4710SRishi Srivatsavai err = EINVAL; 5194eaa4710SRishi Srivatsavai } else { 5204eaa4710SRishi Srivatsavai bcopy(&bmp->bm_linkstate, pr_val, 5214eaa4710SRishi Srivatsavai sizeof (&bmp->bm_linkstate)); 5224eaa4710SRishi Srivatsavai *perm = MAC_PROP_PERM_READ; 5234eaa4710SRishi Srivatsavai } 5244eaa4710SRishi Srivatsavai break; 5254eaa4710SRishi Srivatsavai 5264eaa4710SRishi Srivatsavai default: 5274eaa4710SRishi Srivatsavai err = ENOTSUP; 5284eaa4710SRishi Srivatsavai break; 5294eaa4710SRishi Srivatsavai } 5304eaa4710SRishi Srivatsavai return (err); 5314eaa4710SRishi Srivatsavai } 5324eaa4710SRishi Srivatsavai 5334eaa4710SRishi Srivatsavai static mac_callbacks_t bridge_m_callbacks = { 5344eaa4710SRishi Srivatsavai MC_SETPROP | MC_GETPROP, 5354eaa4710SRishi Srivatsavai bridge_m_getstat, 5364eaa4710SRishi Srivatsavai bridge_m_start, 5374eaa4710SRishi Srivatsavai bridge_m_stop, 5384eaa4710SRishi Srivatsavai bridge_m_setpromisc, 5394eaa4710SRishi Srivatsavai bridge_m_multicst, 5404eaa4710SRishi Srivatsavai bridge_m_unicst, 5414eaa4710SRishi Srivatsavai bridge_m_tx, 5424eaa4710SRishi Srivatsavai NULL, /* ioctl */ 5434eaa4710SRishi Srivatsavai NULL, /* getcapab */ 5444eaa4710SRishi Srivatsavai NULL, /* open */ 5454eaa4710SRishi Srivatsavai NULL, /* close */ 5464eaa4710SRishi Srivatsavai bridge_m_setprop, 5474eaa4710SRishi Srivatsavai bridge_m_getprop 5484eaa4710SRishi Srivatsavai }; 5494eaa4710SRishi Srivatsavai 5504eaa4710SRishi Srivatsavai /* 5514eaa4710SRishi Srivatsavai * Create kstats from a list. 5524eaa4710SRishi Srivatsavai */ 5534eaa4710SRishi Srivatsavai static kstat_t * 5544eaa4710SRishi Srivatsavai kstat_setup(kstat_named_t *knt, const char **names, int nstat, 5554eaa4710SRishi Srivatsavai const char *unitname) 5564eaa4710SRishi Srivatsavai { 5574eaa4710SRishi Srivatsavai kstat_t *ksp; 5584eaa4710SRishi Srivatsavai int i; 5594eaa4710SRishi Srivatsavai 5604eaa4710SRishi Srivatsavai for (i = 0; i < nstat; i++) 5614eaa4710SRishi Srivatsavai kstat_named_init(&knt[i], names[i], KSTAT_DATA_UINT64); 5624eaa4710SRishi Srivatsavai 5634eaa4710SRishi Srivatsavai ksp = kstat_create_zone("bridge", 0, unitname, "net", 5644eaa4710SRishi Srivatsavai KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID); 5654eaa4710SRishi Srivatsavai if (ksp != NULL) { 5664eaa4710SRishi Srivatsavai ksp->ks_data = knt; 5674eaa4710SRishi Srivatsavai kstat_install(ksp); 5684eaa4710SRishi Srivatsavai } 5694eaa4710SRishi Srivatsavai return (ksp); 5704eaa4710SRishi Srivatsavai } 5714eaa4710SRishi Srivatsavai 5724eaa4710SRishi Srivatsavai /* 5734eaa4710SRishi Srivatsavai * Find an existing bridge_mac_t structure or allocate a new one for the given 5744eaa4710SRishi Srivatsavai * bridge instance. This creates the mac driver instance that snoop can use. 5754eaa4710SRishi Srivatsavai */ 5764eaa4710SRishi Srivatsavai static int 5774eaa4710SRishi Srivatsavai bmac_alloc(bridge_inst_t *bip, bridge_mac_t **bmacp) 5784eaa4710SRishi Srivatsavai { 5794eaa4710SRishi Srivatsavai bridge_mac_t *bmp, *bnew; 5804eaa4710SRishi Srivatsavai mac_register_t *mac; 5814eaa4710SRishi Srivatsavai int err; 5824eaa4710SRishi Srivatsavai 5834eaa4710SRishi Srivatsavai *bmacp = NULL; 5844eaa4710SRishi Srivatsavai if ((mac = mac_alloc(MAC_VERSION)) == NULL) 5854eaa4710SRishi Srivatsavai return (EINVAL); 5864eaa4710SRishi Srivatsavai 5874eaa4710SRishi Srivatsavai bnew = kmem_zalloc(sizeof (*bnew), KM_SLEEP); 5884eaa4710SRishi Srivatsavai 5894eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_WRITER); 5904eaa4710SRishi Srivatsavai for (bmp = list_head(&bmac_list); bmp != NULL; 5914eaa4710SRishi Srivatsavai bmp = list_next(&bmac_list, bmp)) { 5924eaa4710SRishi Srivatsavai if (strcmp(bip->bi_name, bmp->bm_name) == 0) { 5934eaa4710SRishi Srivatsavai ASSERT(bmp->bm_inst == NULL); 5944eaa4710SRishi Srivatsavai bmp->bm_inst = bip; 5954eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 5964eaa4710SRishi Srivatsavai kmem_free(bnew, sizeof (*bnew)); 5974eaa4710SRishi Srivatsavai mac_free(mac); 5984eaa4710SRishi Srivatsavai *bmacp = bmp; 5994eaa4710SRishi Srivatsavai return (0); 6004eaa4710SRishi Srivatsavai } 6014eaa4710SRishi Srivatsavai } 6024eaa4710SRishi Srivatsavai 6034eaa4710SRishi Srivatsavai mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 6044eaa4710SRishi Srivatsavai mac->m_driver = bnew; 6054eaa4710SRishi Srivatsavai mac->m_dip = bridge_dev_info; 6064eaa4710SRishi Srivatsavai mac->m_instance = (uint_t)-1; 6074eaa4710SRishi Srivatsavai mac->m_src_addr = (uint8_t *)zero_addr; 6084eaa4710SRishi Srivatsavai mac->m_callbacks = &bridge_m_callbacks; 6094eaa4710SRishi Srivatsavai 6104eaa4710SRishi Srivatsavai /* 6114eaa4710SRishi Srivatsavai * Note that the SDU limits are irrelevant, as nobody transmits on the 6124eaa4710SRishi Srivatsavai * bridge node itself. It's mainly for monitoring but we allow 6134eaa4710SRishi Srivatsavai * setting the bridge MTU for quick transition of all links part of the 6144eaa4710SRishi Srivatsavai * bridge to a new MTU. 6154eaa4710SRishi Srivatsavai */ 6164eaa4710SRishi Srivatsavai mac->m_min_sdu = 1; 6174eaa4710SRishi Srivatsavai mac->m_max_sdu = 1500; 6184eaa4710SRishi Srivatsavai err = mac_register(mac, &bnew->bm_mh); 6194eaa4710SRishi Srivatsavai mac_free(mac); 6204eaa4710SRishi Srivatsavai if (err != 0) { 6214eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 6224eaa4710SRishi Srivatsavai kmem_free(bnew, sizeof (*bnew)); 6234eaa4710SRishi Srivatsavai return (err); 6244eaa4710SRishi Srivatsavai } 6254eaa4710SRishi Srivatsavai 6264eaa4710SRishi Srivatsavai bnew->bm_inst = bip; 6274eaa4710SRishi Srivatsavai (void) strcpy(bnew->bm_name, bip->bi_name); 6284eaa4710SRishi Srivatsavai if (list_is_empty(&bmac_list)) { 6294eaa4710SRishi Srivatsavai bridge_timerid = timeout(bridge_timer, NULL, 6304eaa4710SRishi Srivatsavai bridge_scan_interval); 6314eaa4710SRishi Srivatsavai } 6324eaa4710SRishi Srivatsavai list_insert_tail(&bmac_list, bnew); 6334eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 6344eaa4710SRishi Srivatsavai 6354eaa4710SRishi Srivatsavai /* 6364eaa4710SRishi Srivatsavai * Mark the MAC as unable to go "active" so that only passive clients 6374eaa4710SRishi Srivatsavai * (such as snoop) can bind to it. 6384eaa4710SRishi Srivatsavai */ 6394eaa4710SRishi Srivatsavai mac_no_active(bnew->bm_mh); 6404eaa4710SRishi Srivatsavai *bmacp = bnew; 6414eaa4710SRishi Srivatsavai return (0); 6424eaa4710SRishi Srivatsavai } 6434eaa4710SRishi Srivatsavai 6444eaa4710SRishi Srivatsavai /* 6454eaa4710SRishi Srivatsavai * Disconnect the given bridge_mac_t from its bridge instance. The bridge 6464eaa4710SRishi Srivatsavai * instance is going away. The mac instance can't go away until the clients 6474eaa4710SRishi Srivatsavai * are gone (see bridge_timer). 6484eaa4710SRishi Srivatsavai */ 6494eaa4710SRishi Srivatsavai static void 6504eaa4710SRishi Srivatsavai bmac_disconnect(bridge_mac_t *bmp) 6514eaa4710SRishi Srivatsavai { 6524eaa4710SRishi Srivatsavai bridge_inst_t *bip; 6534eaa4710SRishi Srivatsavai 6544eaa4710SRishi Srivatsavai bmp->bm_linkstate = LINK_STATE_DOWN; 6554eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN); 6564eaa4710SRishi Srivatsavai 6574eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_READER); 6584eaa4710SRishi Srivatsavai bip = bmp->bm_inst; 6594eaa4710SRishi Srivatsavai bip->bi_mac = NULL; 6604eaa4710SRishi Srivatsavai bmp->bm_inst = NULL; 6614eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 6624eaa4710SRishi Srivatsavai } 6634eaa4710SRishi Srivatsavai 6644eaa4710SRishi Srivatsavai /* This is used by the avl trees to sort forwarding table entries */ 6654eaa4710SRishi Srivatsavai static int 6664eaa4710SRishi Srivatsavai fwd_compare(const void *addr1, const void *addr2) 6674eaa4710SRishi Srivatsavai { 6684eaa4710SRishi Srivatsavai const bridge_fwd_t *fwd1 = addr1; 6694eaa4710SRishi Srivatsavai const bridge_fwd_t *fwd2 = addr2; 6704eaa4710SRishi Srivatsavai int diff = memcmp(fwd1->bf_dest, fwd2->bf_dest, ETHERADDRL); 6714eaa4710SRishi Srivatsavai 6724eaa4710SRishi Srivatsavai if (diff != 0) 6734eaa4710SRishi Srivatsavai return (diff > 0 ? 1 : -1); 6744eaa4710SRishi Srivatsavai 6754eaa4710SRishi Srivatsavai if ((fwd1->bf_flags ^ fwd2->bf_flags) & BFF_VLANLOCAL) { 6764eaa4710SRishi Srivatsavai if (fwd1->bf_vlanid > fwd2->bf_vlanid) 6774eaa4710SRishi Srivatsavai return (1); 6784eaa4710SRishi Srivatsavai else if (fwd1->bf_vlanid < fwd2->bf_vlanid) 6794eaa4710SRishi Srivatsavai return (-1); 6804eaa4710SRishi Srivatsavai } 6814eaa4710SRishi Srivatsavai return (0); 6824eaa4710SRishi Srivatsavai } 6834eaa4710SRishi Srivatsavai 6844eaa4710SRishi Srivatsavai static void 6854eaa4710SRishi Srivatsavai inst_free(bridge_inst_t *bip) 6864eaa4710SRishi Srivatsavai { 6874eaa4710SRishi Srivatsavai ASSERT(bip->bi_mac == NULL); 6884eaa4710SRishi Srivatsavai rw_destroy(&bip->bi_rwlock); 6894eaa4710SRishi Srivatsavai list_destroy(&bip->bi_links); 6904eaa4710SRishi Srivatsavai cv_destroy(&bip->bi_linkwait); 6914eaa4710SRishi Srivatsavai avl_destroy(&bip->bi_fwd); 6924eaa4710SRishi Srivatsavai if (bip->bi_ksp != NULL) 6934eaa4710SRishi Srivatsavai kstat_delete(bip->bi_ksp); 6944eaa4710SRishi Srivatsavai kmem_free(bip, sizeof (*bip)); 6954eaa4710SRishi Srivatsavai } 6964eaa4710SRishi Srivatsavai 6974eaa4710SRishi Srivatsavai static bridge_inst_t * 6984eaa4710SRishi Srivatsavai inst_alloc(const char *bridge) 6994eaa4710SRishi Srivatsavai { 7004eaa4710SRishi Srivatsavai bridge_inst_t *bip; 7014eaa4710SRishi Srivatsavai 7024eaa4710SRishi Srivatsavai bip = kmem_zalloc(sizeof (*bip), KM_SLEEP); 7034eaa4710SRishi Srivatsavai bip->bi_refs = 1; 7044eaa4710SRishi Srivatsavai (void) strcpy(bip->bi_name, bridge); 7054eaa4710SRishi Srivatsavai rw_init(&bip->bi_rwlock, NULL, RW_DRIVER, NULL); 7064eaa4710SRishi Srivatsavai list_create(&bip->bi_links, sizeof (bridge_link_t), 7074eaa4710SRishi Srivatsavai offsetof(bridge_link_t, bl_node)); 7084eaa4710SRishi Srivatsavai cv_init(&bip->bi_linkwait, NULL, CV_DRIVER, NULL); 7094eaa4710SRishi Srivatsavai avl_create(&bip->bi_fwd, fwd_compare, sizeof (bridge_fwd_t), 7104eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node)); 7114eaa4710SRishi Srivatsavai return (bip); 7124eaa4710SRishi Srivatsavai } 7134eaa4710SRishi Srivatsavai 7144eaa4710SRishi Srivatsavai static bridge_inst_t * 7154eaa4710SRishi Srivatsavai bridge_find_name(const char *bridge) 7164eaa4710SRishi Srivatsavai { 7174eaa4710SRishi Srivatsavai bridge_inst_t *bip; 7184eaa4710SRishi Srivatsavai 7194eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 7204eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL; 7214eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) { 7224eaa4710SRishi Srivatsavai if (!(bip->bi_flags & BIF_SHUTDOWN) && 7234eaa4710SRishi Srivatsavai strcmp(bridge, bip->bi_name) == 0) { 7244eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs); 7254eaa4710SRishi Srivatsavai break; 7264eaa4710SRishi Srivatsavai } 7274eaa4710SRishi Srivatsavai } 7284eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 7294eaa4710SRishi Srivatsavai 7304eaa4710SRishi Srivatsavai return (bip); 7314eaa4710SRishi Srivatsavai } 7324eaa4710SRishi Srivatsavai 7334eaa4710SRishi Srivatsavai static int 7344eaa4710SRishi Srivatsavai bridge_create(datalink_id_t linkid, const char *bridge, bridge_inst_t **bipc) 7354eaa4710SRishi Srivatsavai { 7364eaa4710SRishi Srivatsavai bridge_inst_t *bip, *bipnew; 7374eaa4710SRishi Srivatsavai bridge_mac_t *bmp = NULL; 7384eaa4710SRishi Srivatsavai int err; 7394eaa4710SRishi Srivatsavai 7404eaa4710SRishi Srivatsavai *bipc = NULL; 7414eaa4710SRishi Srivatsavai bipnew = inst_alloc(bridge); 7424eaa4710SRishi Srivatsavai 7434eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 7444eaa4710SRishi Srivatsavai lookup_retry: 7454eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL; 7464eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) { 7474eaa4710SRishi Srivatsavai if (strcmp(bridge, bip->bi_name) == 0) 7484eaa4710SRishi Srivatsavai break; 7494eaa4710SRishi Srivatsavai } 7504eaa4710SRishi Srivatsavai 7514eaa4710SRishi Srivatsavai /* This should not take long; if it does, we've got a design problem */ 7524eaa4710SRishi Srivatsavai if (bip != NULL && (bip->bi_flags & BIF_SHUTDOWN)) { 7534eaa4710SRishi Srivatsavai cv_wait(&inst_cv, &inst_lock); 7544eaa4710SRishi Srivatsavai goto lookup_retry; 7554eaa4710SRishi Srivatsavai } 7564eaa4710SRishi Srivatsavai 7574eaa4710SRishi Srivatsavai if (bip != NULL) { 7584eaa4710SRishi Srivatsavai /* We weren't expecting to find anything */ 7594eaa4710SRishi Srivatsavai bip = NULL; 7604eaa4710SRishi Srivatsavai err = EEXIST; 7614eaa4710SRishi Srivatsavai } else { 7624eaa4710SRishi Srivatsavai bip = bipnew; 7634eaa4710SRishi Srivatsavai bipnew = NULL; 7644eaa4710SRishi Srivatsavai list_insert_tail(&inst_list, bip); 7654eaa4710SRishi Srivatsavai } 7664eaa4710SRishi Srivatsavai 7674eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 7684eaa4710SRishi Srivatsavai if (bip == NULL) 7694eaa4710SRishi Srivatsavai goto fail; 7704eaa4710SRishi Srivatsavai 7714eaa4710SRishi Srivatsavai bip->bi_ksp = kstat_setup((kstat_named_t *)&bip->bi_kstats, 7724eaa4710SRishi Srivatsavai inst_kstats_list, Dim(inst_kstats_list), bip->bi_name); 7734eaa4710SRishi Srivatsavai 7744eaa4710SRishi Srivatsavai err = bmac_alloc(bip, &bmp); 7754eaa4710SRishi Srivatsavai if ((bip->bi_mac = bmp) == NULL) 7764eaa4710SRishi Srivatsavai goto fail_create; 7774eaa4710SRishi Srivatsavai 7784eaa4710SRishi Srivatsavai /* 7794eaa4710SRishi Srivatsavai * bm_inst is set, so the timer cannot yank the DLS rug from under us. 7804eaa4710SRishi Srivatsavai * No extra locking is needed here. 7814eaa4710SRishi Srivatsavai */ 7824eaa4710SRishi Srivatsavai if (!(bmp->bm_flags & BMF_DLS)) { 7834eaa4710SRishi Srivatsavai if ((err = dls_devnet_create(bmp->bm_mh, linkid)) != 0) 7844eaa4710SRishi Srivatsavai goto fail_create; 7854eaa4710SRishi Srivatsavai bmp->bm_flags |= BMF_DLS; 7864eaa4710SRishi Srivatsavai } 7874eaa4710SRishi Srivatsavai 7884eaa4710SRishi Srivatsavai bip->bi_dev = makedevice(bridge_major, mac_minor(bmp->bm_mh)); 7894eaa4710SRishi Srivatsavai *bipc = bip; 7904eaa4710SRishi Srivatsavai return (0); 7914eaa4710SRishi Srivatsavai 7924eaa4710SRishi Srivatsavai fail_create: 7934eaa4710SRishi Srivatsavai if (bmp != NULL) 7944eaa4710SRishi Srivatsavai bmac_disconnect(bip->bi_mac); 7954eaa4710SRishi Srivatsavai bipnew = bip; 7964eaa4710SRishi Srivatsavai fail: 7974eaa4710SRishi Srivatsavai ASSERT(bipnew->bi_trilldata == NULL); 7984eaa4710SRishi Srivatsavai bipnew->bi_flags |= BIF_SHUTDOWN; 7994eaa4710SRishi Srivatsavai inst_free(bipnew); 8004eaa4710SRishi Srivatsavai return (err); 8014eaa4710SRishi Srivatsavai } 8024eaa4710SRishi Srivatsavai 8034eaa4710SRishi Srivatsavai static void 8044eaa4710SRishi Srivatsavai bridge_unref(bridge_inst_t *bip) 8054eaa4710SRishi Srivatsavai { 8064eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&bip->bi_refs) == 0) { 8074eaa4710SRishi Srivatsavai ASSERT(bip->bi_flags & BIF_SHUTDOWN); 8084eaa4710SRishi Srivatsavai /* free up mac for reuse before leaving global list */ 8094eaa4710SRishi Srivatsavai if (bip->bi_mac != NULL) 8104eaa4710SRishi Srivatsavai bmac_disconnect(bip->bi_mac); 8114eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 8124eaa4710SRishi Srivatsavai list_remove(&inst_list, bip); 8134eaa4710SRishi Srivatsavai cv_broadcast(&inst_cv); 8144eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 8154eaa4710SRishi Srivatsavai inst_free(bip); 8164eaa4710SRishi Srivatsavai } 8174eaa4710SRishi Srivatsavai } 8184eaa4710SRishi Srivatsavai 8194eaa4710SRishi Srivatsavai /* 8204eaa4710SRishi Srivatsavai * Stream instances are used only for allocating bridges and serving as a 8214eaa4710SRishi Srivatsavai * control node. They serve no data-handling function. 8224eaa4710SRishi Srivatsavai */ 8234eaa4710SRishi Srivatsavai static bridge_stream_t * 8244eaa4710SRishi Srivatsavai stream_alloc(void) 8254eaa4710SRishi Srivatsavai { 8264eaa4710SRishi Srivatsavai bridge_stream_t *bsp; 8274eaa4710SRishi Srivatsavai minor_t mn; 8284eaa4710SRishi Srivatsavai 8294eaa4710SRishi Srivatsavai if ((mn = mac_minor_hold(B_FALSE)) == 0) 8304eaa4710SRishi Srivatsavai return (NULL); 8314eaa4710SRishi Srivatsavai bsp = kmem_zalloc(sizeof (*bsp), KM_SLEEP); 8324eaa4710SRishi Srivatsavai bsp->bs_minor = mn; 8334eaa4710SRishi Srivatsavai return (bsp); 8344eaa4710SRishi Srivatsavai } 8354eaa4710SRishi Srivatsavai 8364eaa4710SRishi Srivatsavai static void 8374eaa4710SRishi Srivatsavai stream_free(bridge_stream_t *bsp) 8384eaa4710SRishi Srivatsavai { 8394eaa4710SRishi Srivatsavai mac_minor_rele(bsp->bs_minor); 8404eaa4710SRishi Srivatsavai kmem_free(bsp, sizeof (*bsp)); 8414eaa4710SRishi Srivatsavai } 8424eaa4710SRishi Srivatsavai 8434eaa4710SRishi Srivatsavai /* Reference hold/release functions for STREAMS-related taskq */ 8444eaa4710SRishi Srivatsavai static void 8454eaa4710SRishi Srivatsavai stream_ref(bridge_stream_t *bsp) 8464eaa4710SRishi Srivatsavai { 8474eaa4710SRishi Srivatsavai mutex_enter(&stream_ref_lock); 8484eaa4710SRishi Srivatsavai bsp->bs_taskq_cnt++; 8494eaa4710SRishi Srivatsavai mutex_exit(&stream_ref_lock); 8504eaa4710SRishi Srivatsavai } 8514eaa4710SRishi Srivatsavai 8524eaa4710SRishi Srivatsavai static void 8534eaa4710SRishi Srivatsavai stream_unref(bridge_stream_t *bsp) 8544eaa4710SRishi Srivatsavai { 8554eaa4710SRishi Srivatsavai mutex_enter(&stream_ref_lock); 8564eaa4710SRishi Srivatsavai if (--bsp->bs_taskq_cnt == 0) 8574eaa4710SRishi Srivatsavai cv_broadcast(&stream_ref_cv); 8584eaa4710SRishi Srivatsavai mutex_exit(&stream_ref_lock); 8594eaa4710SRishi Srivatsavai } 8604eaa4710SRishi Srivatsavai 8614eaa4710SRishi Srivatsavai static void 8624eaa4710SRishi Srivatsavai link_free(bridge_link_t *blp) 8634eaa4710SRishi Srivatsavai { 8644eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 8654eaa4710SRishi Srivatsavai 8664eaa4710SRishi Srivatsavai ASSERT(!(blp->bl_flags & BLF_FREED)); 8674eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_FREED; 8684eaa4710SRishi Srivatsavai if (blp->bl_ksp != NULL) 8694eaa4710SRishi Srivatsavai kstat_delete(blp->bl_ksp); 8704eaa4710SRishi Srivatsavai if (blp->bl_lfailmp != NULL) 8714eaa4710SRishi Srivatsavai freeb(blp->bl_lfailmp); 8724eaa4710SRishi Srivatsavai cv_destroy(&blp->bl_trillwait); 8734eaa4710SRishi Srivatsavai mutex_destroy(&blp->bl_trilllock); 8744eaa4710SRishi Srivatsavai kmem_free(blp, sizeof (*blp)); 8754eaa4710SRishi Srivatsavai /* Don't unreference the bridge until the MAC is closed */ 8764eaa4710SRishi Srivatsavai bridge_unref(bip); 8774eaa4710SRishi Srivatsavai } 8784eaa4710SRishi Srivatsavai 8794eaa4710SRishi Srivatsavai static void 8804eaa4710SRishi Srivatsavai link_unref(bridge_link_t *blp) 8814eaa4710SRishi Srivatsavai { 8824eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&blp->bl_refs) == 0) { 8834eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 8844eaa4710SRishi Srivatsavai 8854eaa4710SRishi Srivatsavai ASSERT(blp->bl_flags & BLF_DELETED); 8864eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 8874eaa4710SRishi Srivatsavai list_remove(&bip->bi_links, blp); 8884eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 8894eaa4710SRishi Srivatsavai if (bip->bi_trilldata != NULL && list_is_empty(&bip->bi_links)) 8904eaa4710SRishi Srivatsavai cv_broadcast(&bip->bi_linkwait); 8914eaa4710SRishi Srivatsavai link_free(blp); 8924eaa4710SRishi Srivatsavai } 8934eaa4710SRishi Srivatsavai } 8944eaa4710SRishi Srivatsavai 8954eaa4710SRishi Srivatsavai static bridge_fwd_t * 8964eaa4710SRishi Srivatsavai fwd_alloc(const uint8_t *addr, uint_t nlinks, uint16_t nick) 8974eaa4710SRishi Srivatsavai { 8984eaa4710SRishi Srivatsavai bridge_fwd_t *bfp; 8994eaa4710SRishi Srivatsavai 9004eaa4710SRishi Srivatsavai bfp = kmem_zalloc(sizeof (*bfp) + (nlinks * sizeof (bridge_link_t *)), 9014eaa4710SRishi Srivatsavai KM_NOSLEEP); 9024eaa4710SRishi Srivatsavai if (bfp != NULL) { 9034eaa4710SRishi Srivatsavai bcopy(addr, bfp->bf_dest, ETHERADDRL); 9044eaa4710SRishi Srivatsavai bfp->bf_lastheard = lbolt; 9054eaa4710SRishi Srivatsavai bfp->bf_maxlinks = nlinks; 9064eaa4710SRishi Srivatsavai bfp->bf_links = (bridge_link_t **)(bfp + 1); 9074eaa4710SRishi Srivatsavai bfp->bf_trill_nick = nick; 9084eaa4710SRishi Srivatsavai } 9094eaa4710SRishi Srivatsavai return (bfp); 9104eaa4710SRishi Srivatsavai } 9114eaa4710SRishi Srivatsavai 9124eaa4710SRishi Srivatsavai static bridge_fwd_t * 9134eaa4710SRishi Srivatsavai fwd_find(bridge_inst_t *bip, const uint8_t *addr, uint16_t vlanid) 9144eaa4710SRishi Srivatsavai { 9154eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *vbfp; 9164eaa4710SRishi Srivatsavai bridge_fwd_t match; 9174eaa4710SRishi Srivatsavai 9184eaa4710SRishi Srivatsavai bcopy(addr, match.bf_dest, ETHERADDRL); 9194eaa4710SRishi Srivatsavai match.bf_flags = 0; 9204eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 9214eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) { 9224eaa4710SRishi Srivatsavai if (bfp->bf_vlanid != vlanid && bfp->bf_vcnt > 0) { 9234eaa4710SRishi Srivatsavai match.bf_vlanid = vlanid; 9244eaa4710SRishi Srivatsavai match.bf_flags = BFF_VLANLOCAL; 9254eaa4710SRishi Srivatsavai vbfp = avl_find(&bip->bi_fwd, &match, NULL); 9264eaa4710SRishi Srivatsavai if (vbfp != NULL) 9274eaa4710SRishi Srivatsavai bfp = vbfp; 9284eaa4710SRishi Srivatsavai } 9294eaa4710SRishi Srivatsavai atomic_inc_uint(&bfp->bf_refs); 9304eaa4710SRishi Srivatsavai } 9314eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 9324eaa4710SRishi Srivatsavai return (bfp); 9334eaa4710SRishi Srivatsavai } 9344eaa4710SRishi Srivatsavai 9354eaa4710SRishi Srivatsavai static void 9364eaa4710SRishi Srivatsavai fwd_free(bridge_fwd_t *bfp) 9374eaa4710SRishi Srivatsavai { 9384eaa4710SRishi Srivatsavai uint_t i; 9394eaa4710SRishi Srivatsavai bridge_inst_t *bip = bfp->bf_links[0]->bl_inst; 9404eaa4710SRishi Srivatsavai 9414eaa4710SRishi Srivatsavai KIDECR(bki_count); 9424eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) 9434eaa4710SRishi Srivatsavai link_unref(bfp->bf_links[i]); 9444eaa4710SRishi Srivatsavai kmem_free(bfp, 9454eaa4710SRishi Srivatsavai sizeof (*bfp) + bfp->bf_maxlinks * sizeof (bridge_link_t *)); 9464eaa4710SRishi Srivatsavai } 9474eaa4710SRishi Srivatsavai 9484eaa4710SRishi Srivatsavai static void 9494eaa4710SRishi Srivatsavai fwd_unref(bridge_fwd_t *bfp) 9504eaa4710SRishi Srivatsavai { 9514eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&bfp->bf_refs) == 0) { 9524eaa4710SRishi Srivatsavai ASSERT(!(bfp->bf_flags & BFF_INTREE)); 9534eaa4710SRishi Srivatsavai fwd_free(bfp); 9544eaa4710SRishi Srivatsavai } 9554eaa4710SRishi Srivatsavai } 9564eaa4710SRishi Srivatsavai 9574eaa4710SRishi Srivatsavai static void 9584eaa4710SRishi Srivatsavai fwd_delete(bridge_fwd_t *bfp) 9594eaa4710SRishi Srivatsavai { 9604eaa4710SRishi Srivatsavai bridge_inst_t *bip; 9614eaa4710SRishi Srivatsavai bridge_fwd_t *bfpzero; 9624eaa4710SRishi Srivatsavai 9634eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_INTREE) { 9644eaa4710SRishi Srivatsavai ASSERT(bfp->bf_nlinks > 0); 9654eaa4710SRishi Srivatsavai bip = bfp->bf_links[0]->bl_inst; 9664eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 9674eaa4710SRishi Srivatsavai /* Another thread could beat us to this */ 9684eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_INTREE) { 9694eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 9704eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 9714eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_VLANLOCAL) { 9724eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_VLANLOCAL; 9734eaa4710SRishi Srivatsavai bfpzero = avl_find(&bip->bi_fwd, bfp, NULL); 9744eaa4710SRishi Srivatsavai if (bfpzero != NULL && bfpzero->bf_vcnt > 0) 9754eaa4710SRishi Srivatsavai bfpzero->bf_vcnt--; 9764eaa4710SRishi Srivatsavai } 9774eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 9784eaa4710SRishi Srivatsavai fwd_unref(bfp); /* no longer in avl tree */ 9794eaa4710SRishi Srivatsavai } else { 9804eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 9814eaa4710SRishi Srivatsavai } 9824eaa4710SRishi Srivatsavai } 9834eaa4710SRishi Srivatsavai } 9844eaa4710SRishi Srivatsavai 9854eaa4710SRishi Srivatsavai static boolean_t 9864eaa4710SRishi Srivatsavai fwd_insert(bridge_inst_t *bip, bridge_fwd_t *bfp) 9874eaa4710SRishi Srivatsavai { 9884eaa4710SRishi Srivatsavai avl_index_t idx; 9894eaa4710SRishi Srivatsavai boolean_t retv; 9904eaa4710SRishi Srivatsavai 9914eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 9924eaa4710SRishi Srivatsavai if (!(bip->bi_flags & BIF_SHUTDOWN) && 9934eaa4710SRishi Srivatsavai avl_numnodes(&bip->bi_fwd) < bip->bi_tablemax && 9944eaa4710SRishi Srivatsavai avl_find(&bip->bi_fwd, bfp, &idx) == NULL) { 9954eaa4710SRishi Srivatsavai avl_insert(&bip->bi_fwd, bfp, idx); 9964eaa4710SRishi Srivatsavai bfp->bf_flags |= BFF_INTREE; 9974eaa4710SRishi Srivatsavai atomic_inc_uint(&bfp->bf_refs); /* avl entry */ 9984eaa4710SRishi Srivatsavai retv = B_TRUE; 9994eaa4710SRishi Srivatsavai } else { 10004eaa4710SRishi Srivatsavai retv = B_FALSE; 10014eaa4710SRishi Srivatsavai } 10024eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 10034eaa4710SRishi Srivatsavai return (retv); 10044eaa4710SRishi Srivatsavai } 10054eaa4710SRishi Srivatsavai 10064eaa4710SRishi Srivatsavai static void 10074eaa4710SRishi Srivatsavai fwd_update_local(bridge_link_t *blp, const uint8_t *oldaddr, 10084eaa4710SRishi Srivatsavai const uint8_t *newaddr) 10094eaa4710SRishi Srivatsavai { 10104eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 10114eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnew; 10124eaa4710SRishi Srivatsavai bridge_fwd_t match; 10134eaa4710SRishi Srivatsavai avl_index_t idx; 10144eaa4710SRishi Srivatsavai boolean_t drop_ref = B_FALSE; 10154eaa4710SRishi Srivatsavai 10164eaa4710SRishi Srivatsavai if (bcmp(oldaddr, newaddr, ETHERADDRL) == 0) 10174eaa4710SRishi Srivatsavai return; 10184eaa4710SRishi Srivatsavai 10194eaa4710SRishi Srivatsavai if (bcmp(oldaddr, zero_addr, ETHERADDRL) == 0) 10204eaa4710SRishi Srivatsavai goto no_old_addr; 10214eaa4710SRishi Srivatsavai 10224eaa4710SRishi Srivatsavai /* 10234eaa4710SRishi Srivatsavai * Find the previous entry, and remove our link from it. 10244eaa4710SRishi Srivatsavai */ 10254eaa4710SRishi Srivatsavai bcopy(oldaddr, match.bf_dest, ETHERADDRL); 10264eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 10274eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) { 10284eaa4710SRishi Srivatsavai int i; 10294eaa4710SRishi Srivatsavai 10304eaa4710SRishi Srivatsavai /* 10314eaa4710SRishi Srivatsavai * See if we're in the list, and remove if so. 10324eaa4710SRishi Srivatsavai */ 10334eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) { 10344eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) { 10354eaa4710SRishi Srivatsavai /* 10364eaa4710SRishi Srivatsavai * We assume writes are atomic, so no special 10374eaa4710SRishi Srivatsavai * MT handling is needed. The list length is 10384eaa4710SRishi Srivatsavai * decremented first, and then we remove 10394eaa4710SRishi Srivatsavai * entries. 10404eaa4710SRishi Srivatsavai */ 10414eaa4710SRishi Srivatsavai bfp->bf_nlinks--; 10424eaa4710SRishi Srivatsavai for (; i < bfp->bf_nlinks; i++) 10434eaa4710SRishi Srivatsavai bfp->bf_links[i] = bfp->bf_links[i + 1]; 10444eaa4710SRishi Srivatsavai drop_ref = B_TRUE; 10454eaa4710SRishi Srivatsavai break; 10464eaa4710SRishi Srivatsavai } 10474eaa4710SRishi Srivatsavai } 10484eaa4710SRishi Srivatsavai /* If no more links, then remove and free up */ 10494eaa4710SRishi Srivatsavai if (bfp->bf_nlinks == 0) { 10504eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 10514eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 10524eaa4710SRishi Srivatsavai } else { 10534eaa4710SRishi Srivatsavai bfp = NULL; 10544eaa4710SRishi Srivatsavai } 10554eaa4710SRishi Srivatsavai } 10564eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 10574eaa4710SRishi Srivatsavai if (bfp != NULL) 10584eaa4710SRishi Srivatsavai fwd_unref(bfp); /* no longer in avl tree */ 10594eaa4710SRishi Srivatsavai 10604eaa4710SRishi Srivatsavai /* 10614eaa4710SRishi Srivatsavai * Now get the new link address and add this link to the list. The 10624eaa4710SRishi Srivatsavai * list should be of length 1 unless the user has configured multiple 10634eaa4710SRishi Srivatsavai * NICs with the same address. (That's an incorrect configuration, but 10644eaa4710SRishi Srivatsavai * we support it anyway.) 10654eaa4710SRishi Srivatsavai */ 10664eaa4710SRishi Srivatsavai no_old_addr: 10674eaa4710SRishi Srivatsavai bfp = NULL; 10684eaa4710SRishi Srivatsavai if ((bip->bi_flags & BIF_SHUTDOWN) || 10694eaa4710SRishi Srivatsavai bcmp(newaddr, zero_addr, ETHERADDRL) == 0) 10704eaa4710SRishi Srivatsavai goto no_new_addr; 10714eaa4710SRishi Srivatsavai 10724eaa4710SRishi Srivatsavai bcopy(newaddr, match.bf_dest, ETHERADDRL); 10734eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 10744eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, &idx)) == NULL) { 10754eaa4710SRishi Srivatsavai bfnew = fwd_alloc(newaddr, 1, RBRIDGE_NICKNAME_NONE); 10764eaa4710SRishi Srivatsavai if (bfnew != NULL) 10774eaa4710SRishi Srivatsavai KIINCR(bki_count); 10784eaa4710SRishi Srivatsavai } else if (bfp->bf_nlinks < bfp->bf_maxlinks) { 10794eaa4710SRishi Srivatsavai /* special case: link fits in existing entry */ 10804eaa4710SRishi Srivatsavai bfnew = bfp; 10814eaa4710SRishi Srivatsavai } else { 10824eaa4710SRishi Srivatsavai bfnew = fwd_alloc(newaddr, bfp->bf_nlinks + 1, 10834eaa4710SRishi Srivatsavai RBRIDGE_NICKNAME_NONE); 10844eaa4710SRishi Srivatsavai if (bfnew != NULL) { 10854eaa4710SRishi Srivatsavai KIINCR(bki_count); 10864eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 10874eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 10884eaa4710SRishi Srivatsavai bfnew->bf_nlinks = bfp->bf_nlinks; 10894eaa4710SRishi Srivatsavai bcopy(bfp->bf_links, bfnew->bf_links, 10904eaa4710SRishi Srivatsavai bfp->bf_nlinks * sizeof (bfp)); 10914eaa4710SRishi Srivatsavai /* reset the idx value due to removal above */ 10924eaa4710SRishi Srivatsavai (void) avl_find(&bip->bi_fwd, &match, &idx); 10934eaa4710SRishi Srivatsavai } 10944eaa4710SRishi Srivatsavai } 10954eaa4710SRishi Srivatsavai 10964eaa4710SRishi Srivatsavai if (bfnew != NULL) { 10974eaa4710SRishi Srivatsavai bfnew->bf_links[bfnew->bf_nlinks++] = blp; 10984eaa4710SRishi Srivatsavai if (drop_ref) 10994eaa4710SRishi Srivatsavai drop_ref = B_FALSE; 11004eaa4710SRishi Srivatsavai else 11014eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); /* bf_links entry */ 11024eaa4710SRishi Srivatsavai 11034eaa4710SRishi Srivatsavai if (bfnew != bfp) { 11044eaa4710SRishi Srivatsavai /* local addresses are not subject to table limits */ 11054eaa4710SRishi Srivatsavai avl_insert(&bip->bi_fwd, bfnew, idx); 11064eaa4710SRishi Srivatsavai bfnew->bf_flags |= (BFF_INTREE | BFF_LOCALADDR); 11074eaa4710SRishi Srivatsavai atomic_inc_uint(&bfnew->bf_refs); /* avl entry */ 11084eaa4710SRishi Srivatsavai } 11094eaa4710SRishi Srivatsavai } 11104eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 11114eaa4710SRishi Srivatsavai 11124eaa4710SRishi Srivatsavai no_new_addr: 11134eaa4710SRishi Srivatsavai /* 11144eaa4710SRishi Srivatsavai * If we found an existing entry and we replaced it with a new one, 11154eaa4710SRishi Srivatsavai * then drop the table reference from the old one. We removed it from 11164eaa4710SRishi Srivatsavai * the AVL tree above. 11174eaa4710SRishi Srivatsavai */ 11184eaa4710SRishi Srivatsavai if (bfnew != NULL && bfp != NULL && bfnew != bfp) 11194eaa4710SRishi Srivatsavai fwd_unref(bfp); 11204eaa4710SRishi Srivatsavai 11214eaa4710SRishi Srivatsavai /* Account for removed entry. */ 11224eaa4710SRishi Srivatsavai if (drop_ref) 11234eaa4710SRishi Srivatsavai link_unref(blp); 11244eaa4710SRishi Srivatsavai } 11254eaa4710SRishi Srivatsavai 11264eaa4710SRishi Srivatsavai static void 11274eaa4710SRishi Srivatsavai bridge_new_unicst(bridge_link_t *blp) 11284eaa4710SRishi Srivatsavai { 11294eaa4710SRishi Srivatsavai uint8_t new_mac[ETHERADDRL]; 11304eaa4710SRishi Srivatsavai 11314eaa4710SRishi Srivatsavai mac_unicast_primary_get(blp->bl_mh, new_mac); 11324eaa4710SRishi Srivatsavai fwd_update_local(blp, blp->bl_local_mac, new_mac); 11334eaa4710SRishi Srivatsavai bcopy(new_mac, blp->bl_local_mac, ETHERADDRL); 11344eaa4710SRishi Srivatsavai } 11354eaa4710SRishi Srivatsavai 11364eaa4710SRishi Srivatsavai /* 11374eaa4710SRishi Srivatsavai * We must shut down a link prior to freeing it, and doing that requires 11384eaa4710SRishi Srivatsavai * blocking to wait for running MAC threads while holding a reference. This is 11394eaa4710SRishi Srivatsavai * run from a taskq to accomplish proper link shutdown followed by reference 11404eaa4710SRishi Srivatsavai * drop. 11414eaa4710SRishi Srivatsavai */ 11424eaa4710SRishi Srivatsavai static void 11434eaa4710SRishi Srivatsavai link_shutdown(void *arg) 11444eaa4710SRishi Srivatsavai { 11454eaa4710SRishi Srivatsavai bridge_link_t *blp = arg; 11464eaa4710SRishi Srivatsavai mac_handle_t mh = blp->bl_mh; 11474eaa4710SRishi Srivatsavai bridge_inst_t *bip; 11484eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext; 11494eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge; 11504eaa4710SRishi Srivatsavai int i; 11514eaa4710SRishi Srivatsavai 11524eaa4710SRishi Srivatsavai /* 11534eaa4710SRishi Srivatsavai * This link is being destroyed. Notify TRILL now that it's no longer 11544eaa4710SRishi Srivatsavai * possible to send packets. Data packets may still arrive until TRILL 11554eaa4710SRishi Srivatsavai * calls bridge_trill_lnunref. 11564eaa4710SRishi Srivatsavai */ 11574eaa4710SRishi Srivatsavai if (blp->bl_trilldata != NULL) 11584eaa4710SRishi Srivatsavai trill_lndstr_fn(blp->bl_trilldata, blp); 11594eaa4710SRishi Srivatsavai 11604eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_PROM_ADDED) 11614eaa4710SRishi Srivatsavai (void) mac_promisc_remove(blp->bl_mphp); 11624eaa4710SRishi Srivatsavai 11634eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_SET_BRIDGE) 11644eaa4710SRishi Srivatsavai mac_bridge_clear(mh, (mac_handle_t)blp); 11654eaa4710SRishi Srivatsavai 11664eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_MARGIN_ADDED) { 1167*4249d844SRishi Srivatsavai (void) mac_notify_remove(blp->bl_mnh, B_TRUE); 11684eaa4710SRishi Srivatsavai (void) mac_margin_remove(mh, blp->bl_margin); 11694eaa4710SRishi Srivatsavai } 11704eaa4710SRishi Srivatsavai 11714eaa4710SRishi Srivatsavai /* Tell the clients the real link state when we leave */ 11724eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh, 11734eaa4710SRishi Srivatsavai mac_stat_get(blp->bl_mh, MAC_STAT_LOWLINK_STATE)); 11744eaa4710SRishi Srivatsavai 11754eaa4710SRishi Srivatsavai /* Destroy all of the forwarding entries related to this link */ 11764eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 11774eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node)); 11784eaa4710SRishi Srivatsavai bip = blp->bl_inst; 11794eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 11804eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd); 11814eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 11824eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 11834eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) { 11844eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) 11854eaa4710SRishi Srivatsavai break; 11864eaa4710SRishi Srivatsavai } 11874eaa4710SRishi Srivatsavai if (i >= bfp->bf_nlinks) 11884eaa4710SRishi Srivatsavai continue; 11894eaa4710SRishi Srivatsavai if (bfp->bf_nlinks > 1) { 11904eaa4710SRishi Srivatsavai /* note that this can't be the last reference */ 11914eaa4710SRishi Srivatsavai link_unref(blp); 11924eaa4710SRishi Srivatsavai bfp->bf_nlinks--; 11934eaa4710SRishi Srivatsavai for (; i < bfp->bf_nlinks; i++) 11944eaa4710SRishi Srivatsavai bfp->bf_links[i] = bfp->bf_links[i + 1]; 11954eaa4710SRishi Srivatsavai } else { 11964eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE); 11974eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 11984eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 11994eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp); 12004eaa4710SRishi Srivatsavai } 12014eaa4710SRishi Srivatsavai } 12024eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 12034eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge); 12044eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 12054eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp); 12064eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp); 12074eaa4710SRishi Srivatsavai fwd_unref(bfp); 12084eaa4710SRishi Srivatsavai } 12094eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge); 12104eaa4710SRishi Srivatsavai 12114eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_CLIENT_OPEN) 12124eaa4710SRishi Srivatsavai mac_client_close(blp->bl_mch, 0); 12134eaa4710SRishi Srivatsavai 12144eaa4710SRishi Srivatsavai mac_close(mh); 12154eaa4710SRishi Srivatsavai 12164eaa4710SRishi Srivatsavai /* 12174eaa4710SRishi Srivatsavai * We are now completely removed from the active list, so drop the 12184eaa4710SRishi Srivatsavai * reference (see bridge_add_link). 12194eaa4710SRishi Srivatsavai */ 12204eaa4710SRishi Srivatsavai link_unref(blp); 12214eaa4710SRishi Srivatsavai } 12224eaa4710SRishi Srivatsavai 12234eaa4710SRishi Srivatsavai static void 12244eaa4710SRishi Srivatsavai shutdown_inst(bridge_inst_t *bip) 12254eaa4710SRishi Srivatsavai { 12264eaa4710SRishi Srivatsavai bridge_link_t *blp, *blnext; 12274eaa4710SRishi Srivatsavai bridge_fwd_t *bfp; 12284eaa4710SRishi Srivatsavai 12294eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 12304eaa4710SRishi Srivatsavai if (bip->bi_flags & BIF_SHUTDOWN) { 12314eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 12324eaa4710SRishi Srivatsavai return; 12334eaa4710SRishi Srivatsavai } 12344eaa4710SRishi Srivatsavai 12354eaa4710SRishi Srivatsavai /* 12364eaa4710SRishi Srivatsavai * Once on the inst_list, the bridge instance must not leave that list 12374eaa4710SRishi Srivatsavai * without having the shutdown flag set first. When the shutdown flag 12384eaa4710SRishi Srivatsavai * is set, we own the list reference, so we must drop it before 12394eaa4710SRishi Srivatsavai * returning. 12404eaa4710SRishi Srivatsavai */ 12414eaa4710SRishi Srivatsavai bip->bi_flags |= BIF_SHUTDOWN; 12424eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 12434eaa4710SRishi Srivatsavai 12444eaa4710SRishi Srivatsavai bip->bi_control = NULL; 12454eaa4710SRishi Srivatsavai 12464eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 12474eaa4710SRishi Srivatsavai blnext = list_head(&bip->bi_links); 12484eaa4710SRishi Srivatsavai while ((blp = blnext) != NULL) { 12494eaa4710SRishi Srivatsavai blnext = list_next(&bip->bi_links, blp); 12504eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED)) { 12514eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_DELETED; 12524eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown, 12534eaa4710SRishi Srivatsavai blp, DDI_SLEEP); 12544eaa4710SRishi Srivatsavai } 12554eaa4710SRishi Srivatsavai } 12564eaa4710SRishi Srivatsavai while ((bfp = avl_first(&bip->bi_fwd)) != NULL) { 12574eaa4710SRishi Srivatsavai atomic_inc_uint(&bfp->bf_refs); 12584eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 12594eaa4710SRishi Srivatsavai fwd_delete(bfp); 12604eaa4710SRishi Srivatsavai fwd_unref(bfp); 12614eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 12624eaa4710SRishi Srivatsavai } 12634eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 12644eaa4710SRishi Srivatsavai 12654eaa4710SRishi Srivatsavai /* 12664eaa4710SRishi Srivatsavai * This bridge is being destroyed. Notify TRILL once all of the 12674eaa4710SRishi Srivatsavai * links are all gone. 12684eaa4710SRishi Srivatsavai */ 12694eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 12704eaa4710SRishi Srivatsavai while (bip->bi_trilldata != NULL && !list_is_empty(&bip->bi_links)) 12714eaa4710SRishi Srivatsavai cv_wait(&bip->bi_linkwait, &inst_lock); 12724eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 12734eaa4710SRishi Srivatsavai if (bip->bi_trilldata != NULL) 12744eaa4710SRishi Srivatsavai trill_brdstr_fn(bip->bi_trilldata, bip); 12754eaa4710SRishi Srivatsavai 12764eaa4710SRishi Srivatsavai bridge_unref(bip); 12774eaa4710SRishi Srivatsavai } 12784eaa4710SRishi Srivatsavai 12794eaa4710SRishi Srivatsavai /* 12804eaa4710SRishi Srivatsavai * This is called once by the TRILL module when it starts up. It just sets the 12814eaa4710SRishi Srivatsavai * global TRILL callback function pointers -- data transmit/receive and bridge 12824eaa4710SRishi Srivatsavai * and link destroy notification. There's only one TRILL module, so only one 12834eaa4710SRishi Srivatsavai * registration is needed. 12844eaa4710SRishi Srivatsavai * 12854eaa4710SRishi Srivatsavai * TRILL should call this function with NULL pointers before unloading. It 12864eaa4710SRishi Srivatsavai * must not do so before dropping all references to bridges and links. We 12874eaa4710SRishi Srivatsavai * assert that this is true on debug builds. 12884eaa4710SRishi Srivatsavai */ 12894eaa4710SRishi Srivatsavai void 12904eaa4710SRishi Srivatsavai bridge_trill_register_cb(trill_recv_pkt_t recv_fn, trill_encap_pkt_t encap_fn, 12914eaa4710SRishi Srivatsavai trill_br_dstr_t brdstr_fn, trill_ln_dstr_t lndstr_fn) 12924eaa4710SRishi Srivatsavai { 12934eaa4710SRishi Srivatsavai #ifdef DEBUG 12944eaa4710SRishi Srivatsavai if (recv_fn == NULL && trill_recv_fn != NULL) { 12954eaa4710SRishi Srivatsavai bridge_inst_t *bip; 12964eaa4710SRishi Srivatsavai bridge_link_t *blp; 12974eaa4710SRishi Srivatsavai 12984eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 12994eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL; 13004eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) { 13014eaa4710SRishi Srivatsavai ASSERT(bip->bi_trilldata == NULL); 13024eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 13034eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 13044eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 13054eaa4710SRishi Srivatsavai ASSERT(blp->bl_trilldata == NULL); 13064eaa4710SRishi Srivatsavai } 13074eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 13084eaa4710SRishi Srivatsavai } 13094eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 13104eaa4710SRishi Srivatsavai } 13114eaa4710SRishi Srivatsavai #endif 13124eaa4710SRishi Srivatsavai trill_recv_fn = recv_fn; 13134eaa4710SRishi Srivatsavai trill_encap_fn = encap_fn; 13144eaa4710SRishi Srivatsavai trill_brdstr_fn = brdstr_fn; 13154eaa4710SRishi Srivatsavai trill_lndstr_fn = lndstr_fn; 13164eaa4710SRishi Srivatsavai } 13174eaa4710SRishi Srivatsavai 13184eaa4710SRishi Srivatsavai /* 13194eaa4710SRishi Srivatsavai * This registers the TRILL instance pointer with a bridge. Before this 13204eaa4710SRishi Srivatsavai * pointer is set, the forwarding, TRILL receive, and bridge destructor 13214eaa4710SRishi Srivatsavai * functions won't be called. 13224eaa4710SRishi Srivatsavai * 13234eaa4710SRishi Srivatsavai * TRILL holds a reference on a bridge with this call. It must free the 13244eaa4710SRishi Srivatsavai * reference by calling the unregister function below. 13254eaa4710SRishi Srivatsavai */ 13264eaa4710SRishi Srivatsavai bridge_inst_t * 13274eaa4710SRishi Srivatsavai bridge_trill_brref(const char *bname, void *ptr) 13284eaa4710SRishi Srivatsavai { 13294eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN]; 13304eaa4710SRishi Srivatsavai bridge_inst_t *bip; 13314eaa4710SRishi Srivatsavai 13324eaa4710SRishi Srivatsavai (void) snprintf(bridge, MAXLINKNAMELEN, "%s0", bname); 13334eaa4710SRishi Srivatsavai bip = bridge_find_name(bridge); 13344eaa4710SRishi Srivatsavai if (bip != NULL) { 13354eaa4710SRishi Srivatsavai ASSERT(bip->bi_trilldata == NULL && ptr != NULL); 13364eaa4710SRishi Srivatsavai bip->bi_trilldata = ptr; 13374eaa4710SRishi Srivatsavai } 13384eaa4710SRishi Srivatsavai return (bip); 13394eaa4710SRishi Srivatsavai } 13404eaa4710SRishi Srivatsavai 13414eaa4710SRishi Srivatsavai void 13424eaa4710SRishi Srivatsavai bridge_trill_brunref(bridge_inst_t *bip) 13434eaa4710SRishi Srivatsavai { 13444eaa4710SRishi Srivatsavai ASSERT(bip->bi_trilldata != NULL); 13454eaa4710SRishi Srivatsavai bip->bi_trilldata = NULL; 13464eaa4710SRishi Srivatsavai bridge_unref(bip); 13474eaa4710SRishi Srivatsavai } 13484eaa4710SRishi Srivatsavai 13494eaa4710SRishi Srivatsavai /* 13504eaa4710SRishi Srivatsavai * TRILL calls this function when referencing a particular link on a bridge. 13514eaa4710SRishi Srivatsavai * 13524eaa4710SRishi Srivatsavai * It holds a reference on the link, so TRILL must clear out the reference when 13534eaa4710SRishi Srivatsavai * it's done with the link (on unbinding). 13544eaa4710SRishi Srivatsavai */ 13554eaa4710SRishi Srivatsavai bridge_link_t * 13564eaa4710SRishi Srivatsavai bridge_trill_lnref(bridge_inst_t *bip, datalink_id_t linkid, void *ptr) 13574eaa4710SRishi Srivatsavai { 13584eaa4710SRishi Srivatsavai bridge_link_t *blp; 13594eaa4710SRishi Srivatsavai 13604eaa4710SRishi Srivatsavai ASSERT(ptr != NULL); 13614eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 13624eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 13634eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 13644eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED) && 13654eaa4710SRishi Srivatsavai blp->bl_linkid == linkid && blp->bl_trilldata == NULL) { 13664eaa4710SRishi Srivatsavai blp->bl_trilldata = ptr; 13674eaa4710SRishi Srivatsavai blp->bl_flags &= ~BLF_TRILLACTIVE; 13684eaa4710SRishi Srivatsavai (void) memset(blp->bl_afs, 0, sizeof (blp->bl_afs)); 13694eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); 13704eaa4710SRishi Srivatsavai break; 13714eaa4710SRishi Srivatsavai } 13724eaa4710SRishi Srivatsavai } 13734eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 13744eaa4710SRishi Srivatsavai return (blp); 13754eaa4710SRishi Srivatsavai } 13764eaa4710SRishi Srivatsavai 13774eaa4710SRishi Srivatsavai void 13784eaa4710SRishi Srivatsavai bridge_trill_lnunref(bridge_link_t *blp) 13794eaa4710SRishi Srivatsavai { 13804eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 13814eaa4710SRishi Srivatsavai ASSERT(blp->bl_trilldata != NULL); 13824eaa4710SRishi Srivatsavai blp->bl_trilldata = NULL; 13834eaa4710SRishi Srivatsavai blp->bl_flags &= ~BLF_TRILLACTIVE; 13844eaa4710SRishi Srivatsavai while (blp->bl_trillthreads > 0) 13854eaa4710SRishi Srivatsavai cv_wait(&blp->bl_trillwait, &blp->bl_trilllock); 13864eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 13874eaa4710SRishi Srivatsavai (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs)); 13884eaa4710SRishi Srivatsavai link_unref(blp); 13894eaa4710SRishi Srivatsavai } 13904eaa4710SRishi Srivatsavai 13914eaa4710SRishi Srivatsavai /* 13924eaa4710SRishi Srivatsavai * This periodic timer performs three functions: 13934eaa4710SRishi Srivatsavai * 1. It scans the list of learned forwarding entries, and removes ones that 13944eaa4710SRishi Srivatsavai * haven't been heard from in a while. The time limit is backed down if 13954eaa4710SRishi Srivatsavai * we're above the configured table limit. 13964eaa4710SRishi Srivatsavai * 2. It walks the links and decays away the bl_learns counter. 13974eaa4710SRishi Srivatsavai * 3. It scans the observability node entries looking for ones that can be 13984eaa4710SRishi Srivatsavai * freed up. 13994eaa4710SRishi Srivatsavai */ 14004eaa4710SRishi Srivatsavai /* ARGSUSED */ 14014eaa4710SRishi Srivatsavai static void 14024eaa4710SRishi Srivatsavai bridge_timer(void *arg) 14034eaa4710SRishi Srivatsavai { 14044eaa4710SRishi Srivatsavai bridge_inst_t *bip; 14054eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext; 14064eaa4710SRishi Srivatsavai bridge_mac_t *bmp, *bmnext; 14074eaa4710SRishi Srivatsavai bridge_link_t *blp; 14084eaa4710SRishi Srivatsavai int err; 14094eaa4710SRishi Srivatsavai datalink_id_t tmpid; 14104eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge; 14114eaa4710SRishi Srivatsavai clock_t age_limit; 14124eaa4710SRishi Srivatsavai uint32_t ldecay; 14134eaa4710SRishi Srivatsavai 14144eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 14154eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node)); 14164eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 14174eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL; 14184eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) { 14194eaa4710SRishi Srivatsavai if (bip->bi_flags & BIF_SHUTDOWN) 14204eaa4710SRishi Srivatsavai continue; 14214eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 14224eaa4710SRishi Srivatsavai /* compute scaled maximum age based on table limit */ 14234eaa4710SRishi Srivatsavai if (avl_numnodes(&bip->bi_fwd) > bip->bi_tablemax) 14244eaa4710SRishi Srivatsavai bip->bi_tshift++; 14254eaa4710SRishi Srivatsavai else 14264eaa4710SRishi Srivatsavai bip->bi_tshift = 0; 14274eaa4710SRishi Srivatsavai if ((age_limit = bridge_fwd_age >> bip->bi_tshift) == 0) { 14284eaa4710SRishi Srivatsavai if (bip->bi_tshift != 0) 14294eaa4710SRishi Srivatsavai bip->bi_tshift--; 14304eaa4710SRishi Srivatsavai age_limit = 1; 14314eaa4710SRishi Srivatsavai } 14324eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd); 14334eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 14344eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 14354eaa4710SRishi Srivatsavai if (!(bfp->bf_flags & BFF_LOCALADDR) && 14364eaa4710SRishi Srivatsavai (lbolt - bfp->bf_lastheard) > age_limit) { 14374eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE); 14384eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 14394eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 14404eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp); 14414eaa4710SRishi Srivatsavai } 14424eaa4710SRishi Srivatsavai } 14434eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 14444eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 14454eaa4710SRishi Srivatsavai ldecay = mac_get_ldecay(blp->bl_mh); 14464eaa4710SRishi Srivatsavai if (ldecay >= blp->bl_learns) 14474eaa4710SRishi Srivatsavai blp->bl_learns = 0; 14484eaa4710SRishi Srivatsavai else 14494eaa4710SRishi Srivatsavai atomic_add_int(&blp->bl_learns, -(int)ldecay); 14504eaa4710SRishi Srivatsavai } 14514eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 14524eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge); 14534eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 14544eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp); 14554eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp); 14564eaa4710SRishi Srivatsavai KIINCR(bki_expire); 14574eaa4710SRishi Srivatsavai fwd_unref(bfp); /* drop tree reference */ 14584eaa4710SRishi Srivatsavai } 14594eaa4710SRishi Srivatsavai } 14604eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 14614eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge); 14624eaa4710SRishi Srivatsavai 14634eaa4710SRishi Srivatsavai /* 14644eaa4710SRishi Srivatsavai * Scan the bridge_mac_t entries and try to free up the ones that are 14654eaa4710SRishi Srivatsavai * no longer active. This must be done by polling, as neither DLS nor 14664eaa4710SRishi Srivatsavai * MAC provides a driver any sort of positive control over clients. 14674eaa4710SRishi Srivatsavai */ 14684eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_WRITER); 14694eaa4710SRishi Srivatsavai bmnext = list_head(&bmac_list); 14704eaa4710SRishi Srivatsavai while ((bmp = bmnext) != NULL) { 14714eaa4710SRishi Srivatsavai bmnext = list_next(&bmac_list, bmp); 14724eaa4710SRishi Srivatsavai 14734eaa4710SRishi Srivatsavai /* ignore active bridges */ 14744eaa4710SRishi Srivatsavai if (bmp->bm_inst != NULL) 14754eaa4710SRishi Srivatsavai continue; 14764eaa4710SRishi Srivatsavai 14774eaa4710SRishi Srivatsavai if (bmp->bm_flags & BMF_DLS) { 14784eaa4710SRishi Srivatsavai err = dls_devnet_destroy(bmp->bm_mh, &tmpid, B_FALSE); 14794eaa4710SRishi Srivatsavai ASSERT(err == 0 || err == EBUSY); 14804eaa4710SRishi Srivatsavai if (err == 0) 14814eaa4710SRishi Srivatsavai bmp->bm_flags &= ~BMF_DLS; 14824eaa4710SRishi Srivatsavai } 14834eaa4710SRishi Srivatsavai 14844eaa4710SRishi Srivatsavai if (!(bmp->bm_flags & BMF_DLS)) { 14854eaa4710SRishi Srivatsavai err = mac_unregister(bmp->bm_mh); 14864eaa4710SRishi Srivatsavai ASSERT(err == 0 || err == EBUSY); 14874eaa4710SRishi Srivatsavai if (err == 0) { 14884eaa4710SRishi Srivatsavai list_remove(&bmac_list, bmp); 14894eaa4710SRishi Srivatsavai kmem_free(bmp, sizeof (*bmp)); 14904eaa4710SRishi Srivatsavai } 14914eaa4710SRishi Srivatsavai } 14924eaa4710SRishi Srivatsavai } 14934eaa4710SRishi Srivatsavai if (list_is_empty(&bmac_list)) { 14944eaa4710SRishi Srivatsavai bridge_timerid = 0; 14954eaa4710SRishi Srivatsavai } else { 14964eaa4710SRishi Srivatsavai bridge_timerid = timeout(bridge_timer, NULL, 14974eaa4710SRishi Srivatsavai bridge_scan_interval); 14984eaa4710SRishi Srivatsavai } 14994eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 15004eaa4710SRishi Srivatsavai } 15014eaa4710SRishi Srivatsavai 15024eaa4710SRishi Srivatsavai static int 15034eaa4710SRishi Srivatsavai bridge_open(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp) 15044eaa4710SRishi Srivatsavai { 15054eaa4710SRishi Srivatsavai bridge_stream_t *bsp; 15064eaa4710SRishi Srivatsavai 15074eaa4710SRishi Srivatsavai if (rq->q_ptr != NULL) 15084eaa4710SRishi Srivatsavai return (0); 15094eaa4710SRishi Srivatsavai 15104eaa4710SRishi Srivatsavai if (sflag & MODOPEN) 15114eaa4710SRishi Srivatsavai return (EINVAL); 15124eaa4710SRishi Srivatsavai 15134eaa4710SRishi Srivatsavai /* 15144eaa4710SRishi Srivatsavai * Check the minor node number being opened. This tells us which 15154eaa4710SRishi Srivatsavai * bridge instance the user wants. 15164eaa4710SRishi Srivatsavai */ 15174eaa4710SRishi Srivatsavai if (getminor(*devp) != 0) { 15184eaa4710SRishi Srivatsavai /* 15194eaa4710SRishi Srivatsavai * This is a regular DLPI stream for snoop or the like. 15204eaa4710SRishi Srivatsavai * Redirect it through DLD. 15214eaa4710SRishi Srivatsavai */ 15224eaa4710SRishi Srivatsavai rq->q_qinfo = &bridge_dld_rinit; 15234eaa4710SRishi Srivatsavai OTHERQ(rq)->q_qinfo = &bridge_dld_winit; 15244eaa4710SRishi Srivatsavai return (dld_open(rq, devp, oflag, sflag, credp)); 15254eaa4710SRishi Srivatsavai } else { 15264eaa4710SRishi Srivatsavai /* 15274eaa4710SRishi Srivatsavai * Allocate the bridge control stream structure. 15284eaa4710SRishi Srivatsavai */ 15294eaa4710SRishi Srivatsavai if ((bsp = stream_alloc()) == NULL) 15304eaa4710SRishi Srivatsavai return (ENOSR); 15314eaa4710SRishi Srivatsavai rq->q_ptr = WR(rq)->q_ptr = (caddr_t)bsp; 15324eaa4710SRishi Srivatsavai bsp->bs_wq = WR(rq); 15334eaa4710SRishi Srivatsavai *devp = makedevice(getmajor(*devp), bsp->bs_minor); 15344eaa4710SRishi Srivatsavai qprocson(rq); 15354eaa4710SRishi Srivatsavai return (0); 15364eaa4710SRishi Srivatsavai } 15374eaa4710SRishi Srivatsavai } 15384eaa4710SRishi Srivatsavai 15394eaa4710SRishi Srivatsavai /* 15404eaa4710SRishi Srivatsavai * This is used only for bridge control streams. DLPI goes through dld 15414eaa4710SRishi Srivatsavai * instead. 15424eaa4710SRishi Srivatsavai */ 15434eaa4710SRishi Srivatsavai static int 15444eaa4710SRishi Srivatsavai bridge_close(queue_t *rq) 15454eaa4710SRishi Srivatsavai { 15464eaa4710SRishi Srivatsavai bridge_stream_t *bsp = rq->q_ptr; 15474eaa4710SRishi Srivatsavai bridge_inst_t *bip; 15484eaa4710SRishi Srivatsavai 15494eaa4710SRishi Srivatsavai /* 15504eaa4710SRishi Srivatsavai * Wait for any stray taskq (add/delete link) entries related to this 15514eaa4710SRishi Srivatsavai * stream to leave the system. 15524eaa4710SRishi Srivatsavai */ 15534eaa4710SRishi Srivatsavai mutex_enter(&stream_ref_lock); 15544eaa4710SRishi Srivatsavai while (bsp->bs_taskq_cnt != 0) 15554eaa4710SRishi Srivatsavai cv_wait(&stream_ref_cv, &stream_ref_lock); 15564eaa4710SRishi Srivatsavai mutex_exit(&stream_ref_lock); 15574eaa4710SRishi Srivatsavai 15584eaa4710SRishi Srivatsavai qprocsoff(rq); 15594eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) != NULL) 15604eaa4710SRishi Srivatsavai shutdown_inst(bip); 15614eaa4710SRishi Srivatsavai rq->q_ptr = WR(rq)->q_ptr = NULL; 15624eaa4710SRishi Srivatsavai stream_free(bsp); 15634eaa4710SRishi Srivatsavai if (bip != NULL) 15644eaa4710SRishi Srivatsavai bridge_unref(bip); 15654eaa4710SRishi Srivatsavai 15664eaa4710SRishi Srivatsavai return (0); 15674eaa4710SRishi Srivatsavai } 15684eaa4710SRishi Srivatsavai 15694eaa4710SRishi Srivatsavai static void 15704eaa4710SRishi Srivatsavai bridge_learn(bridge_link_t *blp, const uint8_t *saddr, uint16_t ingress_nick, 15714eaa4710SRishi Srivatsavai uint16_t vlanid) 15724eaa4710SRishi Srivatsavai { 15734eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 15744eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfpnew; 15754eaa4710SRishi Srivatsavai int i; 15764eaa4710SRishi Srivatsavai boolean_t replaced = B_FALSE; 15774eaa4710SRishi Srivatsavai 15784eaa4710SRishi Srivatsavai /* Ignore multi-destination address used as source; it's nonsense. */ 15794eaa4710SRishi Srivatsavai if (*saddr & 1) 15804eaa4710SRishi Srivatsavai return; 15814eaa4710SRishi Srivatsavai 15824eaa4710SRishi Srivatsavai /* 15834eaa4710SRishi Srivatsavai * If the source is known, then check whether it belongs on this link. 15844eaa4710SRishi Srivatsavai * If not, and this isn't a fixed local address, then we've detected a 15854eaa4710SRishi Srivatsavai * move. If it's not known, learn it. 15864eaa4710SRishi Srivatsavai */ 15874eaa4710SRishi Srivatsavai if ((bfp = fwd_find(bip, saddr, vlanid)) != NULL) { 15884eaa4710SRishi Srivatsavai /* 15894eaa4710SRishi Srivatsavai * If the packet has a fixed local source address, then there's 15904eaa4710SRishi Srivatsavai * nothing we can learn. We must quit. If this was a received 15914eaa4710SRishi Srivatsavai * packet, then the sender has stolen our address, but there's 15924eaa4710SRishi Srivatsavai * nothing we can do. If it's a transmitted packet, then 15934eaa4710SRishi Srivatsavai * that's the normal case. 15944eaa4710SRishi Srivatsavai */ 15954eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR) { 15964eaa4710SRishi Srivatsavai fwd_unref(bfp); 15974eaa4710SRishi Srivatsavai return; 15984eaa4710SRishi Srivatsavai } 15994eaa4710SRishi Srivatsavai 16004eaa4710SRishi Srivatsavai /* 16014eaa4710SRishi Srivatsavai * Check if the link (and TRILL sender, if any) being used is 16024eaa4710SRishi Srivatsavai * among the ones registered for this address. If so, then 16034eaa4710SRishi Srivatsavai * this is information that we already know. 16044eaa4710SRishi Srivatsavai */ 16054eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick == ingress_nick) { 16064eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) { 16074eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) { 16084eaa4710SRishi Srivatsavai bfp->bf_lastheard = lbolt; 16094eaa4710SRishi Srivatsavai fwd_unref(bfp); 16104eaa4710SRishi Srivatsavai return; 16114eaa4710SRishi Srivatsavai } 16124eaa4710SRishi Srivatsavai } 16134eaa4710SRishi Srivatsavai } 16144eaa4710SRishi Srivatsavai } 16154eaa4710SRishi Srivatsavai 16164eaa4710SRishi Srivatsavai /* 16174eaa4710SRishi Srivatsavai * Note that we intentionally "unlearn" things that appear to be under 16184eaa4710SRishi Srivatsavai * attack on this link. The forwarding cache is a negative thing for 16194eaa4710SRishi Srivatsavai * security -- it disables reachability as a performance optimization 16204eaa4710SRishi Srivatsavai * -- so leaving out entries optimizes for success and defends against 16214eaa4710SRishi Srivatsavai * the attack. Thus, the bare increment without a check in the delete 16224eaa4710SRishi Srivatsavai * code above is right. (And it's ok if we skid over the limit a 16234eaa4710SRishi Srivatsavai * little, so there's no syncronization needed on the test.) 16244eaa4710SRishi Srivatsavai */ 16254eaa4710SRishi Srivatsavai if (blp->bl_learns >= mac_get_llimit(blp->bl_mh)) { 16264eaa4710SRishi Srivatsavai if (bfp != NULL) { 16274eaa4710SRishi Srivatsavai if (bfp->bf_vcnt == 0) 16284eaa4710SRishi Srivatsavai fwd_delete(bfp); 16294eaa4710SRishi Srivatsavai fwd_unref(bfp); 16304eaa4710SRishi Srivatsavai } 16314eaa4710SRishi Srivatsavai return; 16324eaa4710SRishi Srivatsavai } 16334eaa4710SRishi Srivatsavai 16344eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_learns); 16354eaa4710SRishi Srivatsavai 16364eaa4710SRishi Srivatsavai if ((bfpnew = fwd_alloc(saddr, 1, ingress_nick)) == NULL) { 16374eaa4710SRishi Srivatsavai if (bfp != NULL) 16384eaa4710SRishi Srivatsavai fwd_unref(bfp); 16394eaa4710SRishi Srivatsavai return; 16404eaa4710SRishi Srivatsavai } 16414eaa4710SRishi Srivatsavai KIINCR(bki_count); 16424eaa4710SRishi Srivatsavai 16434eaa4710SRishi Srivatsavai if (bfp != NULL) { 16444eaa4710SRishi Srivatsavai /* 16454eaa4710SRishi Srivatsavai * If this is a new destination for the same VLAN, then delete 16464eaa4710SRishi Srivatsavai * so that we can update. If it's a different VLAN, then we're 16474eaa4710SRishi Srivatsavai * not going to delete the original. Split off instead into an 16484eaa4710SRishi Srivatsavai * IVL entry. 16494eaa4710SRishi Srivatsavai */ 16504eaa4710SRishi Srivatsavai if (bfp->bf_vlanid == vlanid) { 16514eaa4710SRishi Srivatsavai /* save the count of IVL duplicates */ 16524eaa4710SRishi Srivatsavai bfpnew->bf_vcnt = bfp->bf_vcnt; 16534eaa4710SRishi Srivatsavai 16544eaa4710SRishi Srivatsavai /* entry deletes count as learning events */ 16554eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_learns); 16564eaa4710SRishi Srivatsavai 16574eaa4710SRishi Srivatsavai /* destroy and create anew; node moved */ 16584eaa4710SRishi Srivatsavai fwd_delete(bfp); 16594eaa4710SRishi Srivatsavai replaced = B_TRUE; 16604eaa4710SRishi Srivatsavai KIINCR(bki_moved); 16614eaa4710SRishi Srivatsavai } else { 16624eaa4710SRishi Srivatsavai bfp->bf_vcnt++; 16634eaa4710SRishi Srivatsavai bfpnew->bf_flags |= BFF_VLANLOCAL; 16644eaa4710SRishi Srivatsavai } 16654eaa4710SRishi Srivatsavai fwd_unref(bfp); 16664eaa4710SRishi Srivatsavai } 16674eaa4710SRishi Srivatsavai bfpnew->bf_links[0] = blp; 16684eaa4710SRishi Srivatsavai bfpnew->bf_nlinks = 1; 16694eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); /* bf_links entry */ 16704eaa4710SRishi Srivatsavai if (!fwd_insert(bip, bfpnew)) 16714eaa4710SRishi Srivatsavai fwd_free(bfpnew); 16724eaa4710SRishi Srivatsavai else if (!replaced) 16734eaa4710SRishi Srivatsavai KIINCR(bki_source); 16744eaa4710SRishi Srivatsavai } 16754eaa4710SRishi Srivatsavai 16764eaa4710SRishi Srivatsavai /* 16774eaa4710SRishi Srivatsavai * Process the VLAN headers for output on a given link. There are several 16784eaa4710SRishi Srivatsavai * cases (noting that we don't map VLANs): 16794eaa4710SRishi Srivatsavai * 1. The input packet is good as it is; either 16804eaa4710SRishi Srivatsavai * a. It has no tag, and output has same PVID 16814eaa4710SRishi Srivatsavai * b. It has a non-zero priority-only tag for PVID, and b_band is same 16824eaa4710SRishi Srivatsavai * c. It has a tag with VLAN different from PVID, and b_band is same 16834eaa4710SRishi Srivatsavai * 2. The tag must change: non-zero b_band is different from tag priority 16844eaa4710SRishi Srivatsavai * 3. The packet has a tag and should not (VLAN same as PVID, b_band zero) 16854eaa4710SRishi Srivatsavai * 4. The packet has no tag and needs one: 16864eaa4710SRishi Srivatsavai * a. VLAN ID same as PVID, but b_band is non-zero 16874eaa4710SRishi Srivatsavai * b. VLAN ID different from PVID 16884eaa4710SRishi Srivatsavai * We exclude case 1 first, then modify the packet. Note that output packets 16894eaa4710SRishi Srivatsavai * get a priority set by the mblk, not by the header, because QoS in bridging 16904eaa4710SRishi Srivatsavai * requires priority recalculation at each node. 16914eaa4710SRishi Srivatsavai * 16924eaa4710SRishi Srivatsavai * The passed-in tci is the "impossible" value 0xFFFF when no tag is present. 16934eaa4710SRishi Srivatsavai */ 16944eaa4710SRishi Srivatsavai static mblk_t * 16954eaa4710SRishi Srivatsavai reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid) 16964eaa4710SRishi Srivatsavai { 16974eaa4710SRishi Srivatsavai boolean_t source_has_tag = (tci != 0xFFFF); 16984eaa4710SRishi Srivatsavai mblk_t *mpcopy; 16994eaa4710SRishi Srivatsavai size_t mlen, minlen; 17004eaa4710SRishi Srivatsavai struct ether_vlan_header *evh; 17014eaa4710SRishi Srivatsavai int pri; 17024eaa4710SRishi Srivatsavai 17034eaa4710SRishi Srivatsavai /* This helps centralize error handling in the caller. */ 17044eaa4710SRishi Srivatsavai if (mp == NULL) 17054eaa4710SRishi Srivatsavai return (mp); 17064eaa4710SRishi Srivatsavai 17074eaa4710SRishi Srivatsavai /* No forwarded packet can have hardware checksum enabled */ 17084eaa4710SRishi Srivatsavai DB_CKSUMFLAGS(mp) = 0; 17094eaa4710SRishi Srivatsavai 17104eaa4710SRishi Srivatsavai /* Get the no-modification cases out of the way first */ 17114eaa4710SRishi Srivatsavai if (!source_has_tag && vlanid == pvid) /* 1a */ 17124eaa4710SRishi Srivatsavai return (mp); 17134eaa4710SRishi Srivatsavai 17144eaa4710SRishi Srivatsavai pri = VLAN_PRI(tci); 17154eaa4710SRishi Srivatsavai if (source_has_tag && mp->b_band == pri) { 17164eaa4710SRishi Srivatsavai if (vlanid != pvid) /* 1c */ 17174eaa4710SRishi Srivatsavai return (mp); 17184eaa4710SRishi Srivatsavai if (pri != 0 && VLAN_ID(tci) == 0) /* 1b */ 17194eaa4710SRishi Srivatsavai return (mp); 17204eaa4710SRishi Srivatsavai } 17214eaa4710SRishi Srivatsavai 17224eaa4710SRishi Srivatsavai /* 17234eaa4710SRishi Srivatsavai * We now know that we must modify the packet. Prepare for that. Note 17244eaa4710SRishi Srivatsavai * that if a tag is present, the caller has already done a pullup for 17254eaa4710SRishi Srivatsavai * the VLAN header, so we're good to go. 17264eaa4710SRishi Srivatsavai */ 17274eaa4710SRishi Srivatsavai if (MBLKL(mp) < sizeof (struct ether_header)) { 17284eaa4710SRishi Srivatsavai mpcopy = msgpullup(mp, sizeof (struct ether_header)); 17294eaa4710SRishi Srivatsavai if (mpcopy == NULL) { 17304eaa4710SRishi Srivatsavai freemsg(mp); 17314eaa4710SRishi Srivatsavai return (NULL); 17324eaa4710SRishi Srivatsavai } 17334eaa4710SRishi Srivatsavai mp = mpcopy; 17344eaa4710SRishi Srivatsavai } 17354eaa4710SRishi Srivatsavai if (DB_REF(mp) > 1 || !IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)) || 17364eaa4710SRishi Srivatsavai (!source_has_tag && MBLKTAIL(mp) < VLAN_INCR)) { 17374eaa4710SRishi Srivatsavai minlen = mlen = MBLKL(mp); 17384eaa4710SRishi Srivatsavai if (!source_has_tag) 17394eaa4710SRishi Srivatsavai minlen += VLAN_INCR; 17404eaa4710SRishi Srivatsavai ASSERT(minlen >= sizeof (struct ether_vlan_header)); 17414eaa4710SRishi Srivatsavai /* 17424eaa4710SRishi Srivatsavai * We're willing to copy some data to avoid fragmentation, but 17434eaa4710SRishi Srivatsavai * not a lot. 17444eaa4710SRishi Srivatsavai */ 17454eaa4710SRishi Srivatsavai if (minlen > 256) 17464eaa4710SRishi Srivatsavai minlen = sizeof (struct ether_vlan_header); 17474eaa4710SRishi Srivatsavai mpcopy = allocb(minlen, BPRI_MED); 17484eaa4710SRishi Srivatsavai if (mpcopy == NULL) { 17494eaa4710SRishi Srivatsavai freemsg(mp); 17504eaa4710SRishi Srivatsavai return (NULL); 17514eaa4710SRishi Srivatsavai } 17524eaa4710SRishi Srivatsavai if (mlen <= minlen) { 17534eaa4710SRishi Srivatsavai /* We toss the first mblk when we can. */ 17544eaa4710SRishi Srivatsavai bcopy(mp->b_rptr, mpcopy->b_rptr, mlen); 17554eaa4710SRishi Srivatsavai mpcopy->b_wptr += mlen; 17564eaa4710SRishi Srivatsavai mpcopy->b_cont = mp->b_cont; 17574eaa4710SRishi Srivatsavai freeb(mp); 17584eaa4710SRishi Srivatsavai } else { 17594eaa4710SRishi Srivatsavai /* If not, then just copy what we need */ 17604eaa4710SRishi Srivatsavai if (!source_has_tag) 17614eaa4710SRishi Srivatsavai minlen = sizeof (struct ether_header); 17624eaa4710SRishi Srivatsavai bcopy(mp->b_rptr, mpcopy->b_rptr, minlen); 17634eaa4710SRishi Srivatsavai mpcopy->b_wptr += minlen; 17644eaa4710SRishi Srivatsavai mpcopy->b_cont = mp; 17654eaa4710SRishi Srivatsavai mp->b_rptr += minlen; 17664eaa4710SRishi Srivatsavai } 17674eaa4710SRishi Srivatsavai mp = mpcopy; 17684eaa4710SRishi Srivatsavai } 17694eaa4710SRishi Srivatsavai 17704eaa4710SRishi Srivatsavai /* LINTED: pointer alignment */ 17714eaa4710SRishi Srivatsavai evh = (struct ether_vlan_header *)mp->b_rptr; 17724eaa4710SRishi Srivatsavai if (source_has_tag) { 17734eaa4710SRishi Srivatsavai if (mp->b_band == 0 && vlanid == pvid) { /* 3 */ 17744eaa4710SRishi Srivatsavai evh->ether_tpid = evh->ether_type; 17754eaa4710SRishi Srivatsavai mlen = MBLKL(mp); 17764eaa4710SRishi Srivatsavai if (mlen > sizeof (struct ether_vlan_header)) 17774eaa4710SRishi Srivatsavai ovbcopy(mp->b_rptr + 17784eaa4710SRishi Srivatsavai sizeof (struct ether_vlan_header), 17794eaa4710SRishi Srivatsavai mp->b_rptr + sizeof (struct ether_header), 17804eaa4710SRishi Srivatsavai mlen - sizeof (struct ether_vlan_header)); 17814eaa4710SRishi Srivatsavai mp->b_wptr -= VLAN_INCR; 17824eaa4710SRishi Srivatsavai } else { /* 2 */ 17834eaa4710SRishi Srivatsavai if (vlanid == pvid) 17844eaa4710SRishi Srivatsavai vlanid = VLAN_ID_NONE; 17854eaa4710SRishi Srivatsavai tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid); 17864eaa4710SRishi Srivatsavai evh->ether_tci = htons(tci); 17874eaa4710SRishi Srivatsavai } 17884eaa4710SRishi Srivatsavai } else { 17894eaa4710SRishi Srivatsavai /* case 4: no header present, but one is needed */ 17904eaa4710SRishi Srivatsavai mlen = MBLKL(mp); 17914eaa4710SRishi Srivatsavai if (mlen > sizeof (struct ether_header)) 17924eaa4710SRishi Srivatsavai ovbcopy(mp->b_rptr + sizeof (struct ether_header), 17934eaa4710SRishi Srivatsavai mp->b_rptr + sizeof (struct ether_vlan_header), 17944eaa4710SRishi Srivatsavai mlen - sizeof (struct ether_header)); 17954eaa4710SRishi Srivatsavai mp->b_wptr += VLAN_INCR; 17964eaa4710SRishi Srivatsavai ASSERT(mp->b_wptr <= DB_LIM(mp)); 17974eaa4710SRishi Srivatsavai if (vlanid == pvid) 17984eaa4710SRishi Srivatsavai vlanid = VLAN_ID_NONE; 17994eaa4710SRishi Srivatsavai tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid); 18004eaa4710SRishi Srivatsavai evh->ether_type = evh->ether_tpid; 18014eaa4710SRishi Srivatsavai evh->ether_tpid = htons(ETHERTYPE_VLAN); 18024eaa4710SRishi Srivatsavai evh->ether_tci = htons(tci); 18034eaa4710SRishi Srivatsavai } 18044eaa4710SRishi Srivatsavai return (mp); 18054eaa4710SRishi Srivatsavai } 18064eaa4710SRishi Srivatsavai 18074eaa4710SRishi Srivatsavai /* Record VLAN information and strip header if requested . */ 18084eaa4710SRishi Srivatsavai static void 18094eaa4710SRishi Srivatsavai update_header(mblk_t *mp, mac_header_info_t *hdr_info, boolean_t striphdr) 18104eaa4710SRishi Srivatsavai { 18114eaa4710SRishi Srivatsavai if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) { 18124eaa4710SRishi Srivatsavai struct ether_vlan_header *evhp; 18134eaa4710SRishi Srivatsavai uint16_t ether_type; 18144eaa4710SRishi Srivatsavai 18154eaa4710SRishi Srivatsavai /* LINTED: alignment */ 18164eaa4710SRishi Srivatsavai evhp = (struct ether_vlan_header *)mp->b_rptr; 18174eaa4710SRishi Srivatsavai hdr_info->mhi_istagged = B_TRUE; 18184eaa4710SRishi Srivatsavai hdr_info->mhi_tci = ntohs(evhp->ether_tci); 18194eaa4710SRishi Srivatsavai if (striphdr) { 18204eaa4710SRishi Srivatsavai /* 18214eaa4710SRishi Srivatsavai * For VLAN tagged frames update the ether_type 18224eaa4710SRishi Srivatsavai * in hdr_info before stripping the header. 18234eaa4710SRishi Srivatsavai */ 18244eaa4710SRishi Srivatsavai ether_type = ntohs(evhp->ether_type); 18254eaa4710SRishi Srivatsavai hdr_info->mhi_origsap = ether_type; 18264eaa4710SRishi Srivatsavai hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ? 18274eaa4710SRishi Srivatsavai ether_type : DLS_SAP_LLC; 18284eaa4710SRishi Srivatsavai mp->b_rptr = (uchar_t *)(evhp + 1); 18294eaa4710SRishi Srivatsavai } 18304eaa4710SRishi Srivatsavai } else { 18314eaa4710SRishi Srivatsavai hdr_info->mhi_istagged = B_FALSE; 18324eaa4710SRishi Srivatsavai hdr_info->mhi_tci = VLAN_ID_NONE; 18334eaa4710SRishi Srivatsavai if (striphdr) 18344eaa4710SRishi Srivatsavai mp->b_rptr += sizeof (struct ether_header); 18354eaa4710SRishi Srivatsavai } 18364eaa4710SRishi Srivatsavai } 18374eaa4710SRishi Srivatsavai 18384eaa4710SRishi Srivatsavai /* 18394eaa4710SRishi Srivatsavai * Return B_TRUE if we're allowed to send on this link with the given VLAN ID. 18404eaa4710SRishi Srivatsavai */ 18414eaa4710SRishi Srivatsavai static boolean_t 18424eaa4710SRishi Srivatsavai bridge_can_send(bridge_link_t *blp, uint16_t vlanid) 18434eaa4710SRishi Srivatsavai { 18444eaa4710SRishi Srivatsavai ASSERT(vlanid != VLAN_ID_NONE); 18454eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_DELETED) 18464eaa4710SRishi Srivatsavai return (B_FALSE); 18474eaa4710SRishi Srivatsavai if (blp->bl_trilldata == NULL && blp->bl_state != BLS_FORWARDING) 18484eaa4710SRishi Srivatsavai return (B_FALSE); 18494eaa4710SRishi Srivatsavai return (BRIDGE_VLAN_ISSET(blp, vlanid) && BRIDGE_AF_ISSET(blp, vlanid)); 18504eaa4710SRishi Srivatsavai } 18514eaa4710SRishi Srivatsavai 18524eaa4710SRishi Srivatsavai /* 18534eaa4710SRishi Srivatsavai * This function scans the bridge forwarding tables in order to forward a given 18544eaa4710SRishi Srivatsavai * packet. If the packet either doesn't need forwarding (the current link is 18554eaa4710SRishi Srivatsavai * correct) or the current link needs a copy as well, then the packet is 18564eaa4710SRishi Srivatsavai * returned to the caller. 18574eaa4710SRishi Srivatsavai * 18584eaa4710SRishi Srivatsavai * If a packet has been decapsulated from TRILL, then it must *NOT* reenter a 18594eaa4710SRishi Srivatsavai * TRILL tunnel. If the destination points there, then drop instead. 18604eaa4710SRishi Srivatsavai */ 18614eaa4710SRishi Srivatsavai static mblk_t * 18624eaa4710SRishi Srivatsavai bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, 18634eaa4710SRishi Srivatsavai uint16_t vlanid, uint16_t tci, boolean_t from_trill, boolean_t is_xmit) 18644eaa4710SRishi Srivatsavai { 18654eaa4710SRishi Srivatsavai mblk_t *mpsend, *mpcopy; 18664eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 18674eaa4710SRishi Srivatsavai bridge_link_t *blpsend, *blpnext; 18684eaa4710SRishi Srivatsavai bridge_fwd_t *bfp; 18694eaa4710SRishi Srivatsavai uint_t i; 18704eaa4710SRishi Srivatsavai boolean_t selfseen = B_FALSE; 18714eaa4710SRishi Srivatsavai void *tdp; 18724eaa4710SRishi Srivatsavai const uint8_t *daddr = hdr_info->mhi_daddr; 18734eaa4710SRishi Srivatsavai 18744eaa4710SRishi Srivatsavai /* 18754eaa4710SRishi Srivatsavai * Check for the IEEE "reserved" multicast addresses. Messages sent to 18764eaa4710SRishi Srivatsavai * these addresses are used for link-local control (STP and pause), and 18774eaa4710SRishi Srivatsavai * are never forwarded or redirected. 18784eaa4710SRishi Srivatsavai */ 18794eaa4710SRishi Srivatsavai if (daddr[0] == 1 && daddr[1] == 0x80 && daddr[2] == 0xc2 && 18804eaa4710SRishi Srivatsavai daddr[3] == 0 && daddr[4] == 0 && (daddr[5] & 0xf0) == 0) { 18814eaa4710SRishi Srivatsavai if (from_trill) { 18824eaa4710SRishi Srivatsavai freemsg(mp); 18834eaa4710SRishi Srivatsavai mp = NULL; 18844eaa4710SRishi Srivatsavai } 18854eaa4710SRishi Srivatsavai return (mp); 18864eaa4710SRishi Srivatsavai } 18874eaa4710SRishi Srivatsavai 18884eaa4710SRishi Srivatsavai if ((bfp = fwd_find(bip, daddr, vlanid)) != NULL) { 18894eaa4710SRishi Srivatsavai 18904eaa4710SRishi Srivatsavai /* 18914eaa4710SRishi Srivatsavai * If trill indicates a destination for this node, then it's 18924eaa4710SRishi Srivatsavai * clearly not intended for local delivery. We must tell TRILL 18934eaa4710SRishi Srivatsavai * to encapsulate, as long as we didn't just decapsulate it. 18944eaa4710SRishi Srivatsavai */ 18954eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) { 18964eaa4710SRishi Srivatsavai /* 18974eaa4710SRishi Srivatsavai * Error case: can't reencapsulate if the protocols are 18984eaa4710SRishi Srivatsavai * working correctly. 18994eaa4710SRishi Srivatsavai */ 19004eaa4710SRishi Srivatsavai if (from_trill) { 19014eaa4710SRishi Srivatsavai freemsg(mp); 19024eaa4710SRishi Srivatsavai return (NULL); 19034eaa4710SRishi Srivatsavai } 19044eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 19054eaa4710SRishi Srivatsavai if ((tdp = blp->bl_trilldata) != NULL) { 19064eaa4710SRishi Srivatsavai blp->bl_trillthreads++; 19074eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 19084eaa4710SRishi Srivatsavai update_header(mp, hdr_info, B_FALSE); 19094eaa4710SRishi Srivatsavai if (is_xmit) 19104eaa4710SRishi Srivatsavai mp = mac_fix_cksum(mp); 19114eaa4710SRishi Srivatsavai /* all trill data frames have Inner.VLAN */ 19124eaa4710SRishi Srivatsavai mp = reform_vlan_header(mp, vlanid, tci, 0); 19134eaa4710SRishi Srivatsavai if (mp == NULL) { 19144eaa4710SRishi Srivatsavai KIINCR(bki_drops); 19154eaa4710SRishi Srivatsavai fwd_unref(bfp); 19164eaa4710SRishi Srivatsavai return (NULL); 19174eaa4710SRishi Srivatsavai } 19184eaa4710SRishi Srivatsavai trill_encap_fn(tdp, blp, hdr_info, mp, 19194eaa4710SRishi Srivatsavai bfp->bf_trill_nick); 19204eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 19214eaa4710SRishi Srivatsavai if (--blp->bl_trillthreads == 0 && 19224eaa4710SRishi Srivatsavai blp->bl_trilldata == NULL) 19234eaa4710SRishi Srivatsavai cv_broadcast(&blp->bl_trillwait); 19244eaa4710SRishi Srivatsavai } 19254eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 19264eaa4710SRishi Srivatsavai 19274eaa4710SRishi Srivatsavai /* if TRILL has been disabled, then kill this stray */ 19284eaa4710SRishi Srivatsavai if (tdp == NULL) { 19294eaa4710SRishi Srivatsavai freemsg(mp); 19304eaa4710SRishi Srivatsavai fwd_delete(bfp); 19314eaa4710SRishi Srivatsavai } 19324eaa4710SRishi Srivatsavai fwd_unref(bfp); 19334eaa4710SRishi Srivatsavai return (NULL); 19344eaa4710SRishi Srivatsavai } 19354eaa4710SRishi Srivatsavai 19364eaa4710SRishi Srivatsavai /* find first link we can send on */ 19374eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) { 19384eaa4710SRishi Srivatsavai blpsend = bfp->bf_links[i]; 19394eaa4710SRishi Srivatsavai if (blpsend == blp) 19404eaa4710SRishi Srivatsavai selfseen = B_TRUE; 19414eaa4710SRishi Srivatsavai else if (bridge_can_send(blpsend, vlanid)) 19424eaa4710SRishi Srivatsavai break; 19434eaa4710SRishi Srivatsavai } 19444eaa4710SRishi Srivatsavai 19454eaa4710SRishi Srivatsavai while (i < bfp->bf_nlinks) { 19464eaa4710SRishi Srivatsavai blpsend = bfp->bf_links[i]; 19474eaa4710SRishi Srivatsavai for (i++; i < bfp->bf_nlinks; i++) { 19484eaa4710SRishi Srivatsavai blpnext = bfp->bf_links[i]; 19494eaa4710SRishi Srivatsavai if (blpnext == blp) 19504eaa4710SRishi Srivatsavai selfseen = B_TRUE; 19514eaa4710SRishi Srivatsavai else if (bridge_can_send(blpnext, vlanid)) 19524eaa4710SRishi Srivatsavai break; 19534eaa4710SRishi Srivatsavai } 19544eaa4710SRishi Srivatsavai if (i == bfp->bf_nlinks && !selfseen) { 19554eaa4710SRishi Srivatsavai mpsend = mp; 19564eaa4710SRishi Srivatsavai mp = NULL; 19574eaa4710SRishi Srivatsavai } else { 19584eaa4710SRishi Srivatsavai mpsend = copymsg(mp); 19594eaa4710SRishi Srivatsavai } 19604eaa4710SRishi Srivatsavai 19614eaa4710SRishi Srivatsavai if (!from_trill && is_xmit) 19624eaa4710SRishi Srivatsavai mpsend = mac_fix_cksum(mpsend); 19634eaa4710SRishi Srivatsavai 19644eaa4710SRishi Srivatsavai mpsend = reform_vlan_header(mpsend, vlanid, tci, 19654eaa4710SRishi Srivatsavai blpsend->bl_pvid); 19664eaa4710SRishi Srivatsavai if (mpsend == NULL) { 19674eaa4710SRishi Srivatsavai KIINCR(bki_drops); 19684eaa4710SRishi Srivatsavai continue; 19694eaa4710SRishi Srivatsavai } 19704eaa4710SRishi Srivatsavai 19714eaa4710SRishi Srivatsavai KIINCR(bki_forwards); 19724eaa4710SRishi Srivatsavai /* 19734eaa4710SRishi Srivatsavai * No need to bump up the link reference count, as 19744eaa4710SRishi Srivatsavai * the forwarding entry itself holds a reference to 19754eaa4710SRishi Srivatsavai * the link. 19764eaa4710SRishi Srivatsavai */ 19774eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR) { 19784eaa4710SRishi Srivatsavai mac_rx_common(blpsend->bl_mh, NULL, mpsend); 19794eaa4710SRishi Srivatsavai } else { 19804eaa4710SRishi Srivatsavai KLPINCR(blpsend, bkl_xmit); 19814eaa4710SRishi Srivatsavai MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, 19824eaa4710SRishi Srivatsavai mpsend); 19834eaa4710SRishi Srivatsavai freemsg(mpsend); 19844eaa4710SRishi Srivatsavai } 19854eaa4710SRishi Srivatsavai } 19864eaa4710SRishi Srivatsavai /* 19874eaa4710SRishi Srivatsavai * Handle a special case: if we're transmitting to the original 19884eaa4710SRishi Srivatsavai * link, then check whether the localaddr flag is set. If it 19894eaa4710SRishi Srivatsavai * is, then receive instead. This doesn't happen with ordinary 19904eaa4710SRishi Srivatsavai * bridging, but does happen often with TRILL decapsulation. 19914eaa4710SRishi Srivatsavai */ 19924eaa4710SRishi Srivatsavai if (mp != NULL && is_xmit && (bfp->bf_flags & BFF_LOCALADDR)) { 19934eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, NULL, mp); 19944eaa4710SRishi Srivatsavai mp = NULL; 19954eaa4710SRishi Srivatsavai } 19964eaa4710SRishi Srivatsavai fwd_unref(bfp); 19974eaa4710SRishi Srivatsavai } else { 19984eaa4710SRishi Srivatsavai /* 19994eaa4710SRishi Srivatsavai * TRILL has two cases to handle. If the packet is off the 20004eaa4710SRishi Srivatsavai * wire (not from TRILL), then we need to send up into the 20014eaa4710SRishi Srivatsavai * TRILL module to have the distribution tree computed. If the 20024eaa4710SRishi Srivatsavai * packet is from TRILL (decapsulated), then we're part of the 20034eaa4710SRishi Srivatsavai * distribution tree, and we need to copy the packet on member 20044eaa4710SRishi Srivatsavai * interfaces. 20054eaa4710SRishi Srivatsavai * 20064eaa4710SRishi Srivatsavai * Thus, the from TRILL case is identical to the STP case. 20074eaa4710SRishi Srivatsavai */ 20084eaa4710SRishi Srivatsavai if (!from_trill && blp->bl_trilldata != NULL) { 20094eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 20104eaa4710SRishi Srivatsavai if ((tdp = blp->bl_trilldata) != NULL) { 20114eaa4710SRishi Srivatsavai blp->bl_trillthreads++; 20124eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 20134eaa4710SRishi Srivatsavai if ((mpsend = copymsg(mp)) != NULL) { 20144eaa4710SRishi Srivatsavai update_header(mpsend, 20154eaa4710SRishi Srivatsavai hdr_info, B_FALSE); 20164eaa4710SRishi Srivatsavai /* 20174eaa4710SRishi Srivatsavai * all trill data frames have 20184eaa4710SRishi Srivatsavai * Inner.VLAN 20194eaa4710SRishi Srivatsavai */ 20204eaa4710SRishi Srivatsavai mpsend = reform_vlan_header(mpsend, 20214eaa4710SRishi Srivatsavai vlanid, tci, 0); 20224eaa4710SRishi Srivatsavai if (mpsend == NULL) { 20234eaa4710SRishi Srivatsavai KIINCR(bki_drops); 20244eaa4710SRishi Srivatsavai } else { 20254eaa4710SRishi Srivatsavai trill_encap_fn(tdp, blp, 20264eaa4710SRishi Srivatsavai hdr_info, mpsend, 20274eaa4710SRishi Srivatsavai RBRIDGE_NICKNAME_NONE); 20284eaa4710SRishi Srivatsavai } 20294eaa4710SRishi Srivatsavai } 20304eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 20314eaa4710SRishi Srivatsavai if (--blp->bl_trillthreads == 0 && 20324eaa4710SRishi Srivatsavai blp->bl_trilldata == NULL) 20334eaa4710SRishi Srivatsavai cv_broadcast(&blp->bl_trillwait); 20344eaa4710SRishi Srivatsavai } 20354eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 20364eaa4710SRishi Srivatsavai } 20374eaa4710SRishi Srivatsavai 20384eaa4710SRishi Srivatsavai /* 20394eaa4710SRishi Srivatsavai * This is an unknown destination, so flood. 20404eaa4710SRishi Srivatsavai */ 20414eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 20424eaa4710SRishi Srivatsavai for (blpnext = list_head(&bip->bi_links); blpnext != NULL; 20434eaa4710SRishi Srivatsavai blpnext = list_next(&bip->bi_links, blpnext)) { 20444eaa4710SRishi Srivatsavai if (blpnext == blp) 20454eaa4710SRishi Srivatsavai selfseen = B_TRUE; 20464eaa4710SRishi Srivatsavai else if (bridge_can_send(blpnext, vlanid)) 20474eaa4710SRishi Srivatsavai break; 20484eaa4710SRishi Srivatsavai } 20494eaa4710SRishi Srivatsavai if (blpnext != NULL) 20504eaa4710SRishi Srivatsavai atomic_inc_uint(&blpnext->bl_refs); 20514eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 20524eaa4710SRishi Srivatsavai while ((blpsend = blpnext) != NULL) { 20534eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 20544eaa4710SRishi Srivatsavai for (blpnext = list_next(&bip->bi_links, blpsend); 20554eaa4710SRishi Srivatsavai blpnext != NULL; 20564eaa4710SRishi Srivatsavai blpnext = list_next(&bip->bi_links, blpnext)) { 20574eaa4710SRishi Srivatsavai if (blpnext == blp) 20584eaa4710SRishi Srivatsavai selfseen = B_TRUE; 20594eaa4710SRishi Srivatsavai else if (bridge_can_send(blpnext, vlanid)) 20604eaa4710SRishi Srivatsavai break; 20614eaa4710SRishi Srivatsavai } 20624eaa4710SRishi Srivatsavai if (blpnext != NULL) 20634eaa4710SRishi Srivatsavai atomic_inc_uint(&blpnext->bl_refs); 20644eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 20654eaa4710SRishi Srivatsavai if (blpnext == NULL && !selfseen) { 20664eaa4710SRishi Srivatsavai mpsend = mp; 20674eaa4710SRishi Srivatsavai mp = NULL; 20684eaa4710SRishi Srivatsavai } else { 20694eaa4710SRishi Srivatsavai mpsend = copymsg(mp); 20704eaa4710SRishi Srivatsavai } 20714eaa4710SRishi Srivatsavai 20724eaa4710SRishi Srivatsavai if (!from_trill && is_xmit) 20734eaa4710SRishi Srivatsavai mpsend = mac_fix_cksum(mpsend); 20744eaa4710SRishi Srivatsavai 20754eaa4710SRishi Srivatsavai mpsend = reform_vlan_header(mpsend, vlanid, tci, 20764eaa4710SRishi Srivatsavai blpsend->bl_pvid); 20774eaa4710SRishi Srivatsavai if (mpsend == NULL) { 20784eaa4710SRishi Srivatsavai KIINCR(bki_drops); 20794eaa4710SRishi Srivatsavai continue; 20804eaa4710SRishi Srivatsavai } 20814eaa4710SRishi Srivatsavai 20824eaa4710SRishi Srivatsavai if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST) 20834eaa4710SRishi Srivatsavai KIINCR(bki_unknown); 20844eaa4710SRishi Srivatsavai else 20854eaa4710SRishi Srivatsavai KIINCR(bki_mbcast); 20864eaa4710SRishi Srivatsavai KLPINCR(blpsend, bkl_xmit); 20874eaa4710SRishi Srivatsavai if ((mpcopy = copymsg(mpsend)) != NULL) 20884eaa4710SRishi Srivatsavai mac_rx_common(blpsend->bl_mh, NULL, mpcopy); 20894eaa4710SRishi Srivatsavai MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, mpsend); 20904eaa4710SRishi Srivatsavai freemsg(mpsend); 20914eaa4710SRishi Srivatsavai link_unref(blpsend); 20924eaa4710SRishi Srivatsavai } 20934eaa4710SRishi Srivatsavai } 20944eaa4710SRishi Srivatsavai 20954eaa4710SRishi Srivatsavai /* 20964eaa4710SRishi Srivatsavai * At this point, if np is non-NULL, it means that the caller needs to 20974eaa4710SRishi Srivatsavai * continue on the selected link. 20984eaa4710SRishi Srivatsavai */ 20994eaa4710SRishi Srivatsavai return (mp); 21004eaa4710SRishi Srivatsavai } 21014eaa4710SRishi Srivatsavai 21024eaa4710SRishi Srivatsavai /* 21034eaa4710SRishi Srivatsavai * Extract and validate the VLAN information for a given packet. This checks 21044eaa4710SRishi Srivatsavai * conformance with the rules for use of the PVID on the link, and for the 21054eaa4710SRishi Srivatsavai * allowed (configured) VLAN set. 21064eaa4710SRishi Srivatsavai * 21074eaa4710SRishi Srivatsavai * Returns B_TRUE if the packet passes, B_FALSE if it fails. 21084eaa4710SRishi Srivatsavai */ 21094eaa4710SRishi Srivatsavai static boolean_t 21104eaa4710SRishi Srivatsavai bridge_get_vlan(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, 21114eaa4710SRishi Srivatsavai uint16_t *vlanidp, uint16_t *tcip) 21124eaa4710SRishi Srivatsavai { 21134eaa4710SRishi Srivatsavai uint16_t tci, vlanid; 21144eaa4710SRishi Srivatsavai 21154eaa4710SRishi Srivatsavai if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) { 21164eaa4710SRishi Srivatsavai ptrdiff_t tpos = offsetof(struct ether_vlan_header, ether_tci); 21174eaa4710SRishi Srivatsavai ptrdiff_t mlen; 21184eaa4710SRishi Srivatsavai 21194eaa4710SRishi Srivatsavai /* 21204eaa4710SRishi Srivatsavai * Extract the VLAN ID information, regardless of alignment, 21214eaa4710SRishi Srivatsavai * and without a pullup. This isn't attractive, but we do this 21224eaa4710SRishi Srivatsavai * to avoid having to deal with the pointers stashed in 21234eaa4710SRishi Srivatsavai * hdr_info moving around or having the caller deal with a new 21244eaa4710SRishi Srivatsavai * mblk_t pointer. 21254eaa4710SRishi Srivatsavai */ 21264eaa4710SRishi Srivatsavai while (mp != NULL) { 21274eaa4710SRishi Srivatsavai mlen = MBLKL(mp); 21284eaa4710SRishi Srivatsavai if (mlen > tpos && mlen > 0) 21294eaa4710SRishi Srivatsavai break; 21304eaa4710SRishi Srivatsavai tpos -= mlen; 21314eaa4710SRishi Srivatsavai mp = mp->b_cont; 21324eaa4710SRishi Srivatsavai } 21334eaa4710SRishi Srivatsavai if (mp == NULL) 21344eaa4710SRishi Srivatsavai return (B_FALSE); 21354eaa4710SRishi Srivatsavai tci = mp->b_rptr[tpos] << 8; 21364eaa4710SRishi Srivatsavai if (++tpos >= mlen) { 21374eaa4710SRishi Srivatsavai do { 21384eaa4710SRishi Srivatsavai mp = mp->b_cont; 21394eaa4710SRishi Srivatsavai } while (mp != NULL && MBLKL(mp) == 0); 21404eaa4710SRishi Srivatsavai if (mp == NULL) 21414eaa4710SRishi Srivatsavai return (B_FALSE); 21424eaa4710SRishi Srivatsavai tpos = 0; 21434eaa4710SRishi Srivatsavai } 21444eaa4710SRishi Srivatsavai tci |= mp->b_rptr[tpos]; 21454eaa4710SRishi Srivatsavai 21464eaa4710SRishi Srivatsavai vlanid = VLAN_ID(tci); 21474eaa4710SRishi Srivatsavai if (VLAN_CFI(tci) != ETHER_CFI || vlanid > VLAN_ID_MAX) 21484eaa4710SRishi Srivatsavai return (B_FALSE); 21494eaa4710SRishi Srivatsavai if (vlanid == VLAN_ID_NONE || vlanid == blp->bl_pvid) 21504eaa4710SRishi Srivatsavai goto input_no_vlan; 21514eaa4710SRishi Srivatsavai if (!BRIDGE_VLAN_ISSET(blp, vlanid)) 21524eaa4710SRishi Srivatsavai return (B_FALSE); 21534eaa4710SRishi Srivatsavai } else { 21544eaa4710SRishi Srivatsavai tci = 0xFFFF; 21554eaa4710SRishi Srivatsavai input_no_vlan: 21564eaa4710SRishi Srivatsavai /* 21574eaa4710SRishi Srivatsavai * If PVID is set to zero, then untagged traffic is not 21584eaa4710SRishi Srivatsavai * supported here. Do not learn or forward. 21594eaa4710SRishi Srivatsavai */ 21604eaa4710SRishi Srivatsavai if ((vlanid = blp->bl_pvid) == VLAN_ID_NONE) 21614eaa4710SRishi Srivatsavai return (B_FALSE); 21624eaa4710SRishi Srivatsavai } 21634eaa4710SRishi Srivatsavai 21644eaa4710SRishi Srivatsavai *tcip = tci; 21654eaa4710SRishi Srivatsavai *vlanidp = vlanid; 21664eaa4710SRishi Srivatsavai return (B_TRUE); 21674eaa4710SRishi Srivatsavai } 21684eaa4710SRishi Srivatsavai 21694eaa4710SRishi Srivatsavai /* 21704eaa4710SRishi Srivatsavai * Handle MAC notifications. 21714eaa4710SRishi Srivatsavai */ 21724eaa4710SRishi Srivatsavai static void 21734eaa4710SRishi Srivatsavai bridge_notify_cb(void *arg, mac_notify_type_t note_type) 21744eaa4710SRishi Srivatsavai { 21754eaa4710SRishi Srivatsavai bridge_link_t *blp = arg; 21764eaa4710SRishi Srivatsavai 21774eaa4710SRishi Srivatsavai switch (note_type) { 21784eaa4710SRishi Srivatsavai case MAC_NOTE_UNICST: 21794eaa4710SRishi Srivatsavai bridge_new_unicst(blp); 21804eaa4710SRishi Srivatsavai break; 21814eaa4710SRishi Srivatsavai 21824eaa4710SRishi Srivatsavai case MAC_NOTE_SDU_SIZE: { 21834eaa4710SRishi Srivatsavai uint_t maxsdu; 21844eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 21854eaa4710SRishi Srivatsavai bridge_mac_t *bmp = bip->bi_mac; 21864eaa4710SRishi Srivatsavai boolean_t notify = B_FALSE; 21874eaa4710SRishi Srivatsavai mblk_t *mlist = NULL; 21884eaa4710SRishi Srivatsavai 21894eaa4710SRishi Srivatsavai mac_sdu_get(blp->bl_mh, NULL, &maxsdu); 21904eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 21914eaa4710SRishi Srivatsavai if (list_prev(&bip->bi_links, blp) == NULL && 21924eaa4710SRishi Srivatsavai list_next(&bip->bi_links, blp) == NULL) { 21934eaa4710SRishi Srivatsavai notify = (maxsdu != bmp->bm_maxsdu); 21944eaa4710SRishi Srivatsavai bmp->bm_maxsdu = maxsdu; 21954eaa4710SRishi Srivatsavai } 21964eaa4710SRishi Srivatsavai blp->bl_maxsdu = maxsdu; 21974eaa4710SRishi Srivatsavai if (maxsdu != bmp->bm_maxsdu) 21984eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_TRUE, &mlist); 21994eaa4710SRishi Srivatsavai else if (notify) 22004eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 22014eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 22024eaa4710SRishi Srivatsavai send_up_messages(bip, mlist); 22034eaa4710SRishi Srivatsavai break; 22044eaa4710SRishi Srivatsavai } 22054eaa4710SRishi Srivatsavai } 22064eaa4710SRishi Srivatsavai } 22074eaa4710SRishi Srivatsavai 22084eaa4710SRishi Srivatsavai /* 22094eaa4710SRishi Srivatsavai * This is called by the MAC layer. As with the transmit side, we're right in 22104eaa4710SRishi Srivatsavai * the data path for all I/O on this port, so if we don't need to forward this 22114eaa4710SRishi Srivatsavai * packet anywhere, we have to send it upwards via mac_rx_common. 22124eaa4710SRishi Srivatsavai */ 22134eaa4710SRishi Srivatsavai static void 22144eaa4710SRishi Srivatsavai bridge_recv_cb(mac_handle_t mh, mac_resource_handle_t rsrc, mblk_t *mpnext) 22154eaa4710SRishi Srivatsavai { 22164eaa4710SRishi Srivatsavai mblk_t *mp, *mpcopy; 22174eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh; 22184eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 22194eaa4710SRishi Srivatsavai bridge_mac_t *bmp = bip->bi_mac; 22204eaa4710SRishi Srivatsavai mac_header_info_t hdr_info; 22214eaa4710SRishi Srivatsavai uint16_t vlanid, tci; 22224eaa4710SRishi Srivatsavai boolean_t trillmode = B_FALSE; 22234eaa4710SRishi Srivatsavai 22244eaa4710SRishi Srivatsavai KIINCR(bki_recv); 22254eaa4710SRishi Srivatsavai KLINCR(bkl_recv); 22264eaa4710SRishi Srivatsavai 22274eaa4710SRishi Srivatsavai /* 22284eaa4710SRishi Srivatsavai * Regardless of state, check for inbound TRILL packets when TRILL is 22294eaa4710SRishi Srivatsavai * active. These are pulled out of band and sent for TRILL handling. 22304eaa4710SRishi Srivatsavai */ 22314eaa4710SRishi Srivatsavai if (blp->bl_trilldata != NULL) { 22324eaa4710SRishi Srivatsavai void *tdp; 22334eaa4710SRishi Srivatsavai mblk_t *newhead; 22344eaa4710SRishi Srivatsavai mblk_t *tail = NULL; 22354eaa4710SRishi Srivatsavai 22364eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 22374eaa4710SRishi Srivatsavai if ((tdp = blp->bl_trilldata) != NULL) { 22384eaa4710SRishi Srivatsavai blp->bl_trillthreads++; 22394eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 22404eaa4710SRishi Srivatsavai trillmode = B_TRUE; 22414eaa4710SRishi Srivatsavai newhead = mpnext; 22424eaa4710SRishi Srivatsavai while ((mp = mpnext) != NULL) { 22434eaa4710SRishi Srivatsavai boolean_t raw_isis, bridge_group; 22444eaa4710SRishi Srivatsavai 22454eaa4710SRishi Srivatsavai mpnext = mp->b_next; 22464eaa4710SRishi Srivatsavai 22474eaa4710SRishi Srivatsavai /* 22484eaa4710SRishi Srivatsavai * If the header isn't readable, then leave on 22494eaa4710SRishi Srivatsavai * the list and continue. 22504eaa4710SRishi Srivatsavai */ 22514eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, 22524eaa4710SRishi Srivatsavai &hdr_info) != 0) { 22534eaa4710SRishi Srivatsavai tail = mp; 22544eaa4710SRishi Srivatsavai continue; 22554eaa4710SRishi Srivatsavai } 22564eaa4710SRishi Srivatsavai 22574eaa4710SRishi Srivatsavai /* 22584eaa4710SRishi Srivatsavai * The TRILL document specifies that, on 22594eaa4710SRishi Srivatsavai * Ethernet alone, IS-IS packets arrive with 22604eaa4710SRishi Srivatsavai * LLC rather than Ethertype, and using a 22614eaa4710SRishi Srivatsavai * specific destination address. We must check 22624eaa4710SRishi Srivatsavai * for that here. Also, we need to give BPDUs 22634eaa4710SRishi Srivatsavai * to TRILL for processing. 22644eaa4710SRishi Srivatsavai */ 22654eaa4710SRishi Srivatsavai raw_isis = bridge_group = B_FALSE; 22664eaa4710SRishi Srivatsavai if (hdr_info.mhi_dsttype == 22674eaa4710SRishi Srivatsavai MAC_ADDRTYPE_MULTICAST) { 22684eaa4710SRishi Srivatsavai if (memcmp(hdr_info.mhi_daddr, 22694eaa4710SRishi Srivatsavai all_isis_rbridges, ETHERADDRL) == 0) 22704eaa4710SRishi Srivatsavai raw_isis = B_TRUE; 22714eaa4710SRishi Srivatsavai else if (memcmp(hdr_info.mhi_daddr, 22724eaa4710SRishi Srivatsavai bridge_group_address, ETHERADDRL) == 22734eaa4710SRishi Srivatsavai 0) 22744eaa4710SRishi Srivatsavai bridge_group = B_TRUE; 22754eaa4710SRishi Srivatsavai } 22764eaa4710SRishi Srivatsavai if (!raw_isis && !bridge_group && 22774eaa4710SRishi Srivatsavai hdr_info.mhi_bindsap != ETHERTYPE_TRILL && 22784eaa4710SRishi Srivatsavai (hdr_info.mhi_bindsap != ETHERTYPE_VLAN || 22794eaa4710SRishi Srivatsavai /* LINTED: alignment */ 22804eaa4710SRishi Srivatsavai ((struct ether_vlan_header *)mp->b_rptr)-> 22814eaa4710SRishi Srivatsavai ether_type != htons(ETHERTYPE_TRILL))) { 22824eaa4710SRishi Srivatsavai tail = mp; 22834eaa4710SRishi Srivatsavai continue; 22844eaa4710SRishi Srivatsavai } 22854eaa4710SRishi Srivatsavai 22864eaa4710SRishi Srivatsavai /* 22874eaa4710SRishi Srivatsavai * We've got TRILL input. Remove from the list 22884eaa4710SRishi Srivatsavai * and send up through the TRILL module. (Send 22894eaa4710SRishi Srivatsavai * a copy through promiscuous receive just to 22904eaa4710SRishi Srivatsavai * support snooping on TRILL. Order isn't 22914eaa4710SRishi Srivatsavai * preserved strictly, but that doesn't matter 22924eaa4710SRishi Srivatsavai * here.) 22934eaa4710SRishi Srivatsavai */ 22944eaa4710SRishi Srivatsavai if (tail != NULL) 22954eaa4710SRishi Srivatsavai tail->b_next = mpnext; 22964eaa4710SRishi Srivatsavai mp->b_next = NULL; 22974eaa4710SRishi Srivatsavai if (mp == newhead) 22984eaa4710SRishi Srivatsavai newhead = mpnext; 22994eaa4710SRishi Srivatsavai mac_trill_snoop(blp->bl_mh, mp); 23004eaa4710SRishi Srivatsavai update_header(mp, &hdr_info, B_TRUE); 23014eaa4710SRishi Srivatsavai /* 23024eaa4710SRishi Srivatsavai * On raw IS-IS and BPDU frames, we have to 23034eaa4710SRishi Srivatsavai * make sure that the length is trimmed 23044eaa4710SRishi Srivatsavai * properly. We use origsap in order to cope 23054eaa4710SRishi Srivatsavai * with jumbograms for IS-IS. (Regular mac 23064eaa4710SRishi Srivatsavai * can't.) 23074eaa4710SRishi Srivatsavai */ 23084eaa4710SRishi Srivatsavai if (raw_isis || bridge_group) { 23094eaa4710SRishi Srivatsavai size_t msglen = msgdsize(mp); 23104eaa4710SRishi Srivatsavai 23114eaa4710SRishi Srivatsavai if (msglen > hdr_info.mhi_origsap) { 23124eaa4710SRishi Srivatsavai (void) adjmsg(mp, 23134eaa4710SRishi Srivatsavai hdr_info.mhi_origsap - 23144eaa4710SRishi Srivatsavai msglen); 23154eaa4710SRishi Srivatsavai } else if (msglen < 23164eaa4710SRishi Srivatsavai hdr_info.mhi_origsap) { 23174eaa4710SRishi Srivatsavai freemsg(mp); 23184eaa4710SRishi Srivatsavai continue; 23194eaa4710SRishi Srivatsavai } 23204eaa4710SRishi Srivatsavai } 23214eaa4710SRishi Srivatsavai trill_recv_fn(tdp, blp, rsrc, mp, &hdr_info); 23224eaa4710SRishi Srivatsavai } 23234eaa4710SRishi Srivatsavai mpnext = newhead; 23244eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock); 23254eaa4710SRishi Srivatsavai if (--blp->bl_trillthreads == 0 && 23264eaa4710SRishi Srivatsavai blp->bl_trilldata == NULL) 23274eaa4710SRishi Srivatsavai cv_broadcast(&blp->bl_trillwait); 23284eaa4710SRishi Srivatsavai } 23294eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock); 23304eaa4710SRishi Srivatsavai if (mpnext == NULL) 23314eaa4710SRishi Srivatsavai return; 23324eaa4710SRishi Srivatsavai } 23334eaa4710SRishi Srivatsavai 23344eaa4710SRishi Srivatsavai /* 23354eaa4710SRishi Srivatsavai * If this is a TRILL RBridge, then just check whether this link is 23364eaa4710SRishi Srivatsavai * used at all for forwarding. If not, then we're done. 23374eaa4710SRishi Srivatsavai */ 23384eaa4710SRishi Srivatsavai if (trillmode) { 23394eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_TRILLACTIVE) || 23404eaa4710SRishi Srivatsavai (blp->bl_flags & BLF_SDUFAIL)) { 23414eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mpnext); 23424eaa4710SRishi Srivatsavai return; 23434eaa4710SRishi Srivatsavai } 23444eaa4710SRishi Srivatsavai } else { 23454eaa4710SRishi Srivatsavai /* 23464eaa4710SRishi Srivatsavai * For regular (STP) bridges, if we're in blocking or listening 23474eaa4710SRishi Srivatsavai * state, then do nothing. We don't learn or forward until 23484eaa4710SRishi Srivatsavai * told to do so. 23494eaa4710SRishi Srivatsavai */ 23504eaa4710SRishi Srivatsavai if (blp->bl_state == BLS_BLOCKLISTEN) { 23514eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mpnext); 23524eaa4710SRishi Srivatsavai return; 23534eaa4710SRishi Srivatsavai } 23544eaa4710SRishi Srivatsavai } 23554eaa4710SRishi Srivatsavai 23564eaa4710SRishi Srivatsavai /* 23574eaa4710SRishi Srivatsavai * Send a copy of the message chain up to the observability node users. 23584eaa4710SRishi Srivatsavai * For TRILL, we must obey the VLAN AF rules, so we go packet-by- 23594eaa4710SRishi Srivatsavai * packet. 23604eaa4710SRishi Srivatsavai */ 23614eaa4710SRishi Srivatsavai if (!trillmode && blp->bl_state == BLS_FORWARDING && 23624eaa4710SRishi Srivatsavai (bmp->bm_flags & BMF_STARTED) && 23634eaa4710SRishi Srivatsavai (mp = copymsgchain(mpnext)) != NULL) { 23644eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mp); 23654eaa4710SRishi Srivatsavai } 23664eaa4710SRishi Srivatsavai 23674eaa4710SRishi Srivatsavai /* 23684eaa4710SRishi Srivatsavai * We must be in learning or forwarding state, or using TRILL on a link 23694eaa4710SRishi Srivatsavai * with one or more VLANs active. For each packet in the list, process 23704eaa4710SRishi Srivatsavai * the source address, and then attempt to forward. 23714eaa4710SRishi Srivatsavai */ 23724eaa4710SRishi Srivatsavai while ((mp = mpnext) != NULL) { 23734eaa4710SRishi Srivatsavai mpnext = mp->b_next; 23744eaa4710SRishi Srivatsavai mp->b_next = NULL; 23754eaa4710SRishi Srivatsavai 23764eaa4710SRishi Srivatsavai /* 23774eaa4710SRishi Srivatsavai * If we can't decode the header or if the header specifies a 23784eaa4710SRishi Srivatsavai * multicast source address (impossible!), then don't bother 23794eaa4710SRishi Srivatsavai * learning or forwarding, but go ahead and forward up the 23804eaa4710SRishi Srivatsavai * stack for subsequent processing. 23814eaa4710SRishi Srivatsavai */ 23824eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0 || 23834eaa4710SRishi Srivatsavai (hdr_info.mhi_saddr[0] & 1) != 0) { 23844eaa4710SRishi Srivatsavai KIINCR(bki_drops); 23854eaa4710SRishi Srivatsavai KLINCR(bkl_drops); 23864eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp); 23874eaa4710SRishi Srivatsavai continue; 23884eaa4710SRishi Srivatsavai } 23894eaa4710SRishi Srivatsavai 23904eaa4710SRishi Srivatsavai /* 23914eaa4710SRishi Srivatsavai * Extract and validate the VLAN ID for this packet. 23924eaa4710SRishi Srivatsavai */ 23934eaa4710SRishi Srivatsavai if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) || 23944eaa4710SRishi Srivatsavai !BRIDGE_AF_ISSET(blp, vlanid)) { 23954eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp); 23964eaa4710SRishi Srivatsavai continue; 23974eaa4710SRishi Srivatsavai } 23984eaa4710SRishi Srivatsavai 23994eaa4710SRishi Srivatsavai if (trillmode) { 24004eaa4710SRishi Srivatsavai /* 24014eaa4710SRishi Srivatsavai * Special test required by TRILL document: must 24024eaa4710SRishi Srivatsavai * discard frames with outer address set to ESADI. 24034eaa4710SRishi Srivatsavai */ 24044eaa4710SRishi Srivatsavai if (memcmp(hdr_info.mhi_daddr, all_esadi_rbridges, 24054eaa4710SRishi Srivatsavai ETHERADDRL) == 0) { 24064eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp); 24074eaa4710SRishi Srivatsavai continue; 24084eaa4710SRishi Srivatsavai } 24094eaa4710SRishi Srivatsavai 24104eaa4710SRishi Srivatsavai /* 24114eaa4710SRishi Srivatsavai * If we're in TRILL mode, then the call above to get 24124eaa4710SRishi Srivatsavai * the VLAN ID has also checked that we're the 24134eaa4710SRishi Srivatsavai * appointed forwarder, so report that we're handling 24144eaa4710SRishi Srivatsavai * this packet to any observability node users. 24154eaa4710SRishi Srivatsavai */ 24164eaa4710SRishi Srivatsavai if ((bmp->bm_flags & BMF_STARTED) && 24174eaa4710SRishi Srivatsavai (mpcopy = copymsg(mp)) != NULL) 24184eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mpcopy); 24194eaa4710SRishi Srivatsavai } 24204eaa4710SRishi Srivatsavai 24214eaa4710SRishi Srivatsavai /* 24224eaa4710SRishi Srivatsavai * First process the source address and learn from it. For 24234eaa4710SRishi Srivatsavai * TRILL, we learn only if we're the appointed forwarder. 24244eaa4710SRishi Srivatsavai */ 24254eaa4710SRishi Srivatsavai bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE, 24264eaa4710SRishi Srivatsavai vlanid); 24274eaa4710SRishi Srivatsavai 24284eaa4710SRishi Srivatsavai /* 24294eaa4710SRishi Srivatsavai * Now check whether we're forwarding and look up the 24304eaa4710SRishi Srivatsavai * destination. If we can forward, do so. 24314eaa4710SRishi Srivatsavai */ 24324eaa4710SRishi Srivatsavai if (trillmode || blp->bl_state == BLS_FORWARDING) { 24334eaa4710SRishi Srivatsavai mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, 24344eaa4710SRishi Srivatsavai B_FALSE, B_FALSE); 24354eaa4710SRishi Srivatsavai } 24364eaa4710SRishi Srivatsavai if (mp != NULL) 24374eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp); 24384eaa4710SRishi Srivatsavai } 24394eaa4710SRishi Srivatsavai } 24404eaa4710SRishi Srivatsavai 24414eaa4710SRishi Srivatsavai 24424eaa4710SRishi Srivatsavai /* ARGSUSED */ 24434eaa4710SRishi Srivatsavai static mblk_t * 24444eaa4710SRishi Srivatsavai bridge_xmit_cb(mac_handle_t mh, mac_ring_handle_t rh, mblk_t *mpnext) 24454eaa4710SRishi Srivatsavai { 24464eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh; 24474eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 24484eaa4710SRishi Srivatsavai bridge_mac_t *bmp = bip->bi_mac; 24494eaa4710SRishi Srivatsavai mac_header_info_t hdr_info; 24504eaa4710SRishi Srivatsavai uint16_t vlanid, tci; 24514eaa4710SRishi Srivatsavai mblk_t *mp, *mpcopy; 24524eaa4710SRishi Srivatsavai boolean_t trillmode; 24534eaa4710SRishi Srivatsavai 24544eaa4710SRishi Srivatsavai trillmode = blp->bl_trilldata != NULL; 24554eaa4710SRishi Srivatsavai 24564eaa4710SRishi Srivatsavai /* 24574eaa4710SRishi Srivatsavai * If we're using STP and we're in blocking or listening state, or if 24584eaa4710SRishi Srivatsavai * we're using TRILL and no VLANs are active, then behave as though the 24594eaa4710SRishi Srivatsavai * bridge isn't here at all, and send on the local link alone. 24604eaa4710SRishi Srivatsavai */ 24614eaa4710SRishi Srivatsavai if ((!trillmode && blp->bl_state == BLS_BLOCKLISTEN) || 24624eaa4710SRishi Srivatsavai (trillmode && 24634eaa4710SRishi Srivatsavai (!(blp->bl_flags & BLF_TRILLACTIVE) || 24644eaa4710SRishi Srivatsavai (blp->bl_flags & BLF_SDUFAIL)))) { 24654eaa4710SRishi Srivatsavai KIINCR(bki_sent); 24664eaa4710SRishi Srivatsavai KLINCR(bkl_xmit); 24674eaa4710SRishi Srivatsavai MAC_RING_TX(blp->bl_mh, rh, mpnext, mp); 24684eaa4710SRishi Srivatsavai return (mp); 24694eaa4710SRishi Srivatsavai } 24704eaa4710SRishi Srivatsavai 24714eaa4710SRishi Srivatsavai /* 24724eaa4710SRishi Srivatsavai * Send a copy of the message up to the observability node users. 24734eaa4710SRishi Srivatsavai * TRILL needs to check on a packet-by-packet basis. 24744eaa4710SRishi Srivatsavai */ 24754eaa4710SRishi Srivatsavai if (!trillmode && blp->bl_state == BLS_FORWARDING && 24764eaa4710SRishi Srivatsavai (bmp->bm_flags & BMF_STARTED) && 24774eaa4710SRishi Srivatsavai (mp = copymsgchain(mpnext)) != NULL) { 24784eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mp); 24794eaa4710SRishi Srivatsavai } 24804eaa4710SRishi Srivatsavai 24814eaa4710SRishi Srivatsavai while ((mp = mpnext) != NULL) { 24824eaa4710SRishi Srivatsavai mpnext = mp->b_next; 24834eaa4710SRishi Srivatsavai mp->b_next = NULL; 24844eaa4710SRishi Srivatsavai 24854eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) { 24864eaa4710SRishi Srivatsavai freemsg(mp); 24874eaa4710SRishi Srivatsavai continue; 24884eaa4710SRishi Srivatsavai } 24894eaa4710SRishi Srivatsavai 24904eaa4710SRishi Srivatsavai /* 24914eaa4710SRishi Srivatsavai * Extract and validate the VLAN ID for this packet. 24924eaa4710SRishi Srivatsavai */ 24934eaa4710SRishi Srivatsavai if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) || 24944eaa4710SRishi Srivatsavai !BRIDGE_AF_ISSET(blp, vlanid)) { 24954eaa4710SRishi Srivatsavai freemsg(mp); 24964eaa4710SRishi Srivatsavai continue; 24974eaa4710SRishi Srivatsavai } 24984eaa4710SRishi Srivatsavai 24994eaa4710SRishi Srivatsavai /* 25004eaa4710SRishi Srivatsavai * If we're using TRILL, then we've now validated that we're 25014eaa4710SRishi Srivatsavai * the forwarder for this VLAN, so go ahead and let 25024eaa4710SRishi Srivatsavai * observability node users know about the packet. 25034eaa4710SRishi Srivatsavai */ 25044eaa4710SRishi Srivatsavai if (trillmode && (bmp->bm_flags & BMF_STARTED) && 25054eaa4710SRishi Srivatsavai (mpcopy = copymsg(mp)) != NULL) { 25064eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mpcopy); 25074eaa4710SRishi Srivatsavai } 25084eaa4710SRishi Srivatsavai 25094eaa4710SRishi Srivatsavai /* 25104eaa4710SRishi Srivatsavai * We have to learn from our own transmitted packets, because 25114eaa4710SRishi Srivatsavai * there may be a Solaris DLPI raw sender (who can specify his 25124eaa4710SRishi Srivatsavai * own source address) using promiscuous mode for receive. The 25134eaa4710SRishi Srivatsavai * mac layer information won't (and can't) tell us everything 25144eaa4710SRishi Srivatsavai * we need to know. 25154eaa4710SRishi Srivatsavai */ 25164eaa4710SRishi Srivatsavai bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE, 25174eaa4710SRishi Srivatsavai vlanid); 25184eaa4710SRishi Srivatsavai 25194eaa4710SRishi Srivatsavai /* attempt forwarding */ 25204eaa4710SRishi Srivatsavai if (trillmode || blp->bl_state == BLS_FORWARDING) { 25214eaa4710SRishi Srivatsavai mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, 25224eaa4710SRishi Srivatsavai B_FALSE, B_TRUE); 25234eaa4710SRishi Srivatsavai } 25244eaa4710SRishi Srivatsavai if (mp != NULL) { 25254eaa4710SRishi Srivatsavai MAC_RING_TX(blp->bl_mh, rh, mp, mp); 25264eaa4710SRishi Srivatsavai if (mp == NULL) { 25274eaa4710SRishi Srivatsavai KIINCR(bki_sent); 25284eaa4710SRishi Srivatsavai KLINCR(bkl_xmit); 25294eaa4710SRishi Srivatsavai } 25304eaa4710SRishi Srivatsavai } 25314eaa4710SRishi Srivatsavai /* 25324eaa4710SRishi Srivatsavai * If we get stuck, then stop. Don't let the user's output 25334eaa4710SRishi Srivatsavai * packets get out of order. (More importantly: don't try to 25344eaa4710SRishi Srivatsavai * bridge the same packet multiple times if flow control is 25354eaa4710SRishi Srivatsavai * asserted.) 25364eaa4710SRishi Srivatsavai */ 25374eaa4710SRishi Srivatsavai if (mp != NULL) { 25384eaa4710SRishi Srivatsavai mp->b_next = mpnext; 25394eaa4710SRishi Srivatsavai break; 25404eaa4710SRishi Srivatsavai } 25414eaa4710SRishi Srivatsavai } 25424eaa4710SRishi Srivatsavai return (mp); 25434eaa4710SRishi Srivatsavai } 25444eaa4710SRishi Srivatsavai 25454eaa4710SRishi Srivatsavai /* 25464eaa4710SRishi Srivatsavai * This is called by TRILL when it decapsulates an packet, and we must forward 25474eaa4710SRishi Srivatsavai * locally. On failure, we just drop. 25484eaa4710SRishi Srivatsavai * 25494eaa4710SRishi Srivatsavai * Note that the ingress_nick reported by TRILL must not represent this local 25504eaa4710SRishi Srivatsavai * node. 25514eaa4710SRishi Srivatsavai */ 25524eaa4710SRishi Srivatsavai void 25534eaa4710SRishi Srivatsavai bridge_trill_decaps(bridge_link_t *blp, mblk_t *mp, uint16_t ingress_nick) 25544eaa4710SRishi Srivatsavai { 25554eaa4710SRishi Srivatsavai mac_header_info_t hdr_info; 25564eaa4710SRishi Srivatsavai uint16_t vlanid, tci; 25574eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; /* used by macros */ 25584eaa4710SRishi Srivatsavai mblk_t *mpcopy; 25594eaa4710SRishi Srivatsavai 25604eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) { 25614eaa4710SRishi Srivatsavai freemsg(mp); 25624eaa4710SRishi Srivatsavai return; 25634eaa4710SRishi Srivatsavai } 25644eaa4710SRishi Srivatsavai 25654eaa4710SRishi Srivatsavai /* Extract VLAN ID for this packet. */ 25664eaa4710SRishi Srivatsavai if (hdr_info.mhi_bindsap == ETHERTYPE_VLAN) { 25674eaa4710SRishi Srivatsavai struct ether_vlan_header *evhp; 25684eaa4710SRishi Srivatsavai 25694eaa4710SRishi Srivatsavai /* LINTED: alignment */ 25704eaa4710SRishi Srivatsavai evhp = (struct ether_vlan_header *)mp->b_rptr; 25714eaa4710SRishi Srivatsavai tci = ntohs(evhp->ether_tci); 25724eaa4710SRishi Srivatsavai vlanid = VLAN_ID(tci); 25734eaa4710SRishi Srivatsavai } else { 25744eaa4710SRishi Srivatsavai /* Inner VLAN headers are required in TRILL data packets */ 25754eaa4710SRishi Srivatsavai DTRACE_PROBE3(bridge__trill__decaps__novlan, bridge_link_t *, 25764eaa4710SRishi Srivatsavai blp, mblk_t *, mp, uint16_t, ingress_nick); 25774eaa4710SRishi Srivatsavai freemsg(mp); 25784eaa4710SRishi Srivatsavai return; 25794eaa4710SRishi Srivatsavai } 25804eaa4710SRishi Srivatsavai 25814eaa4710SRishi Srivatsavai /* Learn the location of this sender in the RBridge network */ 25824eaa4710SRishi Srivatsavai bridge_learn(blp, hdr_info.mhi_saddr, ingress_nick, vlanid); 25834eaa4710SRishi Srivatsavai 25844eaa4710SRishi Srivatsavai /* attempt forwarding */ 25854eaa4710SRishi Srivatsavai mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, B_TRUE, B_TRUE); 25864eaa4710SRishi Srivatsavai if (mp != NULL) { 25874eaa4710SRishi Srivatsavai if (bridge_can_send(blp, vlanid)) { 25884eaa4710SRishi Srivatsavai /* Deliver a copy locally as well */ 25894eaa4710SRishi Srivatsavai if ((mpcopy = copymsg(mp)) != NULL) 25904eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, NULL, mpcopy); 25914eaa4710SRishi Srivatsavai MAC_RING_TX(blp->bl_mh, NULL, mp, mp); 25924eaa4710SRishi Srivatsavai } 25934eaa4710SRishi Srivatsavai if (mp == NULL) { 25944eaa4710SRishi Srivatsavai KIINCR(bki_sent); 25954eaa4710SRishi Srivatsavai KLINCR(bkl_xmit); 25964eaa4710SRishi Srivatsavai } else { 25974eaa4710SRishi Srivatsavai freemsg(mp); 25984eaa4710SRishi Srivatsavai } 25994eaa4710SRishi Srivatsavai } 26004eaa4710SRishi Srivatsavai } 26014eaa4710SRishi Srivatsavai 26024eaa4710SRishi Srivatsavai /* 26034eaa4710SRishi Srivatsavai * This function is used by TRILL _only_ to transmit TRILL-encapsulated 26044eaa4710SRishi Srivatsavai * packets. It sends on a single underlying link and does not bridge. 26054eaa4710SRishi Srivatsavai */ 26064eaa4710SRishi Srivatsavai mblk_t * 26074eaa4710SRishi Srivatsavai bridge_trill_output(bridge_link_t *blp, mblk_t *mp) 26084eaa4710SRishi Srivatsavai { 26094eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; /* used by macros */ 26104eaa4710SRishi Srivatsavai 26114eaa4710SRishi Srivatsavai mac_trill_snoop(blp->bl_mh, mp); 26124eaa4710SRishi Srivatsavai MAC_RING_TX(blp->bl_mh, NULL, mp, mp); 26134eaa4710SRishi Srivatsavai if (mp == NULL) { 26144eaa4710SRishi Srivatsavai KIINCR(bki_sent); 26154eaa4710SRishi Srivatsavai KLINCR(bkl_xmit); 26164eaa4710SRishi Srivatsavai } 26174eaa4710SRishi Srivatsavai return (mp); 26184eaa4710SRishi Srivatsavai } 26194eaa4710SRishi Srivatsavai 26204eaa4710SRishi Srivatsavai /* 26214eaa4710SRishi Srivatsavai * Set the "appointed forwarder" flag array for this link. TRILL controls 26224eaa4710SRishi Srivatsavai * forwarding on a VLAN basis. The "trillactive" flag is an optimization for 26234eaa4710SRishi Srivatsavai * the forwarder. 26244eaa4710SRishi Srivatsavai */ 26254eaa4710SRishi Srivatsavai void 26264eaa4710SRishi Srivatsavai bridge_trill_setvlans(bridge_link_t *blp, const uint8_t *arr) 26274eaa4710SRishi Srivatsavai { 26284eaa4710SRishi Srivatsavai int i; 26294eaa4710SRishi Srivatsavai uint_t newflags = 0; 26304eaa4710SRishi Srivatsavai 26314eaa4710SRishi Srivatsavai for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) { 26324eaa4710SRishi Srivatsavai if ((blp->bl_afs[i] = arr[i]) != 0) 26334eaa4710SRishi Srivatsavai newflags = BLF_TRILLACTIVE; 26344eaa4710SRishi Srivatsavai } 26354eaa4710SRishi Srivatsavai blp->bl_flags = (blp->bl_flags & ~BLF_TRILLACTIVE) | newflags; 26364eaa4710SRishi Srivatsavai } 26374eaa4710SRishi Srivatsavai 26384eaa4710SRishi Srivatsavai void 26394eaa4710SRishi Srivatsavai bridge_trill_flush(bridge_link_t *blp, uint16_t vlan, boolean_t dotrill) 26404eaa4710SRishi Srivatsavai { 26414eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; 26424eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext; 26434eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge; 26444eaa4710SRishi Srivatsavai int i; 26454eaa4710SRishi Srivatsavai 26464eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(vlan)); 26474eaa4710SRishi Srivatsavai 26484eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 26494eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node)); 26504eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 26514eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd); 26524eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 26534eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 26544eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR) 26554eaa4710SRishi Srivatsavai continue; 26564eaa4710SRishi Srivatsavai if (dotrill) { 26574eaa4710SRishi Srivatsavai /* port doesn't matter if we're flushing TRILL */ 26584eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick == RBRIDGE_NICKNAME_NONE) 26594eaa4710SRishi Srivatsavai continue; 26604eaa4710SRishi Srivatsavai } else { 26614eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) 26624eaa4710SRishi Srivatsavai continue; 26634eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) { 26644eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) 26654eaa4710SRishi Srivatsavai break; 26664eaa4710SRishi Srivatsavai } 26674eaa4710SRishi Srivatsavai if (i >= bfp->bf_nlinks) 26684eaa4710SRishi Srivatsavai continue; 26694eaa4710SRishi Srivatsavai } 26704eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE); 26714eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 26724eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 26734eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp); 26744eaa4710SRishi Srivatsavai } 26754eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 26764eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge); 26774eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 26784eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp); 26794eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp); 26804eaa4710SRishi Srivatsavai fwd_unref(bfp); 26814eaa4710SRishi Srivatsavai } 26824eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge); 26834eaa4710SRishi Srivatsavai } 26844eaa4710SRishi Srivatsavai 26854eaa4710SRishi Srivatsavai /* 26864eaa4710SRishi Srivatsavai * Let the mac module take or drop a reference to a bridge link. When this is 26874eaa4710SRishi Srivatsavai * called, the mac module is holding the mi_bridge_lock, so the link cannot be 26884eaa4710SRishi Srivatsavai * in the process of entering or leaving a bridge. 26894eaa4710SRishi Srivatsavai */ 26904eaa4710SRishi Srivatsavai static void 26914eaa4710SRishi Srivatsavai bridge_ref_cb(mac_handle_t mh, boolean_t hold) 26924eaa4710SRishi Srivatsavai { 26934eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh; 26944eaa4710SRishi Srivatsavai 26954eaa4710SRishi Srivatsavai if (hold) 26964eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); 26974eaa4710SRishi Srivatsavai else 26984eaa4710SRishi Srivatsavai link_unref(blp); 26994eaa4710SRishi Srivatsavai } 27004eaa4710SRishi Srivatsavai 27014eaa4710SRishi Srivatsavai /* 27024eaa4710SRishi Srivatsavai * Handle link state changes reported by the mac layer. This acts as a filter 27034eaa4710SRishi Srivatsavai * for link state changes: if a link is reporting down, but there are other 27044eaa4710SRishi Srivatsavai * links still up on the bridge, then the state is changed to "up." When the 27054eaa4710SRishi Srivatsavai * last link goes down, all are marked down, and when the first link goes up, 27064eaa4710SRishi Srivatsavai * all are marked up. (Recursion is avoided by the use of the "redo" function.) 27074eaa4710SRishi Srivatsavai * 27084eaa4710SRishi Srivatsavai * We treat unknown as equivalent to "up." 27094eaa4710SRishi Srivatsavai */ 27104eaa4710SRishi Srivatsavai static link_state_t 27114eaa4710SRishi Srivatsavai bridge_ls_cb(mac_handle_t mh, link_state_t newls) 27124eaa4710SRishi Srivatsavai { 27134eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh; 27144eaa4710SRishi Srivatsavai bridge_link_t *blcmp; 27154eaa4710SRishi Srivatsavai bridge_inst_t *bip; 27164eaa4710SRishi Srivatsavai bridge_mac_t *bmp; 27174eaa4710SRishi Srivatsavai 27184eaa4710SRishi Srivatsavai if (newls != LINK_STATE_DOWN && blp->bl_linkstate != LINK_STATE_DOWN || 27194eaa4710SRishi Srivatsavai (blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) { 27204eaa4710SRishi Srivatsavai blp->bl_linkstate = newls; 27214eaa4710SRishi Srivatsavai return (newls); 27224eaa4710SRishi Srivatsavai } 27234eaa4710SRishi Srivatsavai 27244eaa4710SRishi Srivatsavai /* 27254eaa4710SRishi Srivatsavai * Scan first to see if there are any other non-down links. If there 27264eaa4710SRishi Srivatsavai * are, then we're done. Otherwise, if all others are down, then the 27274eaa4710SRishi Srivatsavai * state of this link is the state of the bridge. 27284eaa4710SRishi Srivatsavai */ 27294eaa4710SRishi Srivatsavai bip = blp->bl_inst; 27304eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 27314eaa4710SRishi Srivatsavai for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 27324eaa4710SRishi Srivatsavai blcmp = list_next(&bip->bi_links, blcmp)) { 27334eaa4710SRishi Srivatsavai if (blcmp != blp && 27344eaa4710SRishi Srivatsavai !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) && 27354eaa4710SRishi Srivatsavai blcmp->bl_linkstate != LINK_STATE_DOWN) 27364eaa4710SRishi Srivatsavai break; 27374eaa4710SRishi Srivatsavai } 27384eaa4710SRishi Srivatsavai 27394eaa4710SRishi Srivatsavai if (blcmp != NULL) { 27404eaa4710SRishi Srivatsavai /* 27414eaa4710SRishi Srivatsavai * If there are other links that are considered up, then tell 27424eaa4710SRishi Srivatsavai * the caller that the link is actually still up, regardless of 27434eaa4710SRishi Srivatsavai * this link's underlying state. 27444eaa4710SRishi Srivatsavai */ 27454eaa4710SRishi Srivatsavai blp->bl_linkstate = newls; 27464eaa4710SRishi Srivatsavai newls = LINK_STATE_UP; 27474eaa4710SRishi Srivatsavai } else if (blp->bl_linkstate != newls) { 27484eaa4710SRishi Srivatsavai /* 27494eaa4710SRishi Srivatsavai * If we've found no other 'up' links, and this link has 27504eaa4710SRishi Srivatsavai * changed state, then report the new state of the bridge to 27514eaa4710SRishi Srivatsavai * all other clients. 27524eaa4710SRishi Srivatsavai */ 27534eaa4710SRishi Srivatsavai blp->bl_linkstate = newls; 27544eaa4710SRishi Srivatsavai for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 27554eaa4710SRishi Srivatsavai blcmp = list_next(&bip->bi_links, blcmp)) { 27564eaa4710SRishi Srivatsavai if (blcmp != blp && !(blcmp->bl_flags & BLF_DELETED)) 27574eaa4710SRishi Srivatsavai mac_link_redo(blcmp->bl_mh, newls); 27584eaa4710SRishi Srivatsavai } 27594eaa4710SRishi Srivatsavai bmp = bip->bi_mac; 27604eaa4710SRishi Srivatsavai if ((bmp->bm_linkstate = newls) != LINK_STATE_DOWN) 27614eaa4710SRishi Srivatsavai bmp->bm_linkstate = LINK_STATE_UP; 27624eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, bmp->bm_linkstate); 27634eaa4710SRishi Srivatsavai } 27644eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 27654eaa4710SRishi Srivatsavai return (newls); 27664eaa4710SRishi Srivatsavai } 27674eaa4710SRishi Srivatsavai 27684eaa4710SRishi Srivatsavai static void 27694eaa4710SRishi Srivatsavai bridge_add_link(void *arg) 27704eaa4710SRishi Srivatsavai { 27714eaa4710SRishi Srivatsavai mblk_t *mp = arg; 27724eaa4710SRishi Srivatsavai bridge_stream_t *bsp; 27734eaa4710SRishi Srivatsavai bridge_inst_t *bip, *bipt; 27744eaa4710SRishi Srivatsavai bridge_mac_t *bmp; 27754eaa4710SRishi Srivatsavai datalink_id_t linkid; 27764eaa4710SRishi Srivatsavai int err; 27774eaa4710SRishi Srivatsavai mac_handle_t mh; 27784eaa4710SRishi Srivatsavai uint_t maxsdu; 27794eaa4710SRishi Srivatsavai bridge_link_t *blp = NULL, *blpt; 27804eaa4710SRishi Srivatsavai const mac_info_t *mip; 27814eaa4710SRishi Srivatsavai boolean_t macopen = B_FALSE; 27824eaa4710SRishi Srivatsavai char linkname[MAXLINKNAMELEN]; 27834eaa4710SRishi Srivatsavai char kstatname[KSTAT_STRLEN]; 27844eaa4710SRishi Srivatsavai int i; 27854eaa4710SRishi Srivatsavai link_state_t linkstate; 27864eaa4710SRishi Srivatsavai mblk_t *mlist; 27874eaa4710SRishi Srivatsavai 27884eaa4710SRishi Srivatsavai bsp = (bridge_stream_t *)mp->b_next; 27894eaa4710SRishi Srivatsavai mp->b_next = NULL; 27904eaa4710SRishi Srivatsavai bip = bsp->bs_inst; 27914eaa4710SRishi Srivatsavai /* LINTED: alignment */ 27924eaa4710SRishi Srivatsavai linkid = *(datalink_id_t *)mp->b_cont->b_rptr; 27934eaa4710SRishi Srivatsavai 27944eaa4710SRishi Srivatsavai /* 27954eaa4710SRishi Srivatsavai * First make sure that there is no other bridge that has this link. 27964eaa4710SRishi Srivatsavai * We don't want to overlap operations from two bridges; the MAC layer 27974eaa4710SRishi Srivatsavai * supports only one bridge on a given MAC at a time. 27984eaa4710SRishi Srivatsavai * 27994eaa4710SRishi Srivatsavai * We rely on the fact that there's just one taskq thread for the 28004eaa4710SRishi Srivatsavai * bridging module: once we've checked for a duplicate, we can drop the 28014eaa4710SRishi Srivatsavai * lock, because no other thread could possibly be adding another link 28024eaa4710SRishi Srivatsavai * until we're done. 28034eaa4710SRishi Srivatsavai */ 28044eaa4710SRishi Srivatsavai mutex_enter(&inst_lock); 28054eaa4710SRishi Srivatsavai for (bipt = list_head(&inst_list); bipt != NULL; 28064eaa4710SRishi Srivatsavai bipt = list_next(&inst_list, bipt)) { 28074eaa4710SRishi Srivatsavai rw_enter(&bipt->bi_rwlock, RW_READER); 28084eaa4710SRishi Srivatsavai for (blpt = list_head(&bipt->bi_links); blpt != NULL; 28094eaa4710SRishi Srivatsavai blpt = list_next(&bipt->bi_links, blpt)) { 28104eaa4710SRishi Srivatsavai if (linkid == blpt->bl_linkid) 28114eaa4710SRishi Srivatsavai break; 28124eaa4710SRishi Srivatsavai } 28134eaa4710SRishi Srivatsavai rw_exit(&bipt->bi_rwlock); 28144eaa4710SRishi Srivatsavai if (blpt != NULL) 28154eaa4710SRishi Srivatsavai break; 28164eaa4710SRishi Srivatsavai } 28174eaa4710SRishi Srivatsavai mutex_exit(&inst_lock); 28184eaa4710SRishi Srivatsavai if (bipt != NULL) { 28194eaa4710SRishi Srivatsavai err = EBUSY; 28204eaa4710SRishi Srivatsavai goto fail; 28214eaa4710SRishi Srivatsavai } 28224eaa4710SRishi Srivatsavai 28234eaa4710SRishi Srivatsavai if ((err = mac_open_by_linkid(linkid, &mh)) != 0) 28244eaa4710SRishi Srivatsavai goto fail; 28254eaa4710SRishi Srivatsavai macopen = B_TRUE; 28264eaa4710SRishi Srivatsavai 28274eaa4710SRishi Srivatsavai /* we bridge only Ethernet */ 28284eaa4710SRishi Srivatsavai mip = mac_info(mh); 28294eaa4710SRishi Srivatsavai if (mip->mi_media != DL_ETHER) { 28304eaa4710SRishi Srivatsavai err = ENOTSUP; 28314eaa4710SRishi Srivatsavai goto fail; 28324eaa4710SRishi Srivatsavai } 28334eaa4710SRishi Srivatsavai 28344eaa4710SRishi Srivatsavai /* 28354eaa4710SRishi Srivatsavai * Get the current maximum SDU on this interface. If there are other 28364eaa4710SRishi Srivatsavai * links on the bridge, then this one must match, or it errors out. 28374eaa4710SRishi Srivatsavai * Otherwise, the first link becomes the standard for the new bridge. 28384eaa4710SRishi Srivatsavai */ 28394eaa4710SRishi Srivatsavai mac_sdu_get(mh, NULL, &maxsdu); 28404eaa4710SRishi Srivatsavai bmp = bip->bi_mac; 28414eaa4710SRishi Srivatsavai if (list_is_empty(&bip->bi_links)) { 28424eaa4710SRishi Srivatsavai bmp->bm_maxsdu = maxsdu; 28434eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 28444eaa4710SRishi Srivatsavai } 28454eaa4710SRishi Srivatsavai 28464eaa4710SRishi Srivatsavai /* figure the kstat name; also used as the mac client name */ 28474eaa4710SRishi Srivatsavai i = MBLKL(mp->b_cont) - sizeof (datalink_id_t); 28484eaa4710SRishi Srivatsavai if (i < 0 || i >= MAXLINKNAMELEN) 28494eaa4710SRishi Srivatsavai i = MAXLINKNAMELEN - 1; 28504eaa4710SRishi Srivatsavai bcopy(mp->b_cont->b_rptr + sizeof (datalink_id_t), linkname, i); 28514eaa4710SRishi Srivatsavai linkname[i] = '\0'; 28524eaa4710SRishi Srivatsavai (void) snprintf(kstatname, sizeof (kstatname), "%s-%s", bip->bi_name, 28534eaa4710SRishi Srivatsavai linkname); 28544eaa4710SRishi Srivatsavai 28554eaa4710SRishi Srivatsavai if ((blp = kmem_zalloc(sizeof (*blp), KM_NOSLEEP)) == NULL) { 28564eaa4710SRishi Srivatsavai err = ENOMEM; 28574eaa4710SRishi Srivatsavai goto fail; 28584eaa4710SRishi Srivatsavai } 28594eaa4710SRishi Srivatsavai blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED); 28604eaa4710SRishi Srivatsavai if (blp->bl_lfailmp == NULL) { 28614eaa4710SRishi Srivatsavai kmem_free(blp, sizeof (*blp)); 28624eaa4710SRishi Srivatsavai err = ENOMEM; 28634eaa4710SRishi Srivatsavai goto fail; 28644eaa4710SRishi Srivatsavai } 28654eaa4710SRishi Srivatsavai 28664eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs); 28674eaa4710SRishi Srivatsavai blp->bl_inst = bip; 28684eaa4710SRishi Srivatsavai blp->bl_mh = mh; 28694eaa4710SRishi Srivatsavai blp->bl_linkid = linkid; 28704eaa4710SRishi Srivatsavai blp->bl_maxsdu = maxsdu; 28714eaa4710SRishi Srivatsavai cv_init(&blp->bl_trillwait, NULL, CV_DRIVER, NULL); 28724eaa4710SRishi Srivatsavai mutex_init(&blp->bl_trilllock, NULL, MUTEX_DRIVER, NULL); 28734eaa4710SRishi Srivatsavai (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs)); 28744eaa4710SRishi Srivatsavai 28754eaa4710SRishi Srivatsavai err = mac_client_open(mh, &blp->bl_mch, kstatname, 0); 28764eaa4710SRishi Srivatsavai if (err != 0) 28774eaa4710SRishi Srivatsavai goto fail; 28784eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_CLIENT_OPEN; 28794eaa4710SRishi Srivatsavai 28804eaa4710SRishi Srivatsavai err = mac_margin_add(mh, &blp->bl_margin, B_TRUE); 28814eaa4710SRishi Srivatsavai if (err != 0) 28824eaa4710SRishi Srivatsavai goto fail; 28834eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_MARGIN_ADDED; 28844eaa4710SRishi Srivatsavai 28854eaa4710SRishi Srivatsavai blp->bl_mnh = mac_notify_add(mh, bridge_notify_cb, blp); 28864eaa4710SRishi Srivatsavai 28874eaa4710SRishi Srivatsavai err = mac_bridge_set(mh, (mac_handle_t)blp); 28884eaa4710SRishi Srivatsavai if (err != 0) 28894eaa4710SRishi Srivatsavai goto fail; 28904eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_SET_BRIDGE; 28914eaa4710SRishi Srivatsavai 28924eaa4710SRishi Srivatsavai err = mac_promisc_add(blp->bl_mch, MAC_CLIENT_PROMISC_ALL, NULL, 28934eaa4710SRishi Srivatsavai blp, &blp->bl_mphp, MAC_PROMISC_FLAGS_NO_TX_LOOP); 28944eaa4710SRishi Srivatsavai if (err != 0) 28954eaa4710SRishi Srivatsavai goto fail; 28964eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_PROM_ADDED; 28974eaa4710SRishi Srivatsavai 28984eaa4710SRishi Srivatsavai bridge_new_unicst(blp); 28994eaa4710SRishi Srivatsavai 29004eaa4710SRishi Srivatsavai blp->bl_ksp = kstat_setup((kstat_named_t *)&blp->bl_kstats, 29014eaa4710SRishi Srivatsavai link_kstats_list, Dim(link_kstats_list), kstatname); 29024eaa4710SRishi Srivatsavai 29034eaa4710SRishi Srivatsavai /* 29044eaa4710SRishi Srivatsavai * The link holds a reference to the bridge instance, so that the 29054eaa4710SRishi Srivatsavai * instance can't go away before the link is freed. The insertion into 29064eaa4710SRishi Srivatsavai * bi_links holds a reference on the link. When marking as removed 29074eaa4710SRishi Srivatsavai * from bi_links (BLF_DELETED), drop the reference on the link. When 29084eaa4710SRishi Srivatsavai * freeing the link, drop the reference on the instance. 29094eaa4710SRishi Srivatsavai */ 29104eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 29114eaa4710SRishi Srivatsavai list_insert_tail(&bip->bi_links, blp); 29124eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); 29134eaa4710SRishi Srivatsavai 29144eaa4710SRishi Srivatsavai /* 29154eaa4710SRishi Srivatsavai * If the new link is no good on this bridge, then let the daemon know 29164eaa4710SRishi Srivatsavai * about the problem. 29174eaa4710SRishi Srivatsavai */ 29184eaa4710SRishi Srivatsavai mlist = NULL; 29194eaa4710SRishi Srivatsavai if (maxsdu != bmp->bm_maxsdu) 29204eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_TRUE, &mlist); 29214eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 29224eaa4710SRishi Srivatsavai send_up_messages(bip, mlist); 29234eaa4710SRishi Srivatsavai 29244eaa4710SRishi Srivatsavai /* 29254eaa4710SRishi Srivatsavai * Trigger a link state update so that if this link is the first one 29264eaa4710SRishi Srivatsavai * "up" in the bridge, then we notify everyone. This triggers a trip 29274eaa4710SRishi Srivatsavai * through bridge_ls_cb. 29284eaa4710SRishi Srivatsavai */ 29294eaa4710SRishi Srivatsavai linkstate = mac_stat_get(mh, MAC_STAT_LOWLINK_STATE); 29304eaa4710SRishi Srivatsavai blp->bl_linkstate = LINK_STATE_DOWN; 29314eaa4710SRishi Srivatsavai mac_link_update(mh, linkstate); 29324eaa4710SRishi Srivatsavai 29334eaa4710SRishi Srivatsavai /* 29344eaa4710SRishi Srivatsavai * We now need to report back to the stream that invoked us, and then 29354eaa4710SRishi Srivatsavai * drop the reference on the stream that we're holding. 29364eaa4710SRishi Srivatsavai */ 29374eaa4710SRishi Srivatsavai miocack(bsp->bs_wq, mp, 0, 0); 29384eaa4710SRishi Srivatsavai stream_unref(bsp); 29394eaa4710SRishi Srivatsavai return; 29404eaa4710SRishi Srivatsavai 29414eaa4710SRishi Srivatsavai fail: 29424eaa4710SRishi Srivatsavai if (blp == NULL) { 29434eaa4710SRishi Srivatsavai if (macopen) 29444eaa4710SRishi Srivatsavai mac_close(mh); 29454eaa4710SRishi Srivatsavai } else { 29464eaa4710SRishi Srivatsavai link_shutdown(blp); 29474eaa4710SRishi Srivatsavai link_free(blp); 29484eaa4710SRishi Srivatsavai } 29494eaa4710SRishi Srivatsavai miocnak(bsp->bs_wq, mp, 0, err); 29504eaa4710SRishi Srivatsavai stream_unref(bsp); 29514eaa4710SRishi Srivatsavai } 29524eaa4710SRishi Srivatsavai 29534eaa4710SRishi Srivatsavai static void 29544eaa4710SRishi Srivatsavai bridge_rem_link(void *arg) 29554eaa4710SRishi Srivatsavai { 29564eaa4710SRishi Srivatsavai mblk_t *mp = arg; 29574eaa4710SRishi Srivatsavai bridge_stream_t *bsp; 29584eaa4710SRishi Srivatsavai bridge_inst_t *bip; 29594eaa4710SRishi Srivatsavai bridge_mac_t *bmp; 29604eaa4710SRishi Srivatsavai datalink_id_t linkid; 29614eaa4710SRishi Srivatsavai bridge_link_t *blp, *blsave; 29624eaa4710SRishi Srivatsavai boolean_t found; 29634eaa4710SRishi Srivatsavai mblk_t *mlist; 29644eaa4710SRishi Srivatsavai 29654eaa4710SRishi Srivatsavai bsp = (bridge_stream_t *)mp->b_next; 29664eaa4710SRishi Srivatsavai mp->b_next = NULL; 29674eaa4710SRishi Srivatsavai bip = bsp->bs_inst; 29684eaa4710SRishi Srivatsavai /* LINTED: alignment */ 29694eaa4710SRishi Srivatsavai linkid = *(datalink_id_t *)mp->b_cont->b_rptr; 29704eaa4710SRishi Srivatsavai 29714eaa4710SRishi Srivatsavai /* 29724eaa4710SRishi Srivatsavai * We become reader here so that we can loop over the other links and 29734eaa4710SRishi Srivatsavai * deliver link up/down notification. 29744eaa4710SRishi Srivatsavai */ 29754eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 29764eaa4710SRishi Srivatsavai found = B_FALSE; 29774eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 29784eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 29794eaa4710SRishi Srivatsavai if (blp->bl_linkid == linkid && 29804eaa4710SRishi Srivatsavai !(blp->bl_flags & BLF_DELETED)) { 29814eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_DELETED; 29824eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown, 29834eaa4710SRishi Srivatsavai blp, DDI_SLEEP); 29844eaa4710SRishi Srivatsavai found = B_TRUE; 29854eaa4710SRishi Srivatsavai break; 29864eaa4710SRishi Srivatsavai } 29874eaa4710SRishi Srivatsavai } 29884eaa4710SRishi Srivatsavai 29894eaa4710SRishi Srivatsavai /* 29904eaa4710SRishi Srivatsavai * Check if this link is up and the remainder of the links are all 29914eaa4710SRishi Srivatsavai * down. 29924eaa4710SRishi Srivatsavai */ 29934eaa4710SRishi Srivatsavai if (blp != NULL && blp->bl_linkstate != LINK_STATE_DOWN) { 29944eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 29954eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 29964eaa4710SRishi Srivatsavai if (blp->bl_linkstate != LINK_STATE_DOWN && 29974eaa4710SRishi Srivatsavai !(blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) 29984eaa4710SRishi Srivatsavai break; 29994eaa4710SRishi Srivatsavai } 30004eaa4710SRishi Srivatsavai if (blp == NULL) { 30014eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 30024eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 30034eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED)) 30044eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh, 30054eaa4710SRishi Srivatsavai LINK_STATE_DOWN); 30064eaa4710SRishi Srivatsavai } 30074eaa4710SRishi Srivatsavai bmp = bip->bi_mac; 30084eaa4710SRishi Srivatsavai bmp->bm_linkstate = LINK_STATE_DOWN; 30094eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN); 30104eaa4710SRishi Srivatsavai } 30114eaa4710SRishi Srivatsavai } 30124eaa4710SRishi Srivatsavai 30134eaa4710SRishi Srivatsavai /* 30144eaa4710SRishi Srivatsavai * Check if there's just one working link left on the bridge. If so, 30154eaa4710SRishi Srivatsavai * then that link is now authoritative for bridge MTU. 30164eaa4710SRishi Srivatsavai */ 30174eaa4710SRishi Srivatsavai blsave = NULL; 30184eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 30194eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 30204eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED)) { 30214eaa4710SRishi Srivatsavai if (blsave == NULL) 30224eaa4710SRishi Srivatsavai blsave = blp; 30234eaa4710SRishi Srivatsavai else 30244eaa4710SRishi Srivatsavai break; 30254eaa4710SRishi Srivatsavai } 30264eaa4710SRishi Srivatsavai } 30274eaa4710SRishi Srivatsavai mlist = NULL; 30284eaa4710SRishi Srivatsavai bmp = bip->bi_mac; 30294eaa4710SRishi Srivatsavai if (blsave != NULL && blp == NULL && 30304eaa4710SRishi Srivatsavai blsave->bl_maxsdu != bmp->bm_maxsdu) { 30314eaa4710SRishi Srivatsavai bmp->bm_maxsdu = blsave->bl_maxsdu; 30324eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, blsave->bl_maxsdu); 30334eaa4710SRishi Srivatsavai link_sdu_fail(blsave, B_FALSE, &mlist); 30344eaa4710SRishi Srivatsavai } 30354eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 30364eaa4710SRishi Srivatsavai send_up_messages(bip, mlist); 30374eaa4710SRishi Srivatsavai 30384eaa4710SRishi Srivatsavai if (found) 30394eaa4710SRishi Srivatsavai miocack(bsp->bs_wq, mp, 0, 0); 30404eaa4710SRishi Srivatsavai else 30414eaa4710SRishi Srivatsavai miocnak(bsp->bs_wq, mp, 0, ENOENT); 30424eaa4710SRishi Srivatsavai stream_unref(bsp); 30434eaa4710SRishi Srivatsavai } 30444eaa4710SRishi Srivatsavai 30454eaa4710SRishi Srivatsavai /* 30464eaa4710SRishi Srivatsavai * This function intentionally returns with bi_rwlock held; it is intended for 30474eaa4710SRishi Srivatsavai * quick checks and updates. 30484eaa4710SRishi Srivatsavai */ 30494eaa4710SRishi Srivatsavai static bridge_link_t * 30504eaa4710SRishi Srivatsavai enter_link(bridge_inst_t *bip, datalink_id_t linkid) 30514eaa4710SRishi Srivatsavai { 30524eaa4710SRishi Srivatsavai bridge_link_t *blp; 30534eaa4710SRishi Srivatsavai 30544eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER); 30554eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 30564eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 30574eaa4710SRishi Srivatsavai if (blp->bl_linkid == linkid && !(blp->bl_flags & BLF_DELETED)) 30584eaa4710SRishi Srivatsavai break; 30594eaa4710SRishi Srivatsavai } 30604eaa4710SRishi Srivatsavai return (blp); 30614eaa4710SRishi Srivatsavai } 30624eaa4710SRishi Srivatsavai 30634eaa4710SRishi Srivatsavai static void 30644eaa4710SRishi Srivatsavai bridge_ioctl(queue_t *wq, mblk_t *mp) 30654eaa4710SRishi Srivatsavai { 30664eaa4710SRishi Srivatsavai bridge_stream_t *bsp = wq->q_ptr; 30674eaa4710SRishi Srivatsavai bridge_inst_t *bip; 30684eaa4710SRishi Srivatsavai struct iocblk *iop; 30694eaa4710SRishi Srivatsavai int rc = EINVAL; 30704eaa4710SRishi Srivatsavai int len = 0; 30714eaa4710SRishi Srivatsavai bridge_link_t *blp; 30724eaa4710SRishi Srivatsavai cred_t *cr; 30734eaa4710SRishi Srivatsavai 30744eaa4710SRishi Srivatsavai /* LINTED: alignment */ 30754eaa4710SRishi Srivatsavai iop = (struct iocblk *)mp->b_rptr; 30764eaa4710SRishi Srivatsavai 30774eaa4710SRishi Srivatsavai /* 30784eaa4710SRishi Srivatsavai * For now, all of the bridge ioctls are privileged. 30794eaa4710SRishi Srivatsavai */ 30804eaa4710SRishi Srivatsavai if ((cr = msg_getcred(mp, NULL)) == NULL) 30814eaa4710SRishi Srivatsavai cr = iop->ioc_cr; 30824eaa4710SRishi Srivatsavai if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0) { 30834eaa4710SRishi Srivatsavai miocnak(wq, mp, 0, EPERM); 30844eaa4710SRishi Srivatsavai return; 30854eaa4710SRishi Srivatsavai } 30864eaa4710SRishi Srivatsavai 30874eaa4710SRishi Srivatsavai switch (iop->ioc_cmd) { 30884eaa4710SRishi Srivatsavai case BRIOC_NEWBRIDGE: { 30894eaa4710SRishi Srivatsavai bridge_newbridge_t *bnb; 30904eaa4710SRishi Srivatsavai 30914eaa4710SRishi Srivatsavai if (bsp->bs_inst != NULL || 30924eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (bridge_newbridge_t))) != 0) 30934eaa4710SRishi Srivatsavai break; 30944eaa4710SRishi Srivatsavai /* LINTED: alignment */ 30954eaa4710SRishi Srivatsavai bnb = (bridge_newbridge_t *)mp->b_cont->b_rptr; 30964eaa4710SRishi Srivatsavai bnb->bnb_name[MAXNAMELEN-1] = '\0'; 30974eaa4710SRishi Srivatsavai if ((rc = bridge_create(bnb->bnb_linkid, 30984eaa4710SRishi Srivatsavai bnb->bnb_name, &bip)) != 0) 30994eaa4710SRishi Srivatsavai break; 31004eaa4710SRishi Srivatsavai 31014eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 31024eaa4710SRishi Srivatsavai if (bip->bi_control != NULL) { 31034eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 31044eaa4710SRishi Srivatsavai bridge_unref(bip); 31054eaa4710SRishi Srivatsavai rc = EBUSY; 31064eaa4710SRishi Srivatsavai } else { 31074eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs); 31084eaa4710SRishi Srivatsavai bsp->bs_inst = bip; /* stream holds reference */ 31094eaa4710SRishi Srivatsavai bip->bi_control = bsp; 31104eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 31114eaa4710SRishi Srivatsavai rc = 0; 31124eaa4710SRishi Srivatsavai } 31134eaa4710SRishi Srivatsavai break; 31144eaa4710SRishi Srivatsavai } 31154eaa4710SRishi Srivatsavai 31164eaa4710SRishi Srivatsavai case BRIOC_ADDLINK: 31174eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 31184eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0) 31194eaa4710SRishi Srivatsavai break; 31204eaa4710SRishi Srivatsavai /* 31214eaa4710SRishi Srivatsavai * We cannot perform the action in this thread, because we're 31224eaa4710SRishi Srivatsavai * not in process context, and we may already be holding 31234eaa4710SRishi Srivatsavai * MAC-related locks. Place the request on taskq. 31244eaa4710SRishi Srivatsavai */ 31254eaa4710SRishi Srivatsavai mp->b_next = (mblk_t *)bsp; 31264eaa4710SRishi Srivatsavai stream_ref(bsp); 31274eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, bridge_add_link, mp, 31284eaa4710SRishi Srivatsavai DDI_SLEEP); 31294eaa4710SRishi Srivatsavai return; 31304eaa4710SRishi Srivatsavai 31314eaa4710SRishi Srivatsavai case BRIOC_REMLINK: 31324eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 31334eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0) 31344eaa4710SRishi Srivatsavai break; 31354eaa4710SRishi Srivatsavai /* 31364eaa4710SRishi Srivatsavai * We cannot perform the action in this thread, because we're 31374eaa4710SRishi Srivatsavai * not in process context, and we may already be holding 31384eaa4710SRishi Srivatsavai * MAC-related locks. Place the request on taskq. 31394eaa4710SRishi Srivatsavai */ 31404eaa4710SRishi Srivatsavai mp->b_next = (mblk_t *)bsp; 31414eaa4710SRishi Srivatsavai stream_ref(bsp); 31424eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, bridge_rem_link, mp, 31434eaa4710SRishi Srivatsavai DDI_SLEEP); 31444eaa4710SRishi Srivatsavai return; 31454eaa4710SRishi Srivatsavai 31464eaa4710SRishi Srivatsavai case BRIOC_SETSTATE: { 31474eaa4710SRishi Srivatsavai bridge_setstate_t *bss; 31484eaa4710SRishi Srivatsavai 31494eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 31504eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bss))) != 0) 31514eaa4710SRishi Srivatsavai break; 31524eaa4710SRishi Srivatsavai /* LINTED: alignment */ 31534eaa4710SRishi Srivatsavai bss = (bridge_setstate_t *)mp->b_cont->b_rptr; 31544eaa4710SRishi Srivatsavai if ((blp = enter_link(bip, bss->bss_linkid)) == NULL) { 31554eaa4710SRishi Srivatsavai rc = ENOENT; 31564eaa4710SRishi Srivatsavai } else { 31574eaa4710SRishi Srivatsavai rc = 0; 31584eaa4710SRishi Srivatsavai blp->bl_state = bss->bss_state; 31594eaa4710SRishi Srivatsavai } 31604eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 31614eaa4710SRishi Srivatsavai break; 31624eaa4710SRishi Srivatsavai } 31634eaa4710SRishi Srivatsavai 31644eaa4710SRishi Srivatsavai case BRIOC_SETPVID: { 31654eaa4710SRishi Srivatsavai bridge_setpvid_t *bsv; 31664eaa4710SRishi Srivatsavai 31674eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 31684eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bsv))) != 0) 31694eaa4710SRishi Srivatsavai break; 31704eaa4710SRishi Srivatsavai /* LINTED: alignment */ 31714eaa4710SRishi Srivatsavai bsv = (bridge_setpvid_t *)mp->b_cont->b_rptr; 31724eaa4710SRishi Srivatsavai if (bsv->bsv_vlan > VLAN_ID_MAX) 31734eaa4710SRishi Srivatsavai break; 31744eaa4710SRishi Srivatsavai if ((blp = enter_link(bip, bsv->bsv_linkid)) == NULL) { 31754eaa4710SRishi Srivatsavai rc = ENOENT; 31764eaa4710SRishi Srivatsavai } else if (blp->bl_pvid == bsv->bsv_vlan) { 31774eaa4710SRishi Srivatsavai rc = 0; 31784eaa4710SRishi Srivatsavai } else { 31794eaa4710SRishi Srivatsavai rc = 0; 31804eaa4710SRishi Srivatsavai BRIDGE_VLAN_CLR(blp, blp->bl_pvid); 31814eaa4710SRishi Srivatsavai blp->bl_pvid = bsv->bsv_vlan; 31824eaa4710SRishi Srivatsavai if (blp->bl_pvid != 0) 31834eaa4710SRishi Srivatsavai BRIDGE_VLAN_SET(blp, blp->bl_pvid); 31844eaa4710SRishi Srivatsavai } 31854eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 31864eaa4710SRishi Srivatsavai break; 31874eaa4710SRishi Srivatsavai } 31884eaa4710SRishi Srivatsavai 31894eaa4710SRishi Srivatsavai case BRIOC_VLANENAB: { 31904eaa4710SRishi Srivatsavai bridge_vlanenab_t *bve; 31914eaa4710SRishi Srivatsavai 31924eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 31934eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bve))) != 0) 31944eaa4710SRishi Srivatsavai break; 31954eaa4710SRishi Srivatsavai /* LINTED: alignment */ 31964eaa4710SRishi Srivatsavai bve = (bridge_vlanenab_t *)mp->b_cont->b_rptr; 31974eaa4710SRishi Srivatsavai if (bve->bve_vlan > VLAN_ID_MAX) 31984eaa4710SRishi Srivatsavai break; 31994eaa4710SRishi Srivatsavai if ((blp = enter_link(bip, bve->bve_linkid)) == NULL) { 32004eaa4710SRishi Srivatsavai rc = ENOENT; 32014eaa4710SRishi Srivatsavai } else { 32024eaa4710SRishi Srivatsavai rc = 0; 32034eaa4710SRishi Srivatsavai /* special case: vlan 0 means "all" */ 32044eaa4710SRishi Srivatsavai if (bve->bve_vlan == 0) { 32054eaa4710SRishi Srivatsavai (void) memset(blp->bl_vlans, 32064eaa4710SRishi Srivatsavai bve->bve_onoff ? ~0 : 0, 32074eaa4710SRishi Srivatsavai sizeof (blp->bl_vlans)); 32084eaa4710SRishi Srivatsavai BRIDGE_VLAN_CLR(blp, 0); 32094eaa4710SRishi Srivatsavai if (blp->bl_pvid != 0) 32104eaa4710SRishi Srivatsavai BRIDGE_VLAN_SET(blp, blp->bl_pvid); 32114eaa4710SRishi Srivatsavai } else if (bve->bve_vlan == blp->bl_pvid) { 32124eaa4710SRishi Srivatsavai rc = EINVAL; 32134eaa4710SRishi Srivatsavai } else if (bve->bve_onoff) { 32144eaa4710SRishi Srivatsavai BRIDGE_VLAN_SET(blp, bve->bve_vlan); 32154eaa4710SRishi Srivatsavai } else { 32164eaa4710SRishi Srivatsavai BRIDGE_VLAN_CLR(blp, bve->bve_vlan); 32174eaa4710SRishi Srivatsavai } 32184eaa4710SRishi Srivatsavai } 32194eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 32204eaa4710SRishi Srivatsavai break; 32214eaa4710SRishi Srivatsavai } 32224eaa4710SRishi Srivatsavai 32234eaa4710SRishi Srivatsavai case BRIOC_FLUSHFWD: { 32244eaa4710SRishi Srivatsavai bridge_flushfwd_t *bff; 32254eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext; 32264eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge; 32274eaa4710SRishi Srivatsavai int i; 32284eaa4710SRishi Srivatsavai 32294eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 32304eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bff))) != 0) 32314eaa4710SRishi Srivatsavai break; 32324eaa4710SRishi Srivatsavai /* LINTED: alignment */ 32334eaa4710SRishi Srivatsavai bff = (bridge_flushfwd_t *)mp->b_cont->b_rptr; 32344eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER); 32354eaa4710SRishi Srivatsavai /* This case means "all" */ 32364eaa4710SRishi Srivatsavai if (bff->bff_linkid == DATALINK_INVALID_LINKID) { 32374eaa4710SRishi Srivatsavai blp = NULL; 32384eaa4710SRishi Srivatsavai } else { 32394eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL; 32404eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) { 32414eaa4710SRishi Srivatsavai if (blp->bl_linkid == bff->bff_linkid && 32424eaa4710SRishi Srivatsavai !(blp->bl_flags & BLF_DELETED)) 32434eaa4710SRishi Srivatsavai break; 32444eaa4710SRishi Srivatsavai } 32454eaa4710SRishi Srivatsavai if (blp == NULL) { 32464eaa4710SRishi Srivatsavai rc = ENOENT; 32474eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 32484eaa4710SRishi Srivatsavai break; 32494eaa4710SRishi Srivatsavai } 32504eaa4710SRishi Srivatsavai } 32514eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 32524eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node)); 32534eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd); 32544eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 32554eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 32564eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR) 32574eaa4710SRishi Srivatsavai continue; 32584eaa4710SRishi Srivatsavai if (blp != NULL) { 32594eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_maxlinks; i++) { 32604eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) 32614eaa4710SRishi Srivatsavai break; 32624eaa4710SRishi Srivatsavai } 32634eaa4710SRishi Srivatsavai /* 32644eaa4710SRishi Srivatsavai * If the link is there and we're excluding, 32654eaa4710SRishi Srivatsavai * then skip. If the link is not there and 32664eaa4710SRishi Srivatsavai * we're doing only that link, then skip. 32674eaa4710SRishi Srivatsavai */ 32684eaa4710SRishi Srivatsavai if ((i < bfp->bf_maxlinks) == bff->bff_exclude) 32694eaa4710SRishi Srivatsavai continue; 32704eaa4710SRishi Srivatsavai } 32714eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE); 32724eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp); 32734eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE; 32744eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp); 32754eaa4710SRishi Srivatsavai } 32764eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock); 32774eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge); 32784eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) { 32794eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp); 32804eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp); 32814eaa4710SRishi Srivatsavai fwd_unref(bfp); /* drop tree reference */ 32824eaa4710SRishi Srivatsavai } 32834eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge); 32844eaa4710SRishi Srivatsavai break; 32854eaa4710SRishi Srivatsavai } 32864eaa4710SRishi Srivatsavai 32874eaa4710SRishi Srivatsavai case BRIOC_TABLEMAX: 32884eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL || 32894eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (uint32_t))) != 0) 32904eaa4710SRishi Srivatsavai break; 32914eaa4710SRishi Srivatsavai /* LINTED: alignment */ 32924eaa4710SRishi Srivatsavai bip->bi_tablemax = *(uint32_t *)mp->b_cont->b_rptr; 32934eaa4710SRishi Srivatsavai break; 32944eaa4710SRishi Srivatsavai } 32954eaa4710SRishi Srivatsavai 32964eaa4710SRishi Srivatsavai if (rc == 0) 32974eaa4710SRishi Srivatsavai miocack(wq, mp, len, 0); 32984eaa4710SRishi Srivatsavai else 32994eaa4710SRishi Srivatsavai miocnak(wq, mp, 0, rc); 33004eaa4710SRishi Srivatsavai } 33014eaa4710SRishi Srivatsavai 33024eaa4710SRishi Srivatsavai static void 33034eaa4710SRishi Srivatsavai bridge_wput(queue_t *wq, mblk_t *mp) 33044eaa4710SRishi Srivatsavai { 33054eaa4710SRishi Srivatsavai switch (DB_TYPE(mp)) { 33064eaa4710SRishi Srivatsavai case M_IOCTL: 33074eaa4710SRishi Srivatsavai bridge_ioctl(wq, mp); 33084eaa4710SRishi Srivatsavai break; 33094eaa4710SRishi Srivatsavai case M_FLUSH: 33104eaa4710SRishi Srivatsavai if (*mp->b_rptr & FLUSHW) 33114eaa4710SRishi Srivatsavai *mp->b_rptr &= ~FLUSHW; 33124eaa4710SRishi Srivatsavai if (*mp->b_rptr & FLUSHR) 33134eaa4710SRishi Srivatsavai qreply(wq, mp); 33144eaa4710SRishi Srivatsavai else 33154eaa4710SRishi Srivatsavai freemsg(mp); 33164eaa4710SRishi Srivatsavai break; 33174eaa4710SRishi Srivatsavai default: 33184eaa4710SRishi Srivatsavai freemsg(mp); 33194eaa4710SRishi Srivatsavai break; 33204eaa4710SRishi Srivatsavai } 33214eaa4710SRishi Srivatsavai } 33224eaa4710SRishi Srivatsavai 33234eaa4710SRishi Srivatsavai /* 33244eaa4710SRishi Srivatsavai * This function allocates the main data structures for the bridge driver and 33254eaa4710SRishi Srivatsavai * connects us into devfs. 33264eaa4710SRishi Srivatsavai */ 33274eaa4710SRishi Srivatsavai static void 33284eaa4710SRishi Srivatsavai bridge_inst_init(void) 33294eaa4710SRishi Srivatsavai { 33304eaa4710SRishi Srivatsavai bridge_scan_interval = 5 * drv_usectohz(1000000); 33314eaa4710SRishi Srivatsavai bridge_fwd_age = 25 * drv_usectohz(1000000); 33324eaa4710SRishi Srivatsavai 33334eaa4710SRishi Srivatsavai rw_init(&bmac_rwlock, NULL, RW_DRIVER, NULL); 33344eaa4710SRishi Srivatsavai list_create(&bmac_list, sizeof (bridge_mac_t), 33354eaa4710SRishi Srivatsavai offsetof(bridge_mac_t, bm_node)); 33364eaa4710SRishi Srivatsavai list_create(&inst_list, sizeof (bridge_inst_t), 33374eaa4710SRishi Srivatsavai offsetof(bridge_inst_t, bi_node)); 33384eaa4710SRishi Srivatsavai cv_init(&inst_cv, NULL, CV_DRIVER, NULL); 33394eaa4710SRishi Srivatsavai mutex_init(&inst_lock, NULL, MUTEX_DRIVER, NULL); 33404eaa4710SRishi Srivatsavai cv_init(&stream_ref_cv, NULL, CV_DRIVER, NULL); 33414eaa4710SRishi Srivatsavai mutex_init(&stream_ref_lock, NULL, MUTEX_DRIVER, NULL); 33424eaa4710SRishi Srivatsavai 33434eaa4710SRishi Srivatsavai mac_bridge_vectors(bridge_xmit_cb, bridge_recv_cb, bridge_ref_cb, 33444eaa4710SRishi Srivatsavai bridge_ls_cb); 33454eaa4710SRishi Srivatsavai } 33464eaa4710SRishi Srivatsavai 33474eaa4710SRishi Srivatsavai /* 33484eaa4710SRishi Srivatsavai * This function disconnects from devfs and destroys all data structures in 33494eaa4710SRishi Srivatsavai * preparation for unload. It's assumed that there are no active bridge 33504eaa4710SRishi Srivatsavai * references left at this point. 33514eaa4710SRishi Srivatsavai */ 33524eaa4710SRishi Srivatsavai static void 33534eaa4710SRishi Srivatsavai bridge_inst_fini(void) 33544eaa4710SRishi Srivatsavai { 33554eaa4710SRishi Srivatsavai mac_bridge_vectors(NULL, NULL, NULL, NULL); 33564eaa4710SRishi Srivatsavai if (bridge_timerid != 0) 33574eaa4710SRishi Srivatsavai (void) untimeout(bridge_timerid); 33584eaa4710SRishi Srivatsavai rw_destroy(&bmac_rwlock); 33594eaa4710SRishi Srivatsavai list_destroy(&bmac_list); 33604eaa4710SRishi Srivatsavai list_destroy(&inst_list); 33614eaa4710SRishi Srivatsavai cv_destroy(&inst_cv); 33624eaa4710SRishi Srivatsavai mutex_destroy(&inst_lock); 33634eaa4710SRishi Srivatsavai cv_destroy(&stream_ref_cv); 33644eaa4710SRishi Srivatsavai mutex_destroy(&stream_ref_lock); 33654eaa4710SRishi Srivatsavai } 33664eaa4710SRishi Srivatsavai 33674eaa4710SRishi Srivatsavai /* 33684eaa4710SRishi Srivatsavai * bridge_attach() 33694eaa4710SRishi Srivatsavai * 33704eaa4710SRishi Srivatsavai * Description: 33714eaa4710SRishi Srivatsavai * Attach bridge driver to the system. 33724eaa4710SRishi Srivatsavai */ 33734eaa4710SRishi Srivatsavai static int 33744eaa4710SRishi Srivatsavai bridge_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 33754eaa4710SRishi Srivatsavai { 33764eaa4710SRishi Srivatsavai if (cmd != DDI_ATTACH) 33774eaa4710SRishi Srivatsavai return (DDI_FAILURE); 33784eaa4710SRishi Srivatsavai 33794eaa4710SRishi Srivatsavai if (ddi_create_minor_node(dip, BRIDGE_CTL, S_IFCHR, 0, DDI_PSEUDO, 33804eaa4710SRishi Srivatsavai CLONE_DEV) == DDI_FAILURE) { 33814eaa4710SRishi Srivatsavai return (DDI_FAILURE); 33824eaa4710SRishi Srivatsavai } 33834eaa4710SRishi Srivatsavai 33844eaa4710SRishi Srivatsavai if (dld_ioc_register(BRIDGE_IOC, bridge_ioc_list, 33854eaa4710SRishi Srivatsavai DLDIOCCNT(bridge_ioc_list)) != 0) { 33864eaa4710SRishi Srivatsavai ddi_remove_minor_node(dip, BRIDGE_CTL); 33874eaa4710SRishi Srivatsavai return (DDI_FAILURE); 33884eaa4710SRishi Srivatsavai } 33894eaa4710SRishi Srivatsavai 33904eaa4710SRishi Srivatsavai bridge_dev_info = dip; 33914eaa4710SRishi Srivatsavai bridge_major = ddi_driver_major(dip); 33924eaa4710SRishi Srivatsavai bridge_taskq = ddi_taskq_create(dip, "bridge", 1, TASKQ_DEFAULTPRI, 0); 33934eaa4710SRishi Srivatsavai return (DDI_SUCCESS); 33944eaa4710SRishi Srivatsavai } 33954eaa4710SRishi Srivatsavai 33964eaa4710SRishi Srivatsavai /* 33974eaa4710SRishi Srivatsavai * bridge_detach() 33984eaa4710SRishi Srivatsavai * 33994eaa4710SRishi Srivatsavai * Description: 34004eaa4710SRishi Srivatsavai * Detach an interface to the system. 34014eaa4710SRishi Srivatsavai */ 34024eaa4710SRishi Srivatsavai static int 34034eaa4710SRishi Srivatsavai bridge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 34044eaa4710SRishi Srivatsavai { 34054eaa4710SRishi Srivatsavai if (cmd != DDI_DETACH) 34064eaa4710SRishi Srivatsavai return (DDI_FAILURE); 34074eaa4710SRishi Srivatsavai 34084eaa4710SRishi Srivatsavai ddi_remove_minor_node(dip, NULL); 34094eaa4710SRishi Srivatsavai ddi_taskq_destroy(bridge_taskq); 34104eaa4710SRishi Srivatsavai bridge_dev_info = NULL; 34114eaa4710SRishi Srivatsavai return (DDI_SUCCESS); 34124eaa4710SRishi Srivatsavai } 34134eaa4710SRishi Srivatsavai 34144eaa4710SRishi Srivatsavai /* 34154eaa4710SRishi Srivatsavai * bridge_info() 34164eaa4710SRishi Srivatsavai * 34174eaa4710SRishi Srivatsavai * Description: 34184eaa4710SRishi Srivatsavai * Translate "dev_t" to a pointer to the associated "dev_info_t". 34194eaa4710SRishi Srivatsavai */ 34204eaa4710SRishi Srivatsavai /* ARGSUSED */ 34214eaa4710SRishi Srivatsavai static int 34224eaa4710SRishi Srivatsavai bridge_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 34234eaa4710SRishi Srivatsavai void **result) 34244eaa4710SRishi Srivatsavai { 34254eaa4710SRishi Srivatsavai int rc; 34264eaa4710SRishi Srivatsavai 34274eaa4710SRishi Srivatsavai switch (infocmd) { 34284eaa4710SRishi Srivatsavai case DDI_INFO_DEVT2DEVINFO: 34294eaa4710SRishi Srivatsavai if (bridge_dev_info == NULL) { 34304eaa4710SRishi Srivatsavai rc = DDI_FAILURE; 34314eaa4710SRishi Srivatsavai } else { 34324eaa4710SRishi Srivatsavai *result = (void *)bridge_dev_info; 34334eaa4710SRishi Srivatsavai rc = DDI_SUCCESS; 34344eaa4710SRishi Srivatsavai } 34354eaa4710SRishi Srivatsavai break; 34364eaa4710SRishi Srivatsavai case DDI_INFO_DEVT2INSTANCE: 34374eaa4710SRishi Srivatsavai *result = NULL; 34384eaa4710SRishi Srivatsavai rc = DDI_SUCCESS; 34394eaa4710SRishi Srivatsavai break; 34404eaa4710SRishi Srivatsavai default: 34414eaa4710SRishi Srivatsavai rc = DDI_FAILURE; 34424eaa4710SRishi Srivatsavai break; 34434eaa4710SRishi Srivatsavai } 34444eaa4710SRishi Srivatsavai return (rc); 34454eaa4710SRishi Srivatsavai } 34464eaa4710SRishi Srivatsavai 34474eaa4710SRishi Srivatsavai static struct module_info bridge_modinfo = { 34484eaa4710SRishi Srivatsavai 2105, /* mi_idnum */ 34494eaa4710SRishi Srivatsavai "bridge", /* mi_idname */ 34504eaa4710SRishi Srivatsavai 0, /* mi_minpsz */ 34514eaa4710SRishi Srivatsavai 16384, /* mi_maxpsz */ 34524eaa4710SRishi Srivatsavai 65536, /* mi_hiwat */ 34534eaa4710SRishi Srivatsavai 128 /* mi_lowat */ 34544eaa4710SRishi Srivatsavai }; 34554eaa4710SRishi Srivatsavai 34564eaa4710SRishi Srivatsavai static struct qinit bridge_rinit = { 34574eaa4710SRishi Srivatsavai NULL, /* qi_putp */ 34584eaa4710SRishi Srivatsavai NULL, /* qi_srvp */ 34594eaa4710SRishi Srivatsavai bridge_open, /* qi_qopen */ 34604eaa4710SRishi Srivatsavai bridge_close, /* qi_qclose */ 34614eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */ 34624eaa4710SRishi Srivatsavai &bridge_modinfo, /* qi_minfo */ 34634eaa4710SRishi Srivatsavai NULL /* qi_mstat */ 34644eaa4710SRishi Srivatsavai }; 34654eaa4710SRishi Srivatsavai 34664eaa4710SRishi Srivatsavai static struct qinit bridge_winit = { 34674eaa4710SRishi Srivatsavai (int (*)())bridge_wput, /* qi_putp */ 34684eaa4710SRishi Srivatsavai NULL, /* qi_srvp */ 34694eaa4710SRishi Srivatsavai NULL, /* qi_qopen */ 34704eaa4710SRishi Srivatsavai NULL, /* qi_qclose */ 34714eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */ 34724eaa4710SRishi Srivatsavai &bridge_modinfo, /* qi_minfo */ 34734eaa4710SRishi Srivatsavai NULL /* qi_mstat */ 34744eaa4710SRishi Srivatsavai }; 34754eaa4710SRishi Srivatsavai 34764eaa4710SRishi Srivatsavai static struct streamtab bridge_tab = { 34774eaa4710SRishi Srivatsavai &bridge_rinit, /* st_rdinit */ 34784eaa4710SRishi Srivatsavai &bridge_winit /* st_wrinit */ 34794eaa4710SRishi Srivatsavai }; 34804eaa4710SRishi Srivatsavai 34814eaa4710SRishi Srivatsavai /* No STREAMS perimeters; we do all our own locking */ 34824eaa4710SRishi Srivatsavai DDI_DEFINE_STREAM_OPS(bridge_ops, nulldev, nulldev, bridge_attach, 34834eaa4710SRishi Srivatsavai bridge_detach, nodev, bridge_info, D_NEW | D_MP, &bridge_tab, 34844eaa4710SRishi Srivatsavai ddi_quiesce_not_supported); 34854eaa4710SRishi Srivatsavai 34864eaa4710SRishi Srivatsavai static struct modldrv modldrv = { 34874eaa4710SRishi Srivatsavai &mod_driverops, 34884eaa4710SRishi Srivatsavai "bridging driver", 34894eaa4710SRishi Srivatsavai &bridge_ops 34904eaa4710SRishi Srivatsavai }; 34914eaa4710SRishi Srivatsavai 34924eaa4710SRishi Srivatsavai static struct modlinkage modlinkage = { 34934eaa4710SRishi Srivatsavai MODREV_1, 34944eaa4710SRishi Srivatsavai (void *)&modldrv, 34954eaa4710SRishi Srivatsavai NULL 34964eaa4710SRishi Srivatsavai }; 34974eaa4710SRishi Srivatsavai 34984eaa4710SRishi Srivatsavai int 34994eaa4710SRishi Srivatsavai _init(void) 35004eaa4710SRishi Srivatsavai { 35014eaa4710SRishi Srivatsavai int retv; 35024eaa4710SRishi Srivatsavai 35034eaa4710SRishi Srivatsavai bridge_inst_init(); 35044eaa4710SRishi Srivatsavai if ((retv = mod_install(&modlinkage)) != 0) 35054eaa4710SRishi Srivatsavai bridge_inst_fini(); 35064eaa4710SRishi Srivatsavai return (retv); 35074eaa4710SRishi Srivatsavai } 35084eaa4710SRishi Srivatsavai 35094eaa4710SRishi Srivatsavai int 35104eaa4710SRishi Srivatsavai _fini(void) 35114eaa4710SRishi Srivatsavai { 35124eaa4710SRishi Srivatsavai int retv; 35134eaa4710SRishi Srivatsavai 35144eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_READER); 35154eaa4710SRishi Srivatsavai retv = list_is_empty(&bmac_list) ? 0 : EBUSY; 35164eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock); 35174eaa4710SRishi Srivatsavai if (retv == 0 && 35184eaa4710SRishi Srivatsavai (retv = mod_remove(&modlinkage)) == 0) 35194eaa4710SRishi Srivatsavai bridge_inst_fini(); 35204eaa4710SRishi Srivatsavai return (retv); 35214eaa4710SRishi Srivatsavai } 35224eaa4710SRishi Srivatsavai 35234eaa4710SRishi Srivatsavai int 35244eaa4710SRishi Srivatsavai _info(struct modinfo *modinfop) 35254eaa4710SRishi Srivatsavai { 35264eaa4710SRishi Srivatsavai return (mod_info(&modlinkage, modinfop)); 35274eaa4710SRishi Srivatsavai } 3528