dls_link.c revision 0a0e9771ca0211c15f3ac4466b661c145feeb9e4
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 1N/A * Use is subject to license terms. 1N/A * Data-Link Services Module 1N/A * Construct a hash key encompassing both DLSAP value and VLAN idenitifier. 1N/A * Private functions. 1N/A * - Parse the mac header information of the given packet. 1N/A * - Strip the padding and skip over the header. Note that because some 1N/A * DLS consumers only check the db_ref count of the first mblk, we 1N/A * pullup the message into a single mblk. Because the original message 1N/A * is freed as the result of message pulling up, dls_link_header_info() 1N/A * is called again to update the mhi_saddr and mhi_daddr pointers in the 1N/A * mhip. Further, the dls_link_header_info() function ensures that the 1N/A * size of the pulled message is greater than the MAC header size, 1N/A * therefore we can directly advance b_rptr to point at the payload. 1N/A * We choose to use a macro for performance reasons. 1N/A * Truncate the chain starting at mp such that all packets in the chain 1N/A * have identical source and destination addresses, saps, and tag types 1N/A * (see below). It returns a pointer to the mblk following the chain, 1N/A * NULL if there is no further packet following the processed chain. 1N/A * The countp argument is set to the number of valid packets in the chain. 1N/A * Note that the whole MAC header (including the VLAN tag if any) in each 1N/A * packet will be stripped. 1N/A * Compare with subsequent headers until we find one that has 1N/A * differing header information. After checking each packet 1N/A * strip padding and skip over the header. 1N/A * The source, destination, sap, vlan id and the MSGNOLOOP 1N/A * flag must all match in a given subchain. * Note that we don't need to restore the padding. * There are several types of packets. Packets don't match * if they are classified to different type or if they are * VLAN packets but belong to different VLANs: * packet type tagged vid pri * --------------------------------------------------------- * VLAN packets Yes non-zero - * priority tagged Yes zero non-zero * Break the chain at this point and return a pointer to the next * The lock order is mod_hash's internal lock -> dh_lock as in the * call to i_dls_link_rx -> mod_hash_find_cb_rval -> i_dls_head_hold * Try to send mp up to the streams of the given sap and vid. Return B_TRUE * if this message is sent to any streams. * Note that this function will copy the message chain and the original * mp will remain valid after this function * Construct a hash key from the VLAN identifier and the * DLSAP that represents dld_str_t in promiscuous mode. * Search the hash table for dld_str_t eligible to receive * a packet chain for this DLSAP/VLAN combination. The mod hash's * Incrementing the dh_ref (while holding the mod hash lock) ensures * dls_link_remove will wait for the upcall to finish. * Find dld_str_t that will accept the sub-chain. * We have at least one acceptor. * There will normally be at least more dld_str_t * (since we've yet to check for non-promiscuous * dld_str_t) so dup the sub-chain. * Release the hold on the dld_str_t chain now that we have * Wipe the accepted state. * Grab the longest sub-chain we can process as a single * If it is tagged traffic, send it upstream to * all dld_str_t which are attached to the physical * link and bound to SAP 0x8100. * Don't pass the packets up if they are tagged * - their VID and priority are both zero and the * original packet isn't using the PVID (invalid * - their sap is ETHERTYPE_VLAN and their VID is * zero as they have already been sent upstreams. * Construct a hash key from the VLAN identifier and the * Search the has table for dld_str_t eligible to receive * a packet chain for this DLSAP/VLAN combination. * Find the first dld_str_t that will accept the sub-chain. * If we did not find any dld_str_t willing to accept the * sub-chain then throw it away. * We have at least one acceptor. * Find the next dld_str_t that will accept the * If there are no more dld_str_t that are willing * to accept the sub-chain then we don't need to dup * it before handing it to the current one. * Since there are no more dld_str_t, we're * There are more dld_str_t so dup the sub-chain. * Release the hold on the dld_str_t chain now that we have * If there were no acceptors then add the packet count to the * If there is promiscuous handle for vlan, we filter out the untagged * pkts and pkts that are not for the primary unicast address. * In order to filter out sap pkt that no dls channel listens, search * the hash table trying to find a dld_str_t eligible to receive the pkt * Free the structure back to the cache. * Allocate a new dls_link_t structure. * Name the dls_link_t after the MAC interface it represents. * First reference; hold open the MAC interface. /* DLS is the "primary" MAC client */ * Module initialization functions. * Create a kmem_cache of dls_link_t structures. * Create a dls_link_t hash table and associated lock. * Destroy the kmem_cache. * Destroy the hash table and associated lock. * Look up a dls_link_t corresponding to the given macname in the * global hash table. The i_dls_link_hash itself is protected by the * mod_hash package's internal lock which synchronizes * inserts and removes are single threaded on a per mac end point * We didn't find anything so we need to create one. * Bump the reference count and hand back the reference. * The code below assumes that the name constructed above is the * macname. This is not the case for legacy devices. Currently this * is ok because this function is only called in the getinfo(9e) path, * which for a legacy device would directly end up in the driver's * getinfo, rather than here * Check if there are any more references. * Destroy the dls_link_t. * Must fail detach if mac client is busy. * Check whether this dlp is used by its own zone. If yes, we cannot * The link is moving from a non-global zone to the global * zone, so we need to release the reference that was held * when the link was originally assigned to the non-global * We only keep the reference to this link open if the link has * successfully moved from the global zone to a non-global zone. * When a NIC changes zone, that change needs to be communicated to BPF * so that it can correctly enforce access rights on it via BPF. In the * absence of a function from BPF to just change the zoneid, this is * done with a detach followed by an attach. * Generate a hash key based on the sap. * Search the table for a list head with this key. * Add the dld_str_t to the head of the list. List walkers in * i_dls_link_rx_* bump up dh_ref to ensure the list does not change * while they walk the list. The membar below ensures that list walkers * see exactly the old list or the new list. * Save a pointer to the list head. * We set dh_removing here to tell the receive callbacks not to pass * up packets anymore. Then wait till the current callbacks are done. * This happens either in the close path or in processing the * DL_UNBIND_REQ via a taskq thread, and it is ok to cv_wait in either. * The dh_ref ensures there aren't and there won't be any upcalls * walking or using the dh_list. The mod hash internal lock ensures * that the insert/remove of the dls_head_t itself synchronizes with * any i_dls_link_rx trying to locate it. The perimeter ensures that * Walk the list and remove the dld_str_t. * The list is empty so remove the hash table entry. * Packets should always be at least 16 bit aligned. * If this is a VLAN-tagged Ethernet packet, then the SAP in the * mac_header_info_t as returned by mac_header_info() is * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header. * Pullup the message in order to get the MAC header * infomation. Note that this is a read-only function, * we keep the input packet intact. * If this port has a non-zero PVID, then we have to lie to the * caller about the VLAN ID. It's always zero on receive for