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