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