1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2018 Joyent, Inc.
25 */
26
27 #include <sys/types.h>
28 #include <sys/sysmacros.h>
29 #include <sys/conf.h>
30 #include <sys/cmn_err.h>
31 #include <sys/list.h>
32 #include <sys/kmem.h>
33 #include <sys/stream.h>
34 #include <sys/modctl.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/atomic.h>
38 #include <sys/stat.h>
39 #include <sys/modhash.h>
40 #include <sys/strsubr.h>
41 #include <sys/strsun.h>
42 #include <sys/sdt.h>
43 #include <sys/mac.h>
44 #include <sys/mac_impl.h>
45 #include <sys/mac_client_impl.h>
46 #include <sys/mac_client_priv.h>
47 #include <sys/mac_flow_impl.h>
48
49 /*
50 * Broadcast and multicast traffic must be distributed to the MAC clients
51 * that are defined on top of the same MAC. The set of
52 * destinations to which a multicast packet must be sent is a subset
53 * of all MAC clients defined on top of the MAC. A MAC client can be member
54 * of more than one such subset.
55 *
56 * To accomodate these requirements, we introduce broadcast groups.
57 * A broadcast group is associated with a broadcast or multicast
58 * address. The members of a broadcast group consist of the MAC clients
59 * that should received copies of packets sent to the address
60 * associated with the group, and are defined on top of the
61 * same MAC.
62 *
63 * The broadcast groups defined on top of a MAC are chained,
64 * hanging off the mac_impl_t. The broadcast group id's are
65 * unique globally (tracked by mac_bcast_id).
66 */
67
68 /*
69 * The same MAC client may be added for different <addr,vid> tuple,
70 * we maintain a ref count for the number of times it has been added
71 * to account for deleting the MAC client from the group.
72 */
73 typedef struct mac_bcast_grp_mcip_s {
74 mac_client_impl_t *mgb_client;
75 int mgb_client_ref;
76 } mac_bcast_grp_mcip_t;
77
78 typedef struct mac_bcast_grp_s { /* Protected by */
79 struct mac_bcast_grp_s *mbg_next; /* SL */
80 void *mbg_addr; /* SL */
81 uint16_t mbg_vid; /* SL */
82 mac_impl_t *mbg_mac_impl; /* WO */
83 mac_addrtype_t mbg_addrtype; /* WO */
84 flow_entry_t *mbg_flow_ent; /* WO */
85 mac_bcast_grp_mcip_t *mbg_clients; /* mi_rw_lock */
86 uint_t mbg_nclients; /* mi_rw_lock */
87 uint_t mbg_nclients_alloc; /* SL */
88 uint64_t mbg_clients_gen; /* mi_rw_lock */
89 uint32_t mbg_id; /* atomic */
90 } mac_bcast_grp_t;
91
92 static kmem_cache_t *mac_bcast_grp_cache;
93 static uint32_t mac_bcast_id = 0;
94
95 void
mac_bcast_init(void)96 mac_bcast_init(void)
97 {
98 mac_bcast_grp_cache = kmem_cache_create("mac_bcast_grp_cache",
99 sizeof (mac_bcast_grp_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
100 }
101
102 void
mac_bcast_fini(void)103 mac_bcast_fini(void)
104 {
105 kmem_cache_destroy(mac_bcast_grp_cache);
106 }
107
108 mac_impl_t *
mac_bcast_grp_mip(void * grp)109 mac_bcast_grp_mip(void *grp)
110 {
111 mac_bcast_grp_t *bcast_grp = grp;
112
113 return (bcast_grp->mbg_mac_impl);
114 }
115
116 /*
117 * Free the specific broadcast group. Invoked when the last reference
118 * to the group is released.
119 */
120 void
mac_bcast_grp_free(void * bcast_grp)121 mac_bcast_grp_free(void *bcast_grp)
122 {
123 mac_bcast_grp_t *grp = bcast_grp;
124 mac_impl_t *mip = grp->mbg_mac_impl;
125
126 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
127
128 ASSERT(grp->mbg_addr != NULL);
129 kmem_free(grp->mbg_addr, mip->mi_type->mt_addr_length);
130 kmem_free(grp->mbg_clients,
131 grp->mbg_nclients_alloc * sizeof (mac_bcast_grp_mcip_t));
132 mip->mi_bcast_ngrps--;
133 kmem_cache_free(mac_bcast_grp_cache, grp);
134 }
135
136 /*
137 * arg1: broadcast group
138 * arg2: sender MAC client if it is being sent by a MAC client,
139 * NULL if it was received from the wire.
140 */
141 void
mac_bcast_send(void * arg1,void * arg2,mblk_t * mp_chain,boolean_t is_loopback)142 mac_bcast_send(void *arg1, void *arg2, mblk_t *mp_chain, boolean_t is_loopback)
143 {
144 mac_bcast_grp_t *grp = arg1;
145 mac_client_impl_t *src_mcip = arg2, *dst_mcip;
146 mac_impl_t *mip = grp->mbg_mac_impl;
147 uint64_t gen;
148 uint_t i;
149 mblk_t *mp_chain1;
150 flow_entry_t *flent;
151 int err;
152
153 rw_enter(&mip->mi_rw_lock, RW_READER);
154
155 /*
156 * Pass a copy of the mp chain to every MAC client except the sender
157 * MAC client, if the packet was not received from the underlying NIC.
158 *
159 * The broadcast group lock should not be held across calls to
160 * the flow's callback function, since the same group could
161 * potentially be accessed from the same context. When the lock
162 * is reacquired, changes to the broadcast group while the lock
163 * was released are caught using a generation counter incremented
164 * each time the list of MAC clients associated with the broadcast
165 * group is changed.
166 */
167 for (i = 0; i < grp->mbg_nclients_alloc; i++) {
168 dst_mcip = grp->mbg_clients[i].mgb_client;
169 if (dst_mcip == NULL)
170 continue;
171 flent = dst_mcip->mci_flent;
172 if (flent == NULL || dst_mcip == src_mcip) {
173 /*
174 * Don't send a copy of the packet back to
175 * its sender.
176 */
177 continue;
178 }
179
180 /*
181 * It is important to hold a reference on the
182 * flow_ent here.
183 */
184 if ((mp_chain1 = mac_copymsgchain_cksum(mp_chain)) == NULL)
185 break;
186
187 FLOW_TRY_REFHOLD(flent, err);
188 if (err != 0) {
189 freemsgchain(mp_chain1);
190 continue;
191 }
192
193 gen = grp->mbg_clients_gen;
194
195 rw_exit(&mip->mi_rw_lock);
196
197 DTRACE_PROBE4(mac__bcast__send__to, mac_client_impl_t *,
198 src_mcip, flow_fn_t, dst_mcip->mci_flent->fe_cb_fn,
199 void *, dst_mcip->mci_flent->fe_cb_arg1,
200 void *, dst_mcip->mci_flent->fe_cb_arg2);
201
202 (dst_mcip->mci_flent->fe_cb_fn)(dst_mcip->mci_flent->fe_cb_arg1,
203 dst_mcip->mci_flent->fe_cb_arg2, mp_chain1, is_loopback);
204 FLOW_REFRELE(flent);
205
206 rw_enter(&mip->mi_rw_lock, RW_READER);
207
208 /* update stats */
209 if (grp->mbg_addrtype == MAC_ADDRTYPE_MULTICAST) {
210 MCIP_STAT_UPDATE(dst_mcip, multircv, 1);
211 MCIP_STAT_UPDATE(dst_mcip, multircvbytes,
212 msgdsize(mp_chain));
213 } else {
214 MCIP_STAT_UPDATE(dst_mcip, brdcstrcv, 1);
215 MCIP_STAT_UPDATE(dst_mcip, brdcstrcvbytes,
216 msgdsize(mp_chain));
217 }
218
219 if (grp->mbg_clients_gen != gen) {
220 /*
221 * The list of MAC clients associated with the group
222 * was changed while the lock was released.
223 * Give up on the current packet.
224 */
225 rw_exit(&mip->mi_rw_lock);
226 freemsgchain(mp_chain);
227 return;
228 }
229 }
230 rw_exit(&mip->mi_rw_lock);
231
232 if (src_mcip != NULL) {
233 /*
234 * The packet was sent from one of the MAC clients,
235 * so we need to send a copy of the packet to the
236 * underlying NIC so that it can be sent on the wire.
237 */
238 MCIP_STAT_UPDATE(src_mcip, multixmt, 1);
239 MCIP_STAT_UPDATE(src_mcip, multixmtbytes, msgdsize(mp_chain));
240 MCIP_STAT_UPDATE(src_mcip, brdcstxmt, 1);
241 MCIP_STAT_UPDATE(src_mcip, brdcstxmtbytes, msgdsize(mp_chain));
242
243 mp_chain = mac_provider_tx(mip, mip->mi_default_tx_ring,
244 mp_chain, src_mcip);
245 if (mp_chain != NULL)
246 freemsgchain(mp_chain);
247 } else {
248 freemsgchain(mp_chain);
249 }
250 }
251
252 /*
253 * Add the specified MAC client to the group corresponding to the specified
254 * broadcast or multicast address.
255 * Return 0 on success, or an errno value on failure.
256 */
257 int
mac_bcast_add(mac_client_impl_t * mcip,const uint8_t * addr,uint16_t vid,mac_addrtype_t addrtype)258 mac_bcast_add(mac_client_impl_t *mcip, const uint8_t *addr, uint16_t vid,
259 mac_addrtype_t addrtype)
260 {
261 mac_impl_t *mip = mcip->mci_mip;
262 mac_bcast_grp_t *grp = NULL, **last_grp;
263 size_t addr_len = mip->mi_type->mt_addr_length;
264 int rc = 0;
265 int i, index = -1;
266 mac_mcast_addrs_t **prev_mi_addr = NULL;
267 mac_mcast_addrs_t **prev_mci_addr = NULL;
268
269 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
270
271 ASSERT(addrtype == MAC_ADDRTYPE_MULTICAST ||
272 addrtype == MAC_ADDRTYPE_BROADCAST);
273
274 /*
275 * Add the MAC client to the list of MAC clients associated
276 * with the group.
277 */
278 if (addrtype == MAC_ADDRTYPE_MULTICAST) {
279 mac_mcast_addrs_t *maddr;
280
281 /*
282 * In case of a driver (say aggr), we need this information
283 * on a per MAC instance basis.
284 */
285 prev_mi_addr = &mip->mi_mcast_addrs;
286 for (maddr = *prev_mi_addr; maddr != NULL;
287 prev_mi_addr = &maddr->mma_next, maddr = maddr->mma_next) {
288 if (bcmp(maddr->mma_addr, addr, addr_len) == 0)
289 break;
290 }
291 if (maddr == NULL) {
292 /*
293 * For multicast addresses, have the underlying MAC
294 * join the corresponding multicast group.
295 */
296 rc = mip->mi_multicst(mip->mi_driver, B_TRUE, addr);
297 if (rc != 0)
298 return (rc);
299 maddr = kmem_zalloc(sizeof (mac_mcast_addrs_t),
300 KM_SLEEP);
301 bcopy(addr, maddr->mma_addr, addr_len);
302 *prev_mi_addr = maddr;
303 } else {
304 prev_mi_addr = NULL;
305 }
306 maddr->mma_ref++;
307
308 /*
309 * We maintain a separate list for each MAC client. Get
310 * the entry or add, if it is not present.
311 */
312 prev_mci_addr = &mcip->mci_mcast_addrs;
313 for (maddr = *prev_mci_addr; maddr != NULL;
314 prev_mci_addr = &maddr->mma_next, maddr = maddr->mma_next) {
315 if (bcmp(maddr->mma_addr, addr, addr_len) == 0)
316 break;
317 }
318 if (maddr == NULL) {
319 maddr = kmem_zalloc(sizeof (mac_mcast_addrs_t),
320 KM_SLEEP);
321 bcopy(addr, maddr->mma_addr, addr_len);
322 *prev_mci_addr = maddr;
323 } else {
324 prev_mci_addr = NULL;
325 }
326 maddr->mma_ref++;
327 }
328
329 /* The list is protected by the perimeter */
330 last_grp = &mip->mi_bcast_grp;
331 for (grp = *last_grp; grp != NULL;
332 last_grp = &grp->mbg_next, grp = grp->mbg_next) {
333 if (bcmp(grp->mbg_addr, addr, addr_len) == 0 &&
334 grp->mbg_vid == vid)
335 break;
336 }
337
338 if (grp == NULL) {
339 /*
340 * The group does not yet exist, create it.
341 */
342 flow_desc_t flow_desc;
343 char flow_name[MAXFLOWNAMELEN];
344
345 grp = kmem_cache_alloc(mac_bcast_grp_cache, KM_SLEEP);
346 bzero(grp, sizeof (mac_bcast_grp_t));
347 grp->mbg_next = NULL;
348 grp->mbg_mac_impl = mip;
349
350 DTRACE_PROBE1(mac__bcast__add__new__group, mac_bcast_grp_t *,
351 grp);
352
353 grp->mbg_addr = kmem_zalloc(addr_len, KM_SLEEP);
354 bcopy(addr, grp->mbg_addr, addr_len);
355 grp->mbg_addrtype = addrtype;
356 grp->mbg_vid = vid;
357
358 /*
359 * Add a new flow to the underlying MAC.
360 */
361 bzero(&flow_desc, sizeof (flow_desc));
362 bcopy(addr, &flow_desc.fd_dst_mac, addr_len);
363 flow_desc.fd_mac_len = (uint32_t)addr_len;
364
365 flow_desc.fd_mask = FLOW_LINK_DST;
366 if (vid != 0) {
367 flow_desc.fd_vid = vid;
368 flow_desc.fd_mask |= FLOW_LINK_VID;
369 }
370
371 grp->mbg_id = atomic_inc_32_nv(&mac_bcast_id);
372 (void) sprintf(flow_name,
373 "mac/%s/mcast%d", mip->mi_name, grp->mbg_id);
374
375 rc = mac_flow_create(&flow_desc, NULL, flow_name,
376 grp, FLOW_MCAST, &grp->mbg_flow_ent);
377 if (rc != 0) {
378 kmem_free(grp->mbg_addr, addr_len);
379 kmem_cache_free(mac_bcast_grp_cache, grp);
380 goto fail;
381 }
382 grp->mbg_flow_ent->fe_mbg = grp;
383 mip->mi_bcast_ngrps++;
384
385 /*
386 * Initial creation reference on the flow. This is released
387 * in the corresponding delete action i_mac_bcast_delete()
388 */
389 FLOW_REFHOLD(grp->mbg_flow_ent);
390
391 /*
392 * When the multicast and broadcast packet is received
393 * by the underlying NIC, mac_rx_classify() will invoke
394 * mac_bcast_send() with arg2=NULL, which will cause
395 * mac_bcast_send() to send a copy of the packet(s)
396 * to every MAC client opened on top of the underlying MAC.
397 *
398 * When the mac_bcast_send() function is invoked from
399 * the transmit path of a MAC client, it will specify the
400 * transmitting MAC client as the arg2 value, which will
401 * allow mac_bcast_send() to skip that MAC client and not
402 * send it a copy of the packet.
403 *
404 * We program the classifier to dispatch matching broadcast
405 * packets to mac_bcast_send().
406 */
407
408 grp->mbg_flow_ent->fe_cb_fn = mac_bcast_send;
409 grp->mbg_flow_ent->fe_cb_arg1 = grp;
410 grp->mbg_flow_ent->fe_cb_arg2 = NULL;
411
412 rc = mac_flow_add(mip->mi_flow_tab, grp->mbg_flow_ent);
413 if (rc != 0) {
414 FLOW_FINAL_REFRELE(grp->mbg_flow_ent);
415 goto fail;
416 }
417
418 *last_grp = grp;
419 }
420
421 ASSERT(grp->mbg_addrtype == addrtype);
422
423 /*
424 * Add the MAC client to the list of MAC clients associated
425 * with the group.
426 */
427 rw_enter(&mip->mi_rw_lock, RW_WRITER);
428 for (i = 0; i < grp->mbg_nclients_alloc; i++) {
429 /*
430 * The MAC client was already added, say when we have
431 * different unicast addresses with the same vid.
432 * Just increment the ref and we are done.
433 */
434 if (grp->mbg_clients[i].mgb_client == mcip) {
435 grp->mbg_clients[i].mgb_client_ref++;
436 rw_exit(&mip->mi_rw_lock);
437 return (0);
438 } else if (grp->mbg_clients[i].mgb_client == NULL &&
439 index == -1) {
440 index = i;
441 }
442 }
443 if (grp->mbg_nclients_alloc == grp->mbg_nclients) {
444 mac_bcast_grp_mcip_t *new_clients;
445 uint_t new_size = grp->mbg_nclients+1;
446
447 new_clients = kmem_zalloc(new_size *
448 sizeof (mac_bcast_grp_mcip_t), KM_SLEEP);
449
450 if (grp->mbg_nclients > 0) {
451 ASSERT(grp->mbg_clients != NULL);
452 bcopy(grp->mbg_clients, new_clients, grp->mbg_nclients *
453 sizeof (mac_bcast_grp_mcip_t));
454 kmem_free(grp->mbg_clients, grp->mbg_nclients *
455 sizeof (mac_bcast_grp_mcip_t));
456 }
457
458 grp->mbg_clients = new_clients;
459 grp->mbg_nclients_alloc = new_size;
460 index = new_size - 1;
461 }
462
463 ASSERT(index != -1);
464 grp->mbg_clients[index].mgb_client = mcip;
465 grp->mbg_clients[index].mgb_client_ref = 1;
466 grp->mbg_nclients++;
467 /*
468 * Since we're adding to the list of MAC clients using that group,
469 * kick the generation count, which will allow mac_bcast_send()
470 * to detect that condition after re-acquiring the lock.
471 */
472 grp->mbg_clients_gen++;
473 rw_exit(&mip->mi_rw_lock);
474 return (0);
475
476 fail:
477 if (prev_mi_addr != NULL) {
478 kmem_free(*prev_mi_addr, sizeof (mac_mcast_addrs_t));
479 *prev_mi_addr = NULL;
480 (void) mip->mi_multicst(mip->mi_driver, B_FALSE, addr);
481 }
482 if (prev_mci_addr != NULL) {
483 kmem_free(*prev_mci_addr, sizeof (mac_mcast_addrs_t));
484 *prev_mci_addr = NULL;
485 }
486 return (rc);
487 }
488
489 /*
490 * Remove the specified MAC client from the group corresponding to
491 * the specific broadcast or multicast address.
492 *
493 * Note: mac_bcast_delete() calls mac_remove_flow() which
494 * will call cv_wait for fe_refcnt to drop to 0. So this function
495 * should not be called from interrupt or STREAMS context.
496 */
497 void
mac_bcast_delete(mac_client_impl_t * mcip,const uint8_t * addr,uint16_t vid)498 mac_bcast_delete(mac_client_impl_t *mcip, const uint8_t *addr, uint16_t vid)
499 {
500 mac_impl_t *mip = mcip->mci_mip;
501 mac_bcast_grp_t *grp = NULL, **prev;
502 size_t addr_len = mip->mi_type->mt_addr_length;
503 flow_entry_t *flent;
504 uint_t i;
505 mac_mcast_addrs_t *maddr = NULL;
506 mac_mcast_addrs_t **mprev;
507
508 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
509
510 /* find the broadcast group. The list is protected by the perimeter */
511 prev = &mip->mi_bcast_grp;
512 for (grp = mip->mi_bcast_grp; grp != NULL; prev = &grp->mbg_next,
513 grp = grp->mbg_next) {
514 if (bcmp(grp->mbg_addr, addr, addr_len) == 0 &&
515 grp->mbg_vid == vid)
516 break;
517 }
518 ASSERT(grp != NULL);
519
520 /*
521 * Remove the MAC client from the list of MAC clients associated
522 * with that broadcast group.
523 *
524 * We mark the mbg_clients[] location corresponding to the removed MAC
525 * client NULL and reuse that location when we add a new MAC client.
526 */
527
528 rw_enter(&mip->mi_rw_lock, RW_WRITER);
529
530 for (i = 0; i < grp->mbg_nclients_alloc; i++) {
531 if (grp->mbg_clients[i].mgb_client == mcip)
532 break;
533 }
534
535 ASSERT(i < grp->mbg_nclients_alloc);
536 /*
537 * If there are more references to this MAC client, then we let
538 * it remain till it goes to 0.
539 */
540 if (--grp->mbg_clients[i].mgb_client_ref > 0)
541 goto update_maddr;
542
543 grp->mbg_clients[i].mgb_client = NULL;
544 grp->mbg_clients[i].mgb_client_ref = 0;
545
546 /*
547 * Since we're removing from the list of MAC clients using that group,
548 * kick the generation count, which will allow mac_bcast_send()
549 * to detect that condition.
550 */
551 grp->mbg_clients_gen++;
552
553 if (--grp->mbg_nclients == 0) {
554 /*
555 * The last MAC client of the group was just removed.
556 * Unlink the current group from the list of groups
557 * defined on top of the underlying NIC. The group
558 * structure will stay around until the last reference
559 * is dropped.
560 */
561 *prev = grp->mbg_next;
562 }
563 update_maddr:
564 rw_exit(&mip->mi_rw_lock);
565
566 if (grp->mbg_addrtype == MAC_ADDRTYPE_MULTICAST) {
567 mprev = &mcip->mci_mcast_addrs;
568 for (maddr = mcip->mci_mcast_addrs; maddr != NULL;
569 mprev = &maddr->mma_next, maddr = maddr->mma_next) {
570 if (bcmp(grp->mbg_addr, maddr->mma_addr,
571 mip->mi_type->mt_addr_length) == 0)
572 break;
573 }
574 ASSERT(maddr != NULL);
575 if (--maddr->mma_ref == 0) {
576 *mprev = maddr->mma_next;
577 maddr->mma_next = NULL;
578 kmem_free(maddr, sizeof (mac_mcast_addrs_t));
579 }
580
581 mprev = &mip->mi_mcast_addrs;
582 for (maddr = mip->mi_mcast_addrs; maddr != NULL;
583 mprev = &maddr->mma_next, maddr = maddr->mma_next) {
584 if (bcmp(grp->mbg_addr, maddr->mma_addr,
585 mip->mi_type->mt_addr_length) == 0)
586 break;
587 }
588 ASSERT(maddr != NULL);
589 if (--maddr->mma_ref == 0) {
590 (void) mip->mi_multicst(mip->mi_driver, B_FALSE, addr);
591 *mprev = maddr->mma_next;
592 maddr->mma_next = NULL;
593 kmem_free(maddr, sizeof (mac_mcast_addrs_t));
594 }
595 }
596
597 /*
598 * If the group itself is being removed, remove the
599 * corresponding flow from the underlying NIC.
600 */
601 flent = grp->mbg_flow_ent;
602 if (grp->mbg_nclients == 0) {
603 mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE);
604 mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
605 FLOW_FINAL_REFRELE(flent);
606 }
607 }
608
609 /*
610 * This will be called by a driver, such as aggr, when a port is added/removed
611 * to add/remove the port to/from all the multcast addresses for that aggr.
612 */
613 void
mac_bcast_refresh(mac_impl_t * mip,mac_multicst_t refresh_fn,void * arg,boolean_t add)614 mac_bcast_refresh(mac_impl_t *mip, mac_multicst_t refresh_fn, void *arg,
615 boolean_t add)
616 {
617 mac_mcast_addrs_t *grp, *next;
618
619 ASSERT(refresh_fn != NULL);
620
621 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
622
623 /*
624 * Walk the multicast address list and call the refresh function for
625 * each address.
626 */
627
628 for (grp = mip->mi_mcast_addrs; grp != NULL; grp = next) {
629 /*
630 * Save the next pointer just in case the refresh
631 * function's action causes the group entry to be
632 * freed.
633 * We won't be adding to this list as part of the
634 * refresh.
635 */
636 next = grp->mma_next;
637 refresh_fn(arg, add, grp->mma_addr);
638 }
639 }
640
641 /*
642 * Walk the MAC client's multicast address list and add/remove the addr/vid
643 * ('arg' is 'flent') to all the addresses.
644 */
645 void
mac_client_bcast_refresh(mac_client_impl_t * mcip,mac_multicst_t refresh_fn,void * arg,boolean_t add)646 mac_client_bcast_refresh(mac_client_impl_t *mcip, mac_multicst_t refresh_fn,
647 void *arg, boolean_t add)
648 {
649 mac_mcast_addrs_t *grp, *next;
650 mac_impl_t *mip = mcip->mci_mip;
651
652 ASSERT(refresh_fn != NULL);
653
654 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
655 /*
656 * Walk the multicast address list and call the refresh function for
657 * each address.
658 * Broadcast addresses are not added or removed through the multicast
659 * entry points, so don't include them as part of the refresh.
660 */
661 for (grp = mcip->mci_mcast_addrs; grp != NULL; grp = next) {
662 /*
663 * Save the next pointer just in case the refresh
664 * function's action causes the group entry to be
665 * freed.
666 * We won't be adding to this list as part of the
667 * refresh.
668 */
669 next = grp->mma_next;
670 refresh_fn(arg, add, grp->mma_addr);
671 }
672 }
673