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