Print this page
11490 SRS ring polling disabled for VLANs
11491 Want DLS bypass for VLAN traffic
11492 add VLVF bypass to ixgbe core
2869 duplicate packets with vnics over aggrs
11489 DLS stat delete and aggr kstat can deadlock
Portions contributed by: Theo Schlossnagle <jesus@omniti.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/aggr/aggr_port.c
+++ new/usr/src/uts/common/io/aggr/aggr_port.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
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 + * Copyright 2012 OmniTI Computer Consulting, Inc All rights reserved.
25 + * Copyright 2018 Joyent, Inc.
24 26 */
25 27
26 28 /*
27 29 * IEEE 802.3ad Link Aggregation - Link Aggregation MAC ports.
28 30 *
29 31 * Implements the functions needed to manage the MAC ports that are
30 32 * part of Link Aggregation groups.
31 33 */
32 34
33 35 #include <sys/types.h>
34 36 #include <sys/sysmacros.h>
35 37 #include <sys/conf.h>
36 38 #include <sys/cmn_err.h>
37 39 #include <sys/id_space.h>
38 40 #include <sys/list.h>
39 41 #include <sys/ksynch.h>
40 42 #include <sys/kmem.h>
41 43 #include <sys/stream.h>
42 44 #include <sys/modctl.h>
43 45 #include <sys/ddi.h>
44 46 #include <sys/sunddi.h>
45 47 #include <sys/atomic.h>
46 48 #include <sys/stat.h>
47 49 #include <sys/sdt.h>
48 50 #include <sys/dlpi.h>
49 51 #include <sys/dls.h>
50 52 #include <sys/aggr.h>
51 53 #include <sys/aggr_impl.h>
52 54
53 55 static kmem_cache_t *aggr_port_cache;
54 56 static id_space_t *aggr_portids;
55 57
56 58 static void aggr_port_notify_cb(void *, mac_notify_type_t);
57 59
58 60 /*ARGSUSED*/
59 61 static int
60 62 aggr_port_constructor(void *buf, void *arg, int kmflag)
61 63 {
62 64 bzero(buf, sizeof (aggr_port_t));
63 65 return (0);
64 66 }
65 67
66 68 /*ARGSUSED*/
67 69 static void
68 70 aggr_port_destructor(void *buf, void *arg)
69 71 {
70 72 aggr_port_t *port = buf;
71 73
72 74 ASSERT(port->lp_mnh == NULL);
73 75 ASSERT(port->lp_mphp == NULL);
74 76 ASSERT(!port->lp_rx_grp_added && !port->lp_tx_grp_added);
75 77 ASSERT(port->lp_hwgh == NULL);
76 78 }
77 79
78 80 void
79 81 aggr_port_init(void)
80 82 {
81 83 aggr_port_cache = kmem_cache_create("aggr_port_cache",
82 84 sizeof (aggr_port_t), 0, aggr_port_constructor,
83 85 aggr_port_destructor, NULL, NULL, NULL, 0);
84 86
85 87 /*
86 88 * Allocate a id space to manage port identification. The range of
87 89 * the arena will be from 1 to UINT16_MAX, because the LACP protocol
88 90 * specifies 16-bit unique identification.
89 91 */
90 92 aggr_portids = id_space_create("aggr_portids", 1, UINT16_MAX);
91 93 ASSERT(aggr_portids != NULL);
92 94 }
93 95
94 96 void
95 97 aggr_port_fini(void)
96 98 {
97 99 /*
98 100 * This function is called only after all groups have been
99 101 * freed. This ensures that there are no remaining allocated
100 102 * ports when this function is invoked.
101 103 */
102 104 kmem_cache_destroy(aggr_port_cache);
103 105 id_space_destroy(aggr_portids);
104 106 }
105 107
106 108 /* ARGSUSED */
107 109 void
108 110 aggr_port_init_callbacks(aggr_port_t *port)
109 111 {
110 112 /* add the port's receive callback */
111 113 port->lp_mnh = mac_notify_add(port->lp_mh, aggr_port_notify_cb, port);
112 114 /*
113 115 * Hold a reference of the grp and the port and this reference will
114 116 * be released when the thread exits.
115 117 *
116 118 * The reference on the port is used for aggr_port_delete() to
117 119 * continue without waiting for the thread to exit; the reference
118 120 * on the grp is used for aggr_grp_delete() to wait for the thread
119 121 * to exit before calling mac_unregister().
120 122 *
121 123 * Note that these references will be released either in
122 124 * aggr_port_delete() when mac_notify_remove() succeeds, or in
123 125 * the aggr_port_notify_cb() callback when the port is deleted
124 126 * (lp_closing is set).
125 127 */
126 128 aggr_grp_port_hold(port);
127 129 }
128 130
129 131 /* ARGSUSED */
130 132 int
131 133 aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force,
132 134 aggr_port_t **pp)
133 135 {
134 136 int err;
135 137 mac_handle_t mh;
136 138 mac_client_handle_t mch = NULL;
137 139 aggr_port_t *port;
138 140 uint16_t portid;
139 141 uint_t i;
140 142 boolean_t no_link_update = B_FALSE;
141 143 const mac_info_t *mip;
142 144 uint32_t note;
143 145 uint32_t margin;
144 146 char client_name[MAXNAMELEN];
145 147 char aggr_name[MAXNAMELEN];
146 148 char port_name[MAXNAMELEN];
147 149 mac_diag_t diag;
148 150 mac_unicast_handle_t mah;
149 151
150 152 *pp = NULL;
151 153
152 154 if ((err = mac_open_by_linkid(linkid, &mh)) != 0)
153 155 return (err);
154 156
155 157 mip = mac_info(mh);
156 158 if (mip->mi_media != DL_ETHER || mip->mi_nativemedia != DL_ETHER) {
157 159 err = EINVAL;
158 160 goto fail;
159 161 }
160 162
161 163 /*
162 164 * If the underlying MAC does not support link update notification, it
163 165 * can only be aggregated if `force' is set. This is because aggr
164 166 * depends on link notifications to attach ports whose link is up.
165 167 */
166 168 note = mac_no_notification(mh);
167 169 if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) {
168 170 no_link_update = B_TRUE;
169 171 if (!force) {
170 172 /*
171 173 * We borrow this error code to indicate that link
172 174 * notification is not supported.
173 175 */
174 176 err = ENETDOWN;
175 177 goto fail;
176 178 }
177 179 }
178 180
179 181 if (((err = dls_mgmt_get_linkinfo(grp->lg_linkid,
180 182 aggr_name, NULL, NULL, NULL)) != 0) ||
181 183 ((err = dls_mgmt_get_linkinfo(linkid, port_name,
182 184 NULL, NULL, NULL)) != 0)) {
183 185 goto fail;
184 186 }
185 187
186 188 (void) snprintf(client_name, MAXNAMELEN, "%s-%s", aggr_name, port_name);
187 189 if ((err = mac_client_open(mh, &mch, client_name,
188 190 MAC_OPEN_FLAGS_IS_AGGR_PORT | MAC_OPEN_FLAGS_EXCLUSIVE)) != 0) {
189 191 goto fail;
190 192 }
191 193
192 194 if ((portid = (uint16_t)id_alloc(aggr_portids)) == 0) {
193 195 err = ENOMEM;
194 196 goto fail;
195 197 }
196 198
197 199 /*
198 200 * As the underlying mac's current margin size is used to determine
199 201 * the margin size of the aggregation itself, request the underlying
200 202 * mac not to change to a smaller size.
201 203 */
202 204 if ((err = mac_margin_add(mh, &margin, B_TRUE)) != 0) {
203 205 id_free(aggr_portids, portid);
204 206 goto fail;
205 207 }
206 208
207 209 if ((err = mac_unicast_add(mch, NULL, MAC_UNICAST_PRIMARY |
208 210 MAC_UNICAST_DISABLE_TX_VID_CHECK, &mah, 0, &diag)) != 0) {
209 211 VERIFY(mac_margin_remove(mh, margin) == 0);
210 212 id_free(aggr_portids, portid);
211 213 goto fail;
212 214 }
213 215
214 216 port = kmem_cache_alloc(aggr_port_cache, KM_SLEEP);
215 217
216 218 port->lp_refs = 1;
217 219 port->lp_next = NULL;
218 220 port->lp_mh = mh;
219 221 port->lp_mch = mch;
220 222 port->lp_mip = mip;
221 223 port->lp_linkid = linkid;
222 224 port->lp_closing = B_FALSE;
223 225 port->lp_mah = mah;
224 226
225 227 /* get the port's original MAC address */
226 228 mac_unicast_primary_get(port->lp_mh, port->lp_addr);
227 229
228 230 /* initialize state */
229 231 port->lp_state = AGGR_PORT_STATE_STANDBY;
230 232 port->lp_link_state = LINK_STATE_UNKNOWN;
231 233 port->lp_ifspeed = 0;
232 234 port->lp_link_duplex = LINK_DUPLEX_UNKNOWN;
233 235 port->lp_started = B_FALSE;
234 236 port->lp_tx_enabled = B_FALSE;
235 237 port->lp_promisc_on = B_FALSE;
236 238 port->lp_no_link_update = no_link_update;
237 239 port->lp_portid = portid;
238 240 port->lp_margin = margin;
239 241 port->lp_prom_addr = NULL;
240 242
241 243 /*
242 244 * Save the current statistics of the port. They will be used
243 245 * later by aggr_m_stats() when aggregating the statistics of
244 246 * the constituent ports.
245 247 */
246 248 for (i = 0; i < MAC_NSTAT; i++) {
247 249 port->lp_stat[i] =
248 250 aggr_port_stat(port, i + MAC_STAT_MIN);
249 251 }
250 252 for (i = 0; i < ETHER_NSTAT; i++) {
251 253 port->lp_ether_stat[i] =
252 254 aggr_port_stat(port, i + MACTYPE_STAT_MIN);
253 255 }
254 256
255 257 /* LACP related state */
256 258 port->lp_collector_enabled = B_FALSE;
257 259
258 260 *pp = port;
259 261 return (0);
260 262
261 263 fail:
262 264 if (mch != NULL)
263 265 mac_client_close(mch, MAC_CLOSE_FLAGS_EXCLUSIVE);
264 266 mac_close(mh);
265 267 return (err);
266 268 }
267 269
268 270 void
269 271 aggr_port_delete(aggr_port_t *port)
270 272 {
271 273 aggr_lacp_port_t *pl = &port->lp_lacp;
272 274
273 275 ASSERT(port->lp_mphp == NULL);
274 276 ASSERT(!port->lp_promisc_on);
275 277
276 278 port->lp_closing = B_TRUE;
277 279
278 280 VERIFY(mac_margin_remove(port->lp_mh, port->lp_margin) == 0);
279 281 mac_rx_clear(port->lp_mch);
280 282 /*
281 283 * If the notification callback is already in process and waiting for
282 284 * the aggr grp's mac perimeter, don't wait (otherwise there would be
283 285 * deadlock). Otherwise, if mac_notify_remove() succeeds, we can
284 286 * release the reference held when mac_notify_add() is called.
285 287 */
286 288 if ((port->lp_mnh != NULL) &&
287 289 (mac_notify_remove(port->lp_mnh, B_FALSE) == 0)) {
288 290 aggr_grp_port_rele(port);
289 291 }
290 292 port->lp_mnh = NULL;
291 293
292 294 /*
293 295 * Inform the the port lacp timer thread to exit. Note that waiting
294 296 * for the thread to exit may cause deadlock since that thread may
295 297 * need to enter into the mac perimeter which we are currently in.
296 298 * It is fine to continue without waiting though since that thread
297 299 * is holding a reference of the port.
298 300 */
299 301 mutex_enter(&pl->lacp_timer_lock);
300 302 pl->lacp_timer_bits |= LACP_THREAD_EXIT;
301 303 cv_broadcast(&pl->lacp_timer_cv);
302 304 mutex_exit(&pl->lacp_timer_lock);
303 305
304 306 /*
305 307 * Restore the port MAC address. Note it is called after the
306 308 * port's notification callback being removed. This prevent
307 309 * port's MAC_NOTE_UNICST notify callback function being called.
308 310 */
309 311 (void) mac_unicast_primary_set(port->lp_mh, port->lp_addr);
310 312 if (port->lp_mah != NULL)
311 313 (void) mac_unicast_remove(port->lp_mch, port->lp_mah);
312 314 mac_client_close(port->lp_mch, MAC_CLOSE_FLAGS_EXCLUSIVE);
313 315 mac_close(port->lp_mh);
314 316 AGGR_PORT_REFRELE(port);
315 317 }
316 318
317 319 void
318 320 aggr_port_free(aggr_port_t *port)
319 321 {
320 322 ASSERT(port->lp_refs == 0);
321 323 if (port->lp_grp != NULL)
322 324 AGGR_GRP_REFRELE(port->lp_grp);
323 325 port->lp_grp = NULL;
324 326 id_free(aggr_portids, port->lp_portid);
325 327 port->lp_portid = 0;
326 328 mutex_destroy(&port->lp_lacp.lacp_timer_lock);
327 329 cv_destroy(&port->lp_lacp.lacp_timer_cv);
328 330 kmem_cache_free(aggr_port_cache, port);
329 331 }
330 332
331 333 /*
332 334 * Invoked upon receiving a MAC_NOTE_LINK notification for
333 335 * one of the constituent ports.
334 336 */
335 337 boolean_t
336 338 aggr_port_notify_link(aggr_grp_t *grp, aggr_port_t *port)
337 339 {
338 340 boolean_t do_attach = B_FALSE;
339 341 boolean_t do_detach = B_FALSE;
340 342 boolean_t link_state_changed = B_TRUE;
341 343 uint64_t ifspeed;
342 344 link_state_t link_state;
343 345 link_duplex_t link_duplex;
344 346 mac_perim_handle_t mph;
345 347
346 348 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
347 349 mac_perim_enter_by_mh(port->lp_mh, &mph);
348 350
349 351 /*
350 352 * link state change? For links that do not support link state
351 353 * notification, always assume the link is up.
352 354 */
353 355 link_state = port->lp_no_link_update ? LINK_STATE_UP :
354 356 mac_link_get(port->lp_mh);
355 357 if (port->lp_link_state != link_state) {
356 358 if (link_state == LINK_STATE_UP)
357 359 do_attach = (port->lp_link_state != LINK_STATE_UP);
358 360 else
359 361 do_detach = (port->lp_link_state == LINK_STATE_UP);
360 362 }
361 363 port->lp_link_state = link_state;
362 364
363 365 /* link duplex change? */
364 366 link_duplex = aggr_port_stat(port, ETHER_STAT_LINK_DUPLEX);
365 367 if (port->lp_link_duplex != link_duplex) {
↓ open down ↓ |
332 lines elided |
↑ open up ↑ |
366 368 if (link_duplex == LINK_DUPLEX_FULL)
367 369 do_attach |= (port->lp_link_duplex != LINK_DUPLEX_FULL);
368 370 else
369 371 do_detach |= (port->lp_link_duplex == LINK_DUPLEX_FULL);
370 372 }
371 373 port->lp_link_duplex = link_duplex;
372 374
373 375 /* link speed changes? */
374 376 ifspeed = aggr_port_stat(port, MAC_STAT_IFSPEED);
375 377 if (port->lp_ifspeed != ifspeed) {
378 + mutex_enter(&grp->lg_stat_lock);
379 +
376 380 if (port->lp_state == AGGR_PORT_STATE_ATTACHED)
377 381 do_detach |= (ifspeed != grp->lg_ifspeed);
378 382 else
379 383 do_attach |= (ifspeed == grp->lg_ifspeed);
384 +
385 + mutex_exit(&grp->lg_stat_lock);
380 386 }
381 387 port->lp_ifspeed = ifspeed;
382 388
383 389 if (do_attach) {
384 390 /* attempt to attach the port to the aggregation */
385 391 link_state_changed = aggr_grp_attach_port(grp, port);
386 392 } else if (do_detach) {
387 393 /* detach the port from the aggregation */
388 394 link_state_changed = aggr_grp_detach_port(grp, port);
389 395 }
390 396
391 397 mac_perim_exit(mph);
392 398 return (link_state_changed);
393 399 }
394 400
395 401 /*
396 402 * Invoked upon receiving a MAC_NOTE_UNICST for one of the constituent
397 403 * ports of a group.
398 404 */
399 405 static void
400 406 aggr_port_notify_unicst(aggr_grp_t *grp, aggr_port_t *port,
401 407 boolean_t *mac_addr_changedp, boolean_t *link_state_changedp)
402 408 {
403 409 boolean_t mac_addr_changed = B_FALSE;
404 410 boolean_t link_state_changed = B_FALSE;
405 411 uint8_t mac_addr[ETHERADDRL];
406 412 mac_perim_handle_t mph;
407 413
408 414 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
409 415 ASSERT(mac_addr_changedp != NULL);
410 416 ASSERT(link_state_changedp != NULL);
411 417 mac_perim_enter_by_mh(port->lp_mh, &mph);
412 418
413 419 /*
414 420 * If it is called when setting the MAC address to the
415 421 * aggregation group MAC address, do nothing.
416 422 */
417 423 mac_unicast_primary_get(port->lp_mh, mac_addr);
418 424 if (bcmp(mac_addr, grp->lg_addr, ETHERADDRL) == 0) {
419 425 mac_perim_exit(mph);
420 426 goto done;
421 427 }
422 428
423 429 /* save the new port MAC address */
424 430 bcopy(mac_addr, port->lp_addr, ETHERADDRL);
425 431
426 432 aggr_grp_port_mac_changed(grp, port, &mac_addr_changed,
427 433 &link_state_changed);
428 434
429 435 mac_perim_exit(mph);
430 436
431 437 /*
432 438 * If this port was used to determine the MAC address of
433 439 * the group, update the MAC address of the constituent
434 440 * ports.
435 441 */
436 442 if (mac_addr_changed && aggr_grp_update_ports_mac(grp))
437 443 link_state_changed = B_TRUE;
438 444
439 445 done:
440 446 *mac_addr_changedp = mac_addr_changed;
441 447 *link_state_changedp = link_state_changed;
442 448 }
443 449
444 450 /*
445 451 * Notification callback invoked by the MAC service module for
446 452 * a particular MAC port.
447 453 */
448 454 static void
449 455 aggr_port_notify_cb(void *arg, mac_notify_type_t type)
450 456 {
451 457 aggr_port_t *port = arg;
452 458 aggr_grp_t *grp = port->lp_grp;
453 459 boolean_t mac_addr_changed, link_state_changed;
454 460 mac_perim_handle_t mph;
455 461
456 462 mac_perim_enter_by_mh(grp->lg_mh, &mph);
457 463 if (port->lp_closing) {
458 464 mac_perim_exit(mph);
459 465
460 466 /*
461 467 * Release the reference so it is safe for aggr to call
462 468 * mac_unregister() now.
463 469 */
464 470 aggr_grp_port_rele(port);
465 471 return;
466 472 }
467 473
468 474 switch (type) {
469 475 case MAC_NOTE_TX:
470 476 mac_tx_update(grp->lg_mh);
471 477 break;
472 478 case MAC_NOTE_LINK:
473 479 if (aggr_port_notify_link(grp, port))
474 480 mac_link_update(grp->lg_mh, grp->lg_link_state);
475 481 break;
476 482 case MAC_NOTE_UNICST:
477 483 aggr_port_notify_unicst(grp, port, &mac_addr_changed,
478 484 &link_state_changed);
479 485 if (mac_addr_changed)
480 486 mac_unicst_update(grp->lg_mh, grp->lg_addr);
481 487 if (link_state_changed)
482 488 mac_link_update(grp->lg_mh, grp->lg_link_state);
483 489 break;
484 490 default:
485 491 break;
486 492 }
487 493
488 494 mac_perim_exit(mph);
489 495 }
490 496
491 497 int
492 498 aggr_port_start(aggr_port_t *port)
493 499 {
494 500 ASSERT(MAC_PERIM_HELD(port->lp_mh));
495 501
496 502 if (port->lp_started)
497 503 return (0);
498 504
499 505 port->lp_started = B_TRUE;
500 506 aggr_grp_multicst_port(port, B_TRUE);
501 507 return (0);
502 508 }
503 509
504 510 void
505 511 aggr_port_stop(aggr_port_t *port)
506 512 {
507 513 ASSERT(MAC_PERIM_HELD(port->lp_mh));
508 514
509 515 if (!port->lp_started)
510 516 return;
511 517
512 518 aggr_grp_multicst_port(port, B_FALSE);
513 519
514 520 /* update the port state */
515 521 port->lp_started = B_FALSE;
516 522 }
517 523
518 524 int
519 525 aggr_port_promisc(aggr_port_t *port, boolean_t on)
520 526 {
↓ open down ↓ |
131 lines elided |
↑ open up ↑ |
521 527 int rc;
522 528
523 529 ASSERT(MAC_PERIM_HELD(port->lp_mh));
524 530
525 531 if (on == port->lp_promisc_on)
526 532 /* already in desired promiscous mode */
527 533 return (0);
528 534
529 535 if (on) {
530 536 mac_rx_clear(port->lp_mch);
537 +
538 + /*
539 + * We use the promisc callback because without hardware
540 + * rings, we deliver through flows that will cause duplicate
541 + * delivery of packets when we've flipped into this mode
542 + * to compensate for the lack of hardware MAC matching
543 + */
531 544 rc = mac_promisc_add(port->lp_mch, MAC_CLIENT_PROMISC_ALL,
532 - aggr_recv_cb, port, &port->lp_mphp,
545 + aggr_recv_promisc_cb, port, &port->lp_mphp,
533 546 MAC_PROMISC_FLAGS_NO_TX_LOOP);
534 547 if (rc != 0) {
535 548 mac_rx_set(port->lp_mch, aggr_recv_cb, port);
536 549 return (rc);
537 550 }
538 551 } else {
539 552 mac_promisc_remove(port->lp_mphp);
540 553 port->lp_mphp = NULL;
541 554 mac_rx_set(port->lp_mch, aggr_recv_cb, port);
542 555 }
543 556
544 557 port->lp_promisc_on = on;
545 558
546 559 return (0);
547 560 }
548 561
549 562 /*
550 563 * Set the MAC address of a port.
551 564 */
552 565 int
553 566 aggr_port_unicst(aggr_port_t *port)
554 567 {
555 568 aggr_grp_t *grp = port->lp_grp;
556 569
557 570 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
558 571 ASSERT(MAC_PERIM_HELD(port->lp_mh));
559 572
560 573 return (mac_unicast_primary_set(port->lp_mh, grp->lg_addr));
561 574 }
562 575
563 576 /*
564 577 * Add or remove a multicast address to/from a port.
565 578 */
566 579 int
567 580 aggr_port_multicst(void *arg, boolean_t add, const uint8_t *addrp)
568 581 {
569 582 aggr_port_t *port = arg;
570 583
571 584 if (add) {
572 585 return (mac_multicast_add(port->lp_mch, addrp));
573 586 } else {
574 587 mac_multicast_remove(port->lp_mch, addrp);
575 588 return (0);
576 589 }
577 590 }
578 591
579 592 uint64_t
580 593 aggr_port_stat(aggr_port_t *port, uint_t stat)
581 594 {
582 595 return (mac_stat_get(port->lp_mh, stat));
583 596 }
584 597
585 598 /*
586 599 * Add a non-primary unicast address to the underlying port. If the port
587 600 * supports HW Rx group, try to add the address into the HW Rx group of
588 601 * the port first. If that fails, or if the port does not support HW Rx
589 602 * group, enable the port's promiscous mode.
590 603 */
591 604 int
592 605 aggr_port_addmac(aggr_port_t *port, const uint8_t *mac_addr)
593 606 {
594 607 aggr_unicst_addr_t *addr, **pprev;
595 608 mac_perim_handle_t pmph;
596 609 int err;
597 610
598 611 ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
599 612 mac_perim_enter_by_mh(port->lp_mh, &pmph);
600 613
601 614 /*
602 615 * If the underlying port support HW Rx group, add the mac to its
603 616 * RX group directly.
604 617 */
605 618 if ((port->lp_hwgh != NULL) &&
606 619 ((mac_hwgroup_addmac(port->lp_hwgh, mac_addr)) == 0)) {
607 620 mac_perim_exit(pmph);
608 621 return (0);
609 622 }
610 623
611 624 /*
612 625 * If that fails, or if the port does not support HW Rx group, enable
613 626 * the port's promiscous mode. (Note that we turn on the promiscous
614 627 * mode only if the port is already started.
615 628 */
616 629 if (port->lp_started &&
617 630 ((err = aggr_port_promisc(port, B_TRUE)) != 0)) {
618 631 mac_perim_exit(pmph);
619 632 return (err);
620 633 }
621 634
622 635 /*
623 636 * Walk through the unicast addresses that requires promiscous mode
624 637 * enabled on this port, and add this address to the end of the list.
625 638 */
626 639 pprev = &port->lp_prom_addr;
627 640 while ((addr = *pprev) != NULL) {
628 641 ASSERT(bcmp(mac_addr, addr->aua_addr, ETHERADDRL) != 0);
629 642 pprev = &addr->aua_next;
630 643 }
631 644 addr = kmem_alloc(sizeof (aggr_unicst_addr_t), KM_SLEEP);
632 645 bcopy(mac_addr, addr->aua_addr, ETHERADDRL);
633 646 addr->aua_next = NULL;
634 647 *pprev = addr;
635 648 mac_perim_exit(pmph);
636 649 return (0);
637 650 }
638 651
639 652 /*
640 653 * Remove a non-primary unicast address from the underlying port. This address
641 654 * must has been added by aggr_port_addmac(). As a result, we probably need to
642 655 * remove the address from the port's HW Rx group, or to disable the port's
643 656 * promiscous mode.
644 657 */
645 658 void
646 659 aggr_port_remmac(aggr_port_t *port, const uint8_t *mac_addr)
647 660 {
648 661 aggr_grp_t *grp = port->lp_grp;
649 662 aggr_unicst_addr_t *addr, **pprev;
650 663 mac_perim_handle_t pmph;
651 664
652 665 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
653 666 mac_perim_enter_by_mh(port->lp_mh, &pmph);
654 667
655 668 /*
656 669 * See whether this address is in the list of addresses that requires
657 670 * the port being promiscous mode.
658 671 */
659 672 pprev = &port->lp_prom_addr;
660 673 while ((addr = *pprev) != NULL) {
661 674 if (bcmp(mac_addr, addr->aua_addr, ETHERADDRL) == 0)
662 675 break;
663 676 pprev = &addr->aua_next;
664 677 }
665 678 if (addr != NULL) {
666 679 /*
667 680 * This unicast address put the port into the promiscous mode,
668 681 * delete this address from the lp_prom_addr list. If this is
669 682 * the last address in that list, disable the promiscous mode
670 683 * if the aggregation is not in promiscous mode.
↓ open down ↓ |
128 lines elided |
↑ open up ↑ |
671 684 */
672 685 *pprev = addr->aua_next;
673 686 kmem_free(addr, sizeof (aggr_unicst_addr_t));
674 687 if (port->lp_prom_addr == NULL && !grp->lg_promisc)
675 688 (void) aggr_port_promisc(port, B_FALSE);
676 689 } else {
677 690 ASSERT(port->lp_hwgh != NULL);
678 691 (void) mac_hwgroup_remmac(port->lp_hwgh, mac_addr);
679 692 }
680 693 mac_perim_exit(pmph);
694 +}
695 +
696 +int
697 +aggr_port_addvlan(aggr_port_t *port, uint16_t vid)
698 +{
699 + mac_perim_handle_t pmph;
700 + int err;
701 +
702 + ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
703 + mac_perim_enter_by_mh(port->lp_mh, &pmph);
704 +
705 + /*
706 + * Add the VLAN filter to the HW group if the port has a HW
707 + * group. If the port doesn't have a HW group, then it will
708 + * implicitly allow tagged traffic to pass and there is
709 + * nothing to do.
710 + */
711 + if (port->lp_hwgh == NULL)
712 + return (0);
713 +
714 + err = mac_hwgroup_addvlan(port->lp_hwgh, vid);
715 + mac_perim_exit(pmph);
716 + return (err);
717 +}
718 +
719 +int
720 +aggr_port_remvlan(aggr_port_t *port, uint16_t vid)
721 +{
722 + mac_perim_handle_t pmph;
723 + int err;
724 +
725 + ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
726 + mac_perim_enter_by_mh(port->lp_mh, &pmph);
727 +
728 + if (port->lp_hwgh == NULL)
729 + return (0);
730 +
731 + err = mac_hwgroup_remvlan(port->lp_hwgh, vid);
732 + mac_perim_exit(pmph);
733 + return (err);
681 734 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX