4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Data-Link Services Module
30 #include <sys/sysmacros.h>
31 #include <sys/strsubr.h>
32 #include <sys/strsun.h>
34 #include <sys/dld_impl.h>
36 #include <sys/atomic.h>
38 static kmem_cache_t
*i_dls_link_cachep
;
39 mod_hash_t
*i_dls_link_hash
;
40 static uint_t i_dls_link_count
;
42 #define LINK_HASHSZ 67 /* prime */
43 #define IMPL_HASHSZ 67 /* prime */
46 * Construct a hash key encompassing both DLSAP value and VLAN idenitifier.
48 #define MAKE_KEY(_sap) \
49 ((mod_hash_key_t)(uintptr_t)((_sap) << VLAN_ID_SIZE))
51 #define DLS_STRIP_PADDING(pktsize, p) { \
53 ssize_t delta = pktsize - msgdsize(p); \
56 (void) adjmsg(p, delta); \
66 i_dls_link_constructor(void *buf
, void *arg
, int kmflag
)
68 dls_link_t
*dlp
= buf
;
69 char name
[MAXNAMELEN
];
71 bzero(buf
, sizeof (dls_link_t
));
73 (void) snprintf(name
, MAXNAMELEN
, "dls_link_t_%p_hash", buf
);
74 dlp
->dl_str_hash
= mod_hash_create_idhash(name
, IMPL_HASHSZ
,
75 mod_hash_null_valdtor
);
82 i_dls_link_destructor(void *buf
, void *arg
)
84 dls_link_t
*dlp
= buf
;
86 ASSERT(dlp
->dl_ref
== 0);
87 ASSERT(dlp
->dl_mh
== NULL
);
88 ASSERT(dlp
->dl_mah
== NULL
);
89 ASSERT(dlp
->dl_unknowns
== 0);
91 mod_hash_destroy_idhash(dlp
->dl_str_hash
);
92 dlp
->dl_str_hash
= NULL
;
97 * - Parse the mac header information of the given packet.
98 * - Strip the padding and skip over the header. Note that because some
99 * DLS consumers only check the db_ref count of the first mblk, we
100 * pullup the message into a single mblk. Because the original message
101 * is freed as the result of message pulling up, mac_vlan_header_info()
102 * is called again to update the mhi_saddr and mhi_daddr pointers in the
103 * mhip. Further, the mac_vlan_header_info() function ensures that the
104 * size of the pulled message is greater than the MAC header size,
105 * therefore we can directly advance b_rptr to point at the payload.
107 * We choose to use a macro for performance reasons.
109 #define DLS_PREPARE_PKT(mh, mp, mhip, err) { \
110 mblk_t *nextp = (mp)->b_next; \
111 if (((err) = mac_vlan_header_info((mh), (mp), (mhip))) == 0) { \
112 DLS_STRIP_PADDING((mhip)->mhi_pktsize, (mp)); \
113 if (MBLKL((mp)) < (mhip)->mhi_hdrsize) { \
115 if ((newmp = msgpullup((mp), -1)) == NULL) { \
118 (mp)->b_next = NULL; \
121 VERIFY(mac_vlan_header_info((mh), \
122 (mp), (mhip)) == 0); \
123 (mp)->b_next = nextp; \
124 (mp)->b_rptr += (mhip)->mhi_hdrsize; \
127 (mp)->b_rptr += (mhip)->mhi_hdrsize; \
133 * Truncate the chain starting at mp such that all packets in the chain
134 * have identical source and destination addresses, saps, and tag types
135 * (see below). It returns a pointer to the mblk following the chain,
136 * NULL if there is no further packet following the processed chain.
137 * The countp argument is set to the number of valid packets in the chain.
138 * Note that the whole MAC header (including the VLAN tag if any) in each
139 * packet will be stripped.
142 i_dls_link_subchain(dls_link_t
*dlp
, mblk_t
*mp
, const mac_header_info_t
*mhip
,
147 size_t addr_size
= dlp
->dl_mip
->mi_addr_length
;
148 uint16_t vid
= VLAN_ID(mhip
->mhi_tci
);
149 uint16_t pri
= VLAN_PRI(mhip
->mhi_tci
);
152 * Compare with subsequent headers until we find one that has
153 * differing header information. After checking each packet
154 * strip padding and skip over the header.
156 for (prevp
= mp
; (mp
= mp
->b_next
) != NULL
; prevp
= mp
) {
157 mac_header_info_t cmhi
;
161 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &cmhi
, err
);
168 * The source, destination, sap, vlan tag must all match in
171 if (mhip
->mhi_saddr
== NULL
|| cmhi
.mhi_saddr
== NULL
||
172 memcmp(mhip
->mhi_daddr
, cmhi
.mhi_daddr
, addr_size
) != 0 ||
173 memcmp(mhip
->mhi_saddr
, cmhi
.mhi_saddr
, addr_size
) != 0 ||
174 mhip
->mhi_bindsap
!= cmhi
.mhi_bindsap
) {
176 * Note that we don't need to restore the padding.
178 mp
->b_rptr
-= cmhi
.mhi_hdrsize
;
182 cvid
= VLAN_ID(cmhi
.mhi_tci
);
183 cpri
= VLAN_PRI(cmhi
.mhi_tci
);
186 * There are several types of packets. Packets don't match
187 * if they are classified to different type or if they are
188 * VLAN packets but belong to different VLANs:
190 * packet type tagged vid pri
191 * ---------------------------------------------------------
192 * untagged No zero zero
193 * VLAN packets Yes non-zero -
194 * priority tagged Yes zero non-zero
195 * 0 tagged Yes zero zero
197 if ((mhip
->mhi_istagged
!= cmhi
.mhi_istagged
) ||
198 (vid
!= cvid
) || ((vid
== VLAN_ID_NONE
) &&
199 (((pri
== 0) && (cpri
!= 0)) ||
200 ((pri
!= 0) && (cpri
== 0))))) {
201 mp
->b_rptr
-= cmhi
.mhi_hdrsize
;
209 * Break the chain at this point and return a pointer to the next
212 prevp
->b_next
= NULL
;
219 i_dls_head_hold(mod_hash_key_t key
, mod_hash_val_t val
)
221 dls_head_t
*dhp
= (dls_head_t
*)val
;
224 * The lock order is mod_hash's internal lock -> dh_lock as in the
225 * call to i_dls_link_rx -> mod_hash_find_cb_rval -> i_dls_head_hold
227 mutex_enter(&dhp
->dh_lock
);
228 if (dhp
->dh_removing
) {
229 mutex_exit(&dhp
->dh_lock
);
233 mutex_exit(&dhp
->dh_lock
);
238 i_dls_head_rele(dls_head_t
*dhp
)
240 mutex_enter(&dhp
->dh_lock
);
242 if (dhp
->dh_ref
== 0 && dhp
->dh_removing
!= 0)
243 cv_broadcast(&dhp
->dh_cv
);
244 mutex_exit(&dhp
->dh_lock
);
248 i_dls_head_alloc(mod_hash_key_t key
)
252 dhp
= kmem_zalloc(sizeof (dls_head_t
), KM_SLEEP
);
258 i_dls_head_free(dls_head_t
*dhp
)
260 ASSERT(dhp
->dh_ref
== 0);
261 kmem_free(dhp
, sizeof (dls_head_t
));
265 * Try to send mp up to the streams of the given sap and vid. Return B_TRUE
266 * if this message is sent to any streams.
267 * Note that this function will copy the message chain and the original
268 * mp will remain valid after this function
271 i_dls_link_rx_func(dls_link_t
*dlp
, mac_resource_handle_t mrh
,
272 mac_header_info_t
*mhip
, mblk_t
*mp
, uint32_t sap
,
273 boolean_t (*acceptfunc
)())
275 mod_hash_t
*hash
= dlp
->dl_str_hash
;
282 uint_t naccepted
= 0;
286 * Construct a hash key from the VLAN identifier and the
287 * DLSAP that represents dld_str_t in promiscuous mode.
292 * Search the hash table for dld_str_t eligible to receive
293 * a packet chain for this DLSAP/VLAN combination. The mod hash's
294 * internal lock serializes find/insert/remove from the mod hash list.
295 * Incrementing the dh_ref (while holding the mod hash lock) ensures
296 * dls_link_remove will wait for the upcall to finish.
298 if (mod_hash_find_cb_rval(hash
, key
, (mod_hash_val_t
*)&dhp
,
299 i_dls_head_hold
, &rval
) != 0 || (rval
!= 0)) {
304 * Find dld_str_t that will accept the sub-chain.
306 for (dsp
= dhp
->dh_list
; dsp
!= NULL
; dsp
= dsp
->ds_next
) {
307 if (!acceptfunc(dsp
, mhip
, &ds_rx
, &ds_rx_arg
))
311 * We have at least one acceptor.
316 * There will normally be at least more dld_str_t
317 * (since we've yet to check for non-promiscuous
318 * dld_str_t) so dup the sub-chain.
320 if ((nmp
= copymsgchain(mp
)) != NULL
)
321 ds_rx(ds_rx_arg
, mrh
, nmp
, mhip
);
325 * Release the hold on the dld_str_t chain now that we have
326 * finished walking it.
328 i_dls_head_rele(dhp
);
334 i_dls_link_rx(void *arg
, mac_resource_handle_t mrh
, mblk_t
*mp
,
337 dls_link_t
*dlp
= arg
;
338 mod_hash_t
*hash
= dlp
->dl_str_hash
;
340 mac_header_info_t mhi
;
348 dls_rx_t ds_rx
, nds_rx
;
349 void *ds_rx_arg
, *nds_rx_arg
;
354 * Walk the packet chain.
356 for (; mp
!= NULL
; mp
= nextp
) {
358 * Wipe the accepted state.
362 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &mhi
, err
);
364 atomic_inc_32(&(dlp
->dl_unknowns
));
372 * Grab the longest sub-chain we can process as a single
375 nextp
= i_dls_link_subchain(dlp
, mp
, &mhi
, &npacket
);
376 ASSERT(npacket
!= 0);
378 vid
= VLAN_ID(mhi
.mhi_tci
);
380 if (mhi
.mhi_istagged
) {
382 * If it is tagged traffic, send it upstream to
383 * all dld_str_t which are attached to the physical
384 * link and bound to SAP 0x8100.
386 if (i_dls_link_rx_func(dlp
, mrh
, &mhi
, mp
,
387 ETHERTYPE_VLAN
, dls_accept
) > 0) {
392 * Don't pass the packets up if they are tagged
394 * - their VID and priority are both zero and the
395 * original packet isn't using the PVID (invalid
397 * - their sap is ETHERTYPE_VLAN and their VID is
398 * zero as they have already been sent upstreams.
400 if ((vid
== VLAN_ID_NONE
&& !mhi
.mhi_ispvid
&&
401 VLAN_PRI(mhi
.mhi_tci
) == 0) ||
402 (mhi
.mhi_bindsap
== ETHERTYPE_VLAN
&&
403 vid
== VLAN_ID_NONE
)) {
410 * Construct a hash key from the VLAN identifier and the
413 key
= MAKE_KEY(mhi
.mhi_bindsap
);
416 * Search the has table for dld_str_t eligible to receive
417 * a packet chain for this DLSAP/VLAN combination.
419 if (mod_hash_find_cb_rval(hash
, key
, (mod_hash_val_t
*)&dhp
,
420 i_dls_head_hold
, &rval
) != 0 || (rval
!= 0)) {
426 * Find the first dld_str_t that will accept the sub-chain.
428 for (dsp
= dhp
->dh_list
; dsp
!= NULL
; dsp
= dsp
->ds_next
)
429 if (dls_accept(dsp
, &mhi
, &ds_rx
, &ds_rx_arg
))
433 * If we did not find any dld_str_t willing to accept the
434 * sub-chain then throw it away.
437 i_dls_head_rele(dhp
);
443 * We have at least one acceptor.
448 * Find the next dld_str_t that will accept the
451 for (ndsp
= dsp
->ds_next
; ndsp
!= NULL
;
452 ndsp
= ndsp
->ds_next
)
453 if (dls_accept(ndsp
, &mhi
, &nds_rx
,
458 * If there are no more dld_str_t that are willing
459 * to accept the sub-chain then we don't need to dup
460 * it before handing it to the current one.
463 ds_rx(ds_rx_arg
, mrh
, mp
, &mhi
);
466 * Since there are no more dld_str_t, we're
473 * There are more dld_str_t so dup the sub-chain.
475 if ((nmp
= copymsgchain(mp
)) != NULL
)
476 ds_rx(ds_rx_arg
, mrh
, nmp
, &mhi
);
480 ds_rx_arg
= nds_rx_arg
;
484 * Release the hold on the dld_str_t chain now that we have
485 * finished walking it.
487 i_dls_head_rele(dhp
);
491 * If there were no acceptors then add the packet count to the
495 atomic_add_32(&(dlp
->dl_unknowns
), npacket
);
501 dls_rx_vlan_promisc(void *arg
, mac_resource_handle_t mrh
, mblk_t
*mp
,
504 dld_str_t
*dsp
= arg
;
505 dls_link_t
*dlp
= dsp
->ds_dlp
;
506 mac_header_info_t mhi
;
511 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &mhi
, err
);
516 * If there is promiscuous handle for vlan, we filter out the untagged
517 * pkts and pkts that are not for the primary unicast address.
519 if (dsp
->ds_vlan_mph
!= NULL
) {
520 uint8_t prim_addr
[MAXMACADDRLEN
];
521 size_t addr_length
= dsp
->ds_mip
->mi_addr_length
;
523 if (!(mhi
.mhi_istagged
))
525 ASSERT(dsp
->ds_mh
!= NULL
);
526 mac_unicast_primary_get(dsp
->ds_mh
, (uint8_t *)prim_addr
);
527 if (memcmp(mhi
.mhi_daddr
, prim_addr
, addr_length
) != 0)
530 if (!dls_accept(dsp
, &mhi
, &ds_rx
, &ds_rx_arg
))
533 ds_rx(ds_rx_arg
, NULL
, mp
, &mhi
);
538 atomic_inc_32(&dlp
->dl_unknowns
);
544 dls_rx_promisc(void *arg
, mac_resource_handle_t mrh
, mblk_t
*mp
,
547 dld_str_t
*dsp
= arg
;
548 dls_link_t
*dlp
= dsp
->ds_dlp
;
549 mac_header_info_t mhi
;
556 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &mhi
, err
);
561 * In order to filter out sap pkt that no dls channel listens, search
562 * the hash table trying to find a dld_str_t eligible to receive the pkt
564 if ((dsp
->ds_promisc
& DLS_PROMISC_SAP
) == 0) {
565 key
= MAKE_KEY(mhi
.mhi_bindsap
);
566 if (mod_hash_find(dsp
->ds_dlp
->dl_str_hash
, key
,
567 (mod_hash_val_t
*)&dhp
) != 0)
571 if (!dls_accept_promisc(dsp
, &mhi
, &ds_rx
, &ds_rx_arg
, loopback
))
574 ds_rx(ds_rx_arg
, NULL
, mp
, &mhi
);
578 atomic_inc_32(&dlp
->dl_unknowns
);
583 i_dls_link_destroy(dls_link_t
*dlp
)
585 ASSERT(dlp
->dl_nactive
== 0);
586 ASSERT(dlp
->dl_impl_count
== 0);
587 ASSERT(dlp
->dl_zone_ref
== 0);
590 * Free the structure back to the cache.
592 if (dlp
->dl_mch
!= NULL
)
593 mac_client_close(dlp
->dl_mch
, 0);
595 if (dlp
->dl_mh
!= NULL
) {
596 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
597 mac_close(dlp
->dl_mh
);
603 dlp
->dl_unknowns
= 0;
604 dlp
->dl_nonip_cnt
= 0;
605 kmem_cache_free(i_dls_link_cachep
, dlp
);
609 i_dls_link_create(const char *name
, dls_link_t
**dlpp
)
615 * Allocate a new dls_link_t structure.
617 dlp
= kmem_cache_alloc(i_dls_link_cachep
, KM_SLEEP
);
620 * Name the dls_link_t after the MAC interface it represents.
622 (void) strlcpy(dlp
->dl_name
, name
, sizeof (dlp
->dl_name
));
625 * First reference; hold open the MAC interface.
627 ASSERT(dlp
->dl_mh
== NULL
);
628 err
= mac_open(dlp
->dl_name
, &dlp
->dl_mh
);
632 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
633 dlp
->dl_mip
= mac_info(dlp
->dl_mh
);
635 /* DLS is the "primary" MAC client */
636 ASSERT(dlp
->dl_mch
== NULL
);
638 err
= mac_client_open(dlp
->dl_mh
, &dlp
->dl_mch
, NULL
,
639 MAC_OPEN_FLAGS_USE_DATALINK_NAME
);
643 DTRACE_PROBE2(dls__primary__client
, char *, dlp
->dl_name
, void *,
650 i_dls_link_destroy(dlp
);
655 * Module initialization functions.
662 * Create a kmem_cache of dls_link_t structures.
664 i_dls_link_cachep
= kmem_cache_create("dls_link_cache",
665 sizeof (dls_link_t
), 0, i_dls_link_constructor
,
666 i_dls_link_destructor
, NULL
, NULL
, NULL
, 0);
667 ASSERT(i_dls_link_cachep
!= NULL
);
670 * Create a dls_link_t hash table and associated lock.
672 i_dls_link_hash
= mod_hash_create_extended("dls_link_hash",
673 IMPL_HASHSZ
, mod_hash_null_keydtor
, mod_hash_null_valdtor
,
674 mod_hash_bystr
, NULL
, mod_hash_strkey_cmp
, KM_SLEEP
);
675 i_dls_link_count
= 0;
681 if (i_dls_link_count
> 0)
685 * Destroy the kmem_cache.
687 kmem_cache_destroy(i_dls_link_cachep
);
690 * Destroy the hash table and associated lock.
692 mod_hash_destroy_hash(i_dls_link_hash
);
697 * Exported functions.
701 dls_link_hold_common(const char *name
, dls_link_t
**dlpp
, boolean_t create
)
707 * Look up a dls_link_t corresponding to the given macname in the
708 * global hash table. The i_dls_link_hash itself is protected by the
709 * mod_hash package's internal lock which synchronizes
710 * find/insert/remove into the global mod_hash list. Assumes that
711 * inserts and removes are single threaded on a per mac end point
712 * by the mac perimeter.
714 if ((err
= mod_hash_find(i_dls_link_hash
, (mod_hash_key_t
)name
,
715 (mod_hash_val_t
*)&dlp
)) == 0)
718 ASSERT(err
== MH_ERR_NOTFOUND
);
723 * We didn't find anything so we need to create one.
725 if ((err
= i_dls_link_create(name
, &dlp
)) != 0)
729 * Insert the dls_link_t.
731 err
= mod_hash_insert(i_dls_link_hash
, (mod_hash_key_t
)dlp
->dl_name
,
732 (mod_hash_val_t
)dlp
);
735 atomic_inc_32(&i_dls_link_count
);
736 ASSERT(i_dls_link_count
!= 0);
739 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
741 * Bump the reference count and hand back the reference.
749 dls_link_hold_create(const char *name
, dls_link_t
**dlpp
)
751 return (dls_link_hold_common(name
, dlpp
, B_TRUE
));
755 dls_link_hold(const char *name
, dls_link_t
**dlpp
)
757 return (dls_link_hold_common(name
, dlpp
, B_FALSE
));
761 dls_link_devinfo(dev_t dev
)
765 char macname
[MAXNAMELEN
];
767 mac_perim_handle_t mph
;
769 if ((drv
= ddi_major_to_name(getmajor(dev
))) == NULL
)
771 (void) snprintf(macname
, MAXNAMELEN
, "%s%d", drv
,
772 DLS_MINOR2INST(getminor(dev
)));
775 * The code below assumes that the name constructed above is the
776 * macname. This is not the case for legacy devices. Currently this
777 * is ok because this function is only called in the getinfo(9e) path,
778 * which for a legacy device would directly end up in the driver's
779 * getinfo, rather than here
781 if (mac_perim_enter_by_macname(macname
, &mph
) != 0)
784 if (dls_link_hold(macname
, &dlp
) != 0) {
789 dip
= mac_devinfo_get(dlp
->dl_mh
);
797 dls_link_dev(dls_link_t
*dlp
)
799 return (makedevice(ddi_driver_major(mac_devinfo_get(dlp
->dl_mh
)),
800 mac_minor(dlp
->dl_mh
)));
804 dls_link_rele(dls_link_t
*dlp
)
808 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
810 * Check if there are any more references.
812 if (--dlp
->dl_ref
== 0) {
813 (void) mod_hash_remove(i_dls_link_hash
,
814 (mod_hash_key_t
)dlp
->dl_name
, &val
);
815 ASSERT(dlp
== (dls_link_t
*)val
);
818 * Destroy the dls_link_t.
820 i_dls_link_destroy(dlp
);
821 ASSERT(i_dls_link_count
> 0);
822 atomic_dec_32(&i_dls_link_count
);
827 dls_link_rele_by_name(const char *name
)
831 if (mod_hash_find(i_dls_link_hash
, (mod_hash_key_t
)name
,
832 (mod_hash_val_t
*)&dlp
) != 0)
835 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
838 * Must fail detach if mac client is busy.
840 ASSERT(dlp
->dl_ref
> 0 && dlp
->dl_mch
!= NULL
);
841 if (mac_link_has_flows(dlp
->dl_mch
))
849 dls_link_setzid(const char *name
, zoneid_t zid
)
855 if ((err
= dls_link_hold_create(name
, &dlp
)) != 0)
858 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
860 if ((old_zid
= dlp
->dl_zid
) == zid
)
864 * Check whether this dlp is used by its own zone. If yes, we cannot
867 if (dlp
->dl_zone_ref
!= 0) {
874 if (zid
== GLOBAL_ZONEID
) {
876 * The link is moving from a non-global zone to the global
877 * zone, so we need to release the reference that was held
878 * when the link was originally assigned to the non-global
886 * We only keep the reference to this link open if the link has
887 * successfully moved from the global zone to a non-global zone.
889 if (err
!= 0 || old_zid
!= GLOBAL_ZONEID
)
895 dls_link_getzid(const char *name
, zoneid_t
*zidp
)
900 if ((err
= dls_link_hold(name
, &dlp
)) != 0)
903 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
912 dls_link_add(dls_link_t
*dlp
, uint32_t sap
, dld_str_t
*dsp
)
914 mod_hash_t
*hash
= dlp
->dl_str_hash
;
920 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
923 * Generate a hash key based on the sap.
928 * Search the table for a list head with this key.
930 if ((err
= mod_hash_find(hash
, key
, (mod_hash_val_t
*)&dhp
)) != 0) {
931 ASSERT(err
== MH_ERR_NOTFOUND
);
933 dhp
= i_dls_head_alloc(key
);
934 err
= mod_hash_insert(hash
, key
, (mod_hash_val_t
)dhp
);
939 * Add the dld_str_t to the head of the list. List walkers in
940 * i_dls_link_rx_* bump up dh_ref to ensure the list does not change
941 * while they walk the list. The membar below ensures that list walkers
942 * see exactly the old list or the new list.
944 ASSERT(dsp
->ds_next
== NULL
);
953 * Save a pointer to the list head.
956 dlp
->dl_impl_count
++;
960 dls_link_remove(dls_link_t
*dlp
, dld_str_t
*dsp
)
962 mod_hash_t
*hash
= dlp
->dl_str_hash
;
967 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
970 * We set dh_removing here to tell the receive callbacks not to pass
971 * up packets anymore. Then wait till the current callbacks are done.
972 * This happens either in the close path or in processing the
973 * DL_UNBIND_REQ via a taskq thread, and it is ok to cv_wait in either.
974 * The dh_ref ensures there aren't and there won't be any upcalls
975 * walking or using the dh_list. The mod hash internal lock ensures
976 * that the insert/remove of the dls_head_t itself synchronizes with
977 * any i_dls_link_rx trying to locate it. The perimeter ensures that
978 * there isn't another simultaneous dls_link_add/remove.
982 mutex_enter(&dhp
->dh_lock
);
983 dhp
->dh_removing
= B_TRUE
;
984 while (dhp
->dh_ref
!= 0)
985 cv_wait(&dhp
->dh_cv
, &dhp
->dh_lock
);
986 mutex_exit(&dhp
->dh_lock
);
989 * Walk the list and remove the dld_str_t.
991 for (pp
= &dhp
->dh_list
; (p
= *pp
) != NULL
; pp
= &(p
->ds_next
)) {
1000 ASSERT(dlp
->dl_impl_count
!= 0);
1001 dlp
->dl_impl_count
--;
1003 if (dhp
->dh_list
== NULL
) {
1004 mod_hash_val_t val
= NULL
;
1007 * The list is empty so remove the hash table entry.
1009 (void) mod_hash_remove(hash
, dhp
->dh_key
, &val
);
1010 ASSERT(dhp
== (dls_head_t
*)val
);
1011 i_dls_head_free(dhp
);
1013 mutex_enter(&dhp
->dh_lock
);
1014 dhp
->dh_removing
= B_FALSE
;
1015 mutex_exit(&dhp
->dh_lock
);