Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/aggr/aggr_lacp.c
+++ new/usr/src/uts/common/io/aggr/aggr_lacp.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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 /*
26 26 * IEEE 802.3ad Link Aggregation - LACP & Marker Protocol processing.
27 27 */
28 28
29 29 #include <sys/types.h>
30 30 #include <sys/sysmacros.h>
31 31 #include <sys/callb.h>
32 32 #include <sys/conf.h>
33 33 #include <sys/cmn_err.h>
34 34 #include <sys/disp.h>
35 35 #include <sys/list.h>
36 36 #include <sys/ksynch.h>
37 37 #include <sys/kmem.h>
38 38 #include <sys/stream.h>
39 39 #include <sys/modctl.h>
40 40 #include <sys/ddi.h>
41 41 #include <sys/sunddi.h>
42 42 #include <sys/atomic.h>
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
43 43 #include <sys/stat.h>
44 44 #include <sys/byteorder.h>
45 45 #include <sys/strsun.h>
46 46 #include <sys/isa_defs.h>
47 47 #include <sys/sdt.h>
48 48
49 49 #include <sys/aggr.h>
50 50 #include <sys/aggr_impl.h>
51 51
52 52 static struct ether_addr etherzeroaddr = {
53 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
53 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
54 54 };
55 55
56 56 /*
57 57 * Slow_Protocol_Multicast address, as per IEEE 802.3ad spec.
58 58 */
59 59 static struct ether_addr slow_multicast_addr = {
60 - 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02
60 + {0x01, 0x80, 0xc2, 0x00, 0x00, 0x02}
61 61 };
62 62
63 63 #ifdef DEBUG
64 64 /* LACP state machine debugging support */
65 65 static uint32_t aggr_lacp_debug = 0;
66 66 #define AGGR_LACP_DBG(x) if (aggr_lacp_debug) { (void) printf x; }
67 67 #else
68 68 #define AGGR_LACP_DBG(x) {}
69 69 #endif /* DEBUG */
70 70
71 71 #define NSECS_PER_SEC 1000000000ll
72 72
73 73 /* used by lacp_misconfig_walker() */
74 74 typedef struct lacp_misconfig_check_state_s {
75 75 aggr_port_t *cs_portp;
76 76 boolean_t cs_found;
77 77 } lacp_misconfig_check_state_t;
78 78
79 79 static const char *lacp_receive_str[] = LACP_RECEIVE_STATE_STRINGS;
80 80 static const char *lacp_periodic_str[] = LACP_PERIODIC_STRINGS;
81 81 static const char *lacp_mux_str[] = LACP_MUX_STRINGS;
82 82
83 83 static uint16_t lacp_port_priority = 0x1000;
84 84 static uint16_t lacp_system_priority = 0x1000;
85 85
86 86 /*
87 87 * Maintains a list of all ports in ATTACHED state. This information
88 88 * is used to detect misconfiguration.
89 89 */
90 90 typedef struct lacp_sel_ports {
91 91 datalink_id_t sp_grp_linkid;
92 92 datalink_id_t sp_linkid;
93 93 /* Note: sp_partner_system must be 2-byte aligned */
94 94 struct ether_addr sp_partner_system;
95 95 uint32_t sp_partner_key;
96 96 struct lacp_sel_ports *sp_next;
97 97 } lacp_sel_ports_t;
98 98
99 99 static lacp_sel_ports_t *sel_ports = NULL;
100 100 static kmutex_t lacp_sel_lock;
101 101
102 102 static void periodic_timer_pop(void *);
103 103 static void periodic_timer_pop_handler(aggr_port_t *);
104 104 static void lacp_xmit_sm(aggr_port_t *);
105 105 static void lacp_periodic_sm(aggr_port_t *);
106 106 static void fill_lacp_pdu(aggr_port_t *, lacp_t *);
107 107 static void fill_lacp_ether(aggr_port_t *, struct ether_header *);
108 108 static void lacp_on(aggr_port_t *);
109 109 static void lacp_off(aggr_port_t *);
110 110 static boolean_t valid_lacp_pdu(aggr_port_t *, lacp_t *);
111 111 static void lacp_receive_sm(aggr_port_t *, lacp_t *);
112 112 static void aggr_set_coll_dist(aggr_port_t *, boolean_t);
113 113 static void start_wait_while_timer(aggr_port_t *);
114 114 static void stop_wait_while_timer(aggr_port_t *);
115 115 static void lacp_reset_port(aggr_port_t *);
116 116 static void stop_current_while_timer(aggr_port_t *);
117 117 static void current_while_timer_pop(void *);
118 118 static void current_while_timer_pop_handler(aggr_port_t *);
119 119 static void update_default_selected(aggr_port_t *);
120 120 static boolean_t update_selected(aggr_port_t *, lacp_t *);
121 121 static boolean_t lacp_sel_ports_add(aggr_port_t *);
122 122 static void lacp_sel_ports_del(aggr_port_t *);
123 123 static void wait_while_timer_pop(void *);
124 124 static void wait_while_timer_pop_handler(aggr_port_t *);
125 125
126 126 void
127 127 aggr_lacp_init(void)
128 128 {
129 129 mutex_init(&lacp_sel_lock, NULL, MUTEX_DEFAULT, NULL);
130 130 }
131 131
132 132 void
133 133 aggr_lacp_fini(void)
134 134 {
135 135 mutex_destroy(&lacp_sel_lock);
136 136 }
137 137
138 138 /*
139 139 * The following functions are used for handling LACP timers.
140 140 *
141 141 * Note that we cannot fully rely on the aggr's mac perimeter in the timeout
142 142 * handler routine, otherwise it may cause deadlock with the untimeout() call
143 143 * which is usually called with the mac perimeter held. Instead, a
144 144 * lacp_timer_lock mutex is introduced, which protects a bitwise flag
145 145 * (lacp_timer_bits). This flag is set/cleared by timeout()/stop_timer()
146 146 * routines and is checked by a dedicated thread, that executes the real
147 147 * timeout operation.
148 148 */
149 149 static void
150 150 aggr_port_timer_thread(void *arg)
151 151 {
152 152 aggr_port_t *port = arg;
153 153 aggr_lacp_port_t *pl = &port->lp_lacp;
154 154 aggr_grp_t *grp = port->lp_grp;
155 155 uint32_t lacp_timer_bits;
156 156 mac_perim_handle_t mph;
157 157 callb_cpr_t cprinfo;
158 158
159 159 CALLB_CPR_INIT(&cprinfo, &pl->lacp_timer_lock, callb_generic_cpr,
160 160 "aggr_port_timer_thread");
161 161
162 162 mutex_enter(&pl->lacp_timer_lock);
163 163
164 164 for (;;) {
165 165
166 166 if ((lacp_timer_bits = pl->lacp_timer_bits) == 0) {
167 167 CALLB_CPR_SAFE_BEGIN(&cprinfo);
168 168 cv_wait(&pl->lacp_timer_cv, &pl->lacp_timer_lock);
169 169 CALLB_CPR_SAFE_END(&cprinfo, &pl->lacp_timer_lock);
170 170 continue;
171 171 }
172 172 pl->lacp_timer_bits = 0;
173 173
174 174 if (lacp_timer_bits & LACP_THREAD_EXIT)
175 175 break;
176 176
177 177 if (lacp_timer_bits & LACP_PERIODIC_TIMEOUT)
178 178 pl->periodic_timer.id = 0;
179 179 if (lacp_timer_bits & LACP_WAIT_WHILE_TIMEOUT)
180 180 pl->wait_while_timer.id = 0;
181 181 if (lacp_timer_bits & LACP_CURRENT_WHILE_TIMEOUT)
182 182 pl->current_while_timer.id = 0;
183 183
184 184 mutex_exit(&pl->lacp_timer_lock);
185 185
186 186 mac_perim_enter_by_mh(grp->lg_mh, &mph);
187 187 if (port->lp_closing) {
188 188 mac_perim_exit(mph);
189 189 mutex_enter(&pl->lacp_timer_lock);
190 190 break;
191 191 }
192 192
193 193 if (lacp_timer_bits & LACP_PERIODIC_TIMEOUT)
194 194 periodic_timer_pop_handler(port);
195 195 if (lacp_timer_bits & LACP_WAIT_WHILE_TIMEOUT)
196 196 wait_while_timer_pop_handler(port);
197 197 if (lacp_timer_bits & LACP_CURRENT_WHILE_TIMEOUT)
198 198 current_while_timer_pop_handler(port);
199 199 mac_perim_exit(mph);
200 200
201 201 mutex_enter(&pl->lacp_timer_lock);
202 202 if (pl->lacp_timer_bits & LACP_THREAD_EXIT)
203 203 break;
204 204 }
205 205
206 206 pl->lacp_timer_bits = 0;
207 207 pl->lacp_timer_thread = NULL;
208 208 cv_broadcast(&pl->lacp_timer_cv);
209 209
210 210 /* CALLB_CPR_EXIT drops the lock */
211 211 CALLB_CPR_EXIT(&cprinfo);
212 212
213 213 /*
214 214 * Release the reference of the grp so aggr_grp_delete() can call
215 215 * mac_unregister() safely.
216 216 */
217 217 aggr_grp_port_rele(port);
218 218 thread_exit();
219 219 }
220 220
221 221 /*
222 222 * Set the port LACP state to SELECTED. Returns B_FALSE if the operation
223 223 * could not be performed due to a memory allocation error, B_TRUE otherwise.
224 224 */
225 225 static boolean_t
226 226 lacp_port_select(aggr_port_t *portp)
227 227 {
228 228 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
229 229
230 230 if (!lacp_sel_ports_add(portp))
231 231 return (B_FALSE);
232 232 portp->lp_lacp.sm.selected = AGGR_SELECTED;
233 233 return (B_TRUE);
234 234 }
235 235
236 236 /*
237 237 * Set the port LACP state to UNSELECTED.
238 238 */
239 239 static void
240 240 lacp_port_unselect(aggr_port_t *portp)
241 241 {
242 242 aggr_grp_t *grp = portp->lp_grp;
243 243
244 244 ASSERT((grp->lg_mh == NULL) || MAC_PERIM_HELD(grp->lg_mh));
245 245
246 246 lacp_sel_ports_del(portp);
247 247 portp->lp_lacp.sm.selected = AGGR_UNSELECTED;
248 248 }
249 249
250 250 /*
251 251 * Initialize group specific LACP state and parameters.
252 252 */
253 253 void
254 254 aggr_lacp_init_grp(aggr_grp_t *aggrp)
255 255 {
256 256 aggrp->aggr.PeriodicTimer = AGGR_LACP_TIMER_SHORT;
257 257 aggrp->aggr.ActorSystemPriority = (uint16_t)lacp_system_priority;
258 258 aggrp->aggr.CollectorMaxDelay = 10;
259 259 aggrp->lg_lacp_mode = AGGR_LACP_OFF;
260 260 aggrp->aggr.ready = B_FALSE;
261 261 }
262 262
263 263 /*
264 264 * Complete LACP info initialization at port creation time.
265 265 */
266 266 void
267 267 aggr_lacp_init_port(aggr_port_t *portp)
268 268 {
269 269 aggr_grp_t *aggrp = portp->lp_grp;
270 270 aggr_lacp_port_t *pl = &portp->lp_lacp;
271 271
272 272 ASSERT(aggrp->lg_mh == NULL || MAC_PERIM_HELD(aggrp->lg_mh));
273 273 ASSERT(MAC_PERIM_HELD(portp->lp_mh));
274 274
275 275 /* actor port # */
276 276 pl->ActorPortNumber = portp->lp_portid;
277 277 AGGR_LACP_DBG(("aggr_lacp_init_port(%d): "
278 278 "ActorPortNumber = 0x%x\n", portp->lp_linkid,
279 279 pl->ActorPortNumber));
280 280
281 281 pl->ActorPortPriority = (uint16_t)lacp_port_priority;
282 282 pl->ActorPortAggrId = 0; /* aggregator id - not used */
283 283 pl->NTT = B_FALSE; /* need to transmit */
284 284
285 285 pl->ActorAdminPortKey = aggrp->lg_key;
286 286 pl->ActorOperPortKey = pl->ActorAdminPortKey;
287 287 AGGR_LACP_DBG(("aggr_lacp_init_port(%d) "
288 288 "ActorAdminPortKey = 0x%x, ActorAdminPortKey = 0x%x\n",
289 289 portp->lp_linkid, pl->ActorAdminPortKey, pl->ActorOperPortKey));
290 290
291 291 /* Actor admin. port state */
292 292 pl->ActorAdminPortState.bit.activity = B_FALSE;
293 293 pl->ActorAdminPortState.bit.timeout = B_TRUE;
294 294 pl->ActorAdminPortState.bit.aggregation = B_TRUE;
295 295 pl->ActorAdminPortState.bit.sync = B_FALSE;
296 296 pl->ActorAdminPortState.bit.collecting = B_FALSE;
297 297 pl->ActorAdminPortState.bit.distributing = B_FALSE;
298 298 pl->ActorAdminPortState.bit.defaulted = B_FALSE;
299 299 pl->ActorAdminPortState.bit.expired = B_FALSE;
300 300 pl->ActorOperPortState = pl->ActorAdminPortState;
301 301
302 302 /*
303 303 * Partner Administrative Information
304 304 * (All initialized to zero except for the following)
305 305 * Fast Timeouts.
306 306 */
307 307 pl->PartnerAdminPortState.bit.timeout =
308 308 pl->PartnerOperPortState.bit.timeout = B_TRUE;
309 309
310 310 pl->PartnerCollectorMaxDelay = 0; /* tens of microseconds */
311 311
312 312 /*
313 313 * State machine information.
314 314 */
315 315 pl->sm.lacp_on = B_FALSE; /* LACP Off default */
316 316 pl->sm.begin = B_TRUE; /* Prevents transmissions */
317 317 pl->sm.lacp_enabled = B_FALSE;
318 318 pl->sm.port_enabled = B_FALSE; /* Link Down */
319 319 pl->sm.actor_churn = B_FALSE;
320 320 pl->sm.partner_churn = B_FALSE;
321 321 pl->sm.ready_n = B_FALSE;
322 322 pl->sm.port_moved = B_FALSE;
323 323
324 324 lacp_port_unselect(portp);
325 325
326 326 pl->sm.periodic_state = LACP_NO_PERIODIC;
327 327 pl->sm.receive_state = LACP_INITIALIZE;
328 328 pl->sm.mux_state = LACP_DETACHED;
329 329 pl->sm.churn_state = LACP_NO_ACTOR_CHURN;
330 330
331 331 /*
332 332 * Timer information.
333 333 */
334 334 pl->current_while_timer.id = 0;
335 335 pl->current_while_timer.val = SHORT_TIMEOUT_TIME;
336 336
337 337 pl->periodic_timer.id = 0;
338 338 pl->periodic_timer.val = FAST_PERIODIC_TIME;
339 339
340 340 pl->wait_while_timer.id = 0;
341 341 pl->wait_while_timer.val = AGGREGATE_WAIT_TIME;
342 342
343 343 pl->lacp_timer_bits = 0;
344 344
345 345 mutex_init(&pl->lacp_timer_lock, NULL, MUTEX_DRIVER, NULL);
346 346 cv_init(&pl->lacp_timer_cv, NULL, CV_DRIVER, NULL);
347 347
348 348 pl->lacp_timer_thread = thread_create(NULL, 0, aggr_port_timer_thread,
349 349 portp, 0, &p0, TS_RUN, minclsyspri);
350 350
351 351 /*
352 352 * Hold a reference of the grp and the port and this reference will
353 353 * be release when the thread exits.
354 354 *
355 355 * The reference on the port is used for aggr_port_delete() to
356 356 * continue without waiting for the thread to exit; the reference
357 357 * on the grp is used for aggr_grp_delete() to wait for the thread
358 358 * to exit before calling mac_unregister().
359 359 */
360 360 aggr_grp_port_hold(portp);
361 361 }
362 362
363 363 /*
364 364 * Port initialization when we need to
365 365 * turn LACP on/off, etc. Not everything is
366 366 * reset like in the above routine.
367 367 * Do NOT modify things like link status.
368 368 */
369 369 static void
370 370 lacp_reset_port(aggr_port_t *portp)
371 371 {
372 372 aggr_lacp_port_t *pl = &portp->lp_lacp;
373 373
374 374 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
375 375
376 376 pl->NTT = B_FALSE; /* need to transmit */
377 377
378 378 /* reset operational port state */
379 379 pl->ActorOperPortState.bit.timeout =
380 380 pl->ActorAdminPortState.bit.timeout;
381 381
382 382 pl->ActorOperPortState.bit.sync = B_FALSE;
383 383 pl->ActorOperPortState.bit.collecting = B_FALSE;
384 384 pl->ActorOperPortState.bit.distributing = B_FALSE;
385 385 pl->ActorOperPortState.bit.defaulted = B_TRUE;
386 386 pl->ActorOperPortState.bit.expired = B_FALSE;
387 387
388 388 pl->PartnerOperPortState.bit.timeout = B_TRUE; /* fast t/o */
389 389 pl->PartnerCollectorMaxDelay = 0; /* tens of microseconds */
390 390
391 391 /*
392 392 * State machine information.
393 393 */
394 394 pl->sm.begin = B_TRUE; /* Prevents transmissions */
395 395 pl->sm.actor_churn = B_FALSE;
396 396 pl->sm.partner_churn = B_FALSE;
397 397 pl->sm.ready_n = B_FALSE;
398 398
399 399 lacp_port_unselect(portp);
400 400
401 401 pl->sm.periodic_state = LACP_NO_PERIODIC;
402 402 pl->sm.receive_state = LACP_INITIALIZE;
403 403 pl->sm.mux_state = LACP_DETACHED;
404 404 pl->sm.churn_state = LACP_NO_ACTOR_CHURN;
405 405
406 406 /*
407 407 * Timer information.
408 408 */
409 409 pl->current_while_timer.val = SHORT_TIMEOUT_TIME;
410 410 pl->periodic_timer.val = FAST_PERIODIC_TIME;
411 411 }
412 412
413 413 static void
414 414 aggr_lacp_mcast_on(aggr_port_t *port)
415 415 {
416 416 ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
417 417 ASSERT(MAC_PERIM_HELD(port->lp_mh));
418 418
419 419 if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
420 420 return;
421 421
422 422 (void) aggr_port_multicst(port, B_TRUE,
423 423 (uchar_t *)&slow_multicast_addr);
424 424 }
425 425
426 426 static void
427 427 aggr_lacp_mcast_off(aggr_port_t *port)
428 428 {
429 429 ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
430 430 ASSERT(MAC_PERIM_HELD(port->lp_mh));
431 431
432 432 if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
433 433 return;
434 434
435 435 (void) aggr_port_multicst(port, B_FALSE,
436 436 (uchar_t *)&slow_multicast_addr);
437 437 }
438 438
439 439 static void
440 440 start_periodic_timer(aggr_port_t *portp)
441 441 {
442 442 aggr_lacp_port_t *pl = &portp->lp_lacp;
443 443
444 444 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
445 445
446 446 mutex_enter(&pl->lacp_timer_lock);
447 447 if (pl->periodic_timer.id == 0) {
448 448 pl->periodic_timer.id = timeout(periodic_timer_pop, portp,
449 449 drv_usectohz(1000000 * portp->lp_lacp.periodic_timer.val));
450 450 }
451 451 mutex_exit(&pl->lacp_timer_lock);
452 452 }
453 453
454 454 static void
455 455 stop_periodic_timer(aggr_port_t *portp)
456 456 {
457 457 aggr_lacp_port_t *pl = &portp->lp_lacp;
458 458 timeout_id_t id;
459 459
460 460 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
461 461
462 462 mutex_enter(&pl->lacp_timer_lock);
463 463 if ((id = pl->periodic_timer.id) != 0) {
464 464 pl->lacp_timer_bits &= ~LACP_PERIODIC_TIMEOUT;
465 465 pl->periodic_timer.id = 0;
466 466 }
467 467 mutex_exit(&pl->lacp_timer_lock);
468 468
469 469 if (id != 0)
470 470 (void) untimeout(id);
471 471 }
472 472
473 473 /*
474 474 * When the timer pops, we arrive here to
475 475 * clear out LACPDU count as well as transmit an
476 476 * LACPDU. We then set the periodic state and let
477 477 * the periodic state machine restart the timer.
478 478 */
479 479 static void
480 480 periodic_timer_pop(void *data)
481 481 {
482 482 aggr_port_t *portp = data;
483 483 aggr_lacp_port_t *pl = &portp->lp_lacp;
484 484
485 485 mutex_enter(&pl->lacp_timer_lock);
486 486 pl->lacp_timer_bits |= LACP_PERIODIC_TIMEOUT;
487 487 cv_broadcast(&pl->lacp_timer_cv);
488 488 mutex_exit(&pl->lacp_timer_lock);
489 489 }
490 490
491 491 /*
492 492 * When the timer pops, we arrive here to
493 493 * clear out LACPDU count as well as transmit an
494 494 * LACPDU. We then set the periodic state and let
495 495 * the periodic state machine restart the timer.
496 496 */
497 497 static void
498 498 periodic_timer_pop_handler(aggr_port_t *portp)
499 499 {
500 500 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
501 501
502 502 portp->lp_lacp_stats.LACPDUsTx = 0;
503 503
504 504 /* current timestamp */
505 505 portp->lp_lacp.time = gethrtime();
506 506 portp->lp_lacp.NTT = B_TRUE;
507 507 lacp_xmit_sm(portp);
508 508
509 509 /*
510 510 * Set Periodic State machine state based on the
511 511 * value of the Partner Operation Port State timeout
512 512 * bit.
513 513 */
514 514 if (portp->lp_lacp.PartnerOperPortState.bit.timeout) {
515 515 portp->lp_lacp.periodic_timer.val = FAST_PERIODIC_TIME;
516 516 portp->lp_lacp.sm.periodic_state = LACP_FAST_PERIODIC;
517 517 } else {
518 518 portp->lp_lacp.periodic_timer.val = SLOW_PERIODIC_TIME;
519 519 portp->lp_lacp.sm.periodic_state = LACP_SLOW_PERIODIC;
520 520 }
521 521
522 522 lacp_periodic_sm(portp);
523 523 }
524 524
525 525 /*
526 526 * Invoked from:
527 527 * - startup upon aggregation
528 528 * - when the periodic timer pops
529 529 * - when the periodic timer value is changed
530 530 * - when the port is attached or detached
531 531 * - when LACP mode is changed.
532 532 */
533 533 static void
534 534 lacp_periodic_sm(aggr_port_t *portp)
535 535 {
536 536 lacp_periodic_state_t oldstate = portp->lp_lacp.sm.periodic_state;
537 537 aggr_lacp_port_t *pl = &portp->lp_lacp;
538 538
539 539 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
540 540
541 541 /* LACP_OFF state not in specification so check here. */
542 542 if (!pl->sm.lacp_on) {
543 543 /* Stop timer whether it is running or not */
544 544 stop_periodic_timer(portp);
545 545 pl->sm.periodic_state = LACP_NO_PERIODIC;
546 546 pl->NTT = B_FALSE;
547 547 AGGR_LACP_DBG(("lacp_periodic_sm(%d):NO LACP "
548 548 "%s--->%s\n", portp->lp_linkid,
549 549 lacp_periodic_str[oldstate],
550 550 lacp_periodic_str[pl->sm.periodic_state]));
551 551 return;
552 552 }
553 553
554 554 if (pl->sm.begin || !pl->sm.lacp_enabled ||
555 555 !pl->sm.port_enabled ||
556 556 !pl->ActorOperPortState.bit.activity &&
557 557 !pl->PartnerOperPortState.bit.activity) {
558 558
559 559 /* Stop timer whether it is running or not */
560 560 stop_periodic_timer(portp);
561 561 pl->sm.periodic_state = LACP_NO_PERIODIC;
562 562 pl->NTT = B_FALSE;
563 563 AGGR_LACP_DBG(("lacp_periodic_sm(%d):STOP %s--->%s\n",
564 564 portp->lp_linkid, lacp_periodic_str[oldstate],
565 565 lacp_periodic_str[pl->sm.periodic_state]));
566 566 return;
567 567 }
568 568
569 569 /*
570 570 * Startup with FAST_PERIODIC_TIME if no previous LACPDU
571 571 * has been received. Then after we timeout, then it is
572 572 * possible to go to SLOW_PERIODIC_TIME.
573 573 */
574 574 if (pl->sm.periodic_state == LACP_NO_PERIODIC) {
575 575 pl->periodic_timer.val = FAST_PERIODIC_TIME;
576 576 pl->sm.periodic_state = LACP_FAST_PERIODIC;
577 577 } else if ((pl->sm.periodic_state == LACP_SLOW_PERIODIC) &&
578 578 pl->PartnerOperPortState.bit.timeout) {
579 579 /*
580 580 * If we receive a bit indicating we are going to
581 581 * fast periodic from slow periodic, stop the timer
582 582 * and let the periodic_timer_pop routine deal
583 583 * with reseting the periodic state and transmitting
584 584 * a LACPDU.
585 585 */
586 586 stop_periodic_timer(portp);
587 587 periodic_timer_pop_handler(portp);
588 588 }
589 589
590 590 /* Rearm timer with value provided by partner */
591 591 start_periodic_timer(portp);
592 592 }
593 593
594 594 /*
595 595 * This routine transmits an LACPDU if lacp_enabled
596 596 * is TRUE and if NTT is set.
597 597 */
598 598 static void
599 599 lacp_xmit_sm(aggr_port_t *portp)
600 600 {
601 601 aggr_lacp_port_t *pl = &portp->lp_lacp;
602 602 size_t len;
603 603 mblk_t *mp;
604 604 hrtime_t now, elapsed;
605 605
606 606 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
607 607
608 608 /* LACP_OFF state not in specification so check here. */
609 609 if (!pl->sm.lacp_on || !pl->NTT || !portp->lp_started)
610 610 return;
611 611
612 612 /*
613 613 * Do nothing if LACP has been turned off or if the
614 614 * periodic state machine is not enabled.
615 615 */
616 616 if ((pl->sm.periodic_state == LACP_NO_PERIODIC) ||
617 617 !pl->sm.lacp_enabled || pl->sm.begin) {
618 618 pl->NTT = B_FALSE;
619 619 return;
620 620 }
621 621
622 622 /*
623 623 * If we have sent 5 Slow packets in the last second, avoid
624 624 * sending any more here. No more than three LACPDUs may be transmitted
625 625 * in any Fast_Periodic_Time interval.
626 626 */
627 627 if (portp->lp_lacp_stats.LACPDUsTx >= 3) {
628 628 /*
629 629 * Grab the current time value and see if
630 630 * more than 1 second has passed. If so,
631 631 * reset the timestamp and clear the count.
632 632 */
633 633 now = gethrtime();
634 634 elapsed = now - pl->time;
635 635 if (elapsed > NSECS_PER_SEC) {
636 636 portp->lp_lacp_stats.LACPDUsTx = 0;
637 637 pl->time = now;
638 638 } else {
639 639 return;
640 640 }
641 641 }
642 642
643 643 len = sizeof (lacp_t) + sizeof (struct ether_header);
644 644 mp = allocb(len, BPRI_MED);
645 645 if (mp == NULL)
646 646 return;
647 647
648 648 mp->b_wptr = mp->b_rptr + len;
649 649 bzero(mp->b_rptr, len);
650 650
651 651 fill_lacp_ether(portp, (struct ether_header *)mp->b_rptr);
652 652 fill_lacp_pdu(portp,
653 653 (lacp_t *)(mp->b_rptr + sizeof (struct ether_header)));
654 654
655 655 /* Send the packet over the first TX ring */
656 656 mp = mac_hwring_send_priv(portp->lp_mch, portp->lp_tx_rings[0], mp);
657 657 if (mp != NULL)
658 658 freemsg(mp);
659 659
660 660 pl->NTT = B_FALSE;
661 661 portp->lp_lacp_stats.LACPDUsTx++;
662 662 }
663 663
664 664 /*
665 665 * Initialize the ethernet header of a LACP packet sent from the specified
666 666 * port.
667 667 */
668 668 static void
669 669 fill_lacp_ether(aggr_port_t *port, struct ether_header *ether)
670 670 {
671 671 bcopy(port->lp_addr, (uint8_t *)&(ether->ether_shost), ETHERADDRL);
672 672 bcopy(&slow_multicast_addr, (uint8_t *)&(ether->ether_dhost),
673 673 ETHERADDRL);
674 674 ether->ether_type = htons(ETHERTYPE_SLOW);
675 675 }
676 676
677 677 static void
678 678 fill_lacp_pdu(aggr_port_t *portp, lacp_t *lacp)
679 679 {
680 680 aggr_lacp_port_t *pl = &portp->lp_lacp;
681 681 aggr_grp_t *aggrp = portp->lp_grp;
682 682 mac_perim_handle_t pmph;
683 683
684 684 ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
685 685 mac_perim_enter_by_mh(portp->lp_mh, &pmph);
686 686
687 687 lacp->subtype = LACP_SUBTYPE;
688 688 lacp->version = LACP_VERSION;
689 689
690 690 /*
691 691 * Actor Information
692 692 */
693 693 lacp->actor_info.tlv_type = ACTOR_TLV;
694 694 lacp->actor_info.information_len = sizeof (link_info_t);
695 695 lacp->actor_info.system_priority =
696 696 htons(aggrp->aggr.ActorSystemPriority);
697 697 bcopy(aggrp->lg_addr, (uchar_t *)&lacp->actor_info.system_id,
698 698 ETHERADDRL);
699 699 lacp->actor_info.key = htons(pl->ActorOperPortKey);
700 700 lacp->actor_info.port_priority = htons(pl->ActorPortPriority);
701 701 lacp->actor_info.port = htons(pl->ActorPortNumber);
702 702 lacp->actor_info.state.state = pl->ActorOperPortState.state;
703 703
704 704 /*
705 705 * Partner Information
706 706 */
707 707 lacp->partner_info.tlv_type = PARTNER_TLV;
708 708 lacp->partner_info.information_len = sizeof (link_info_t);
709 709 lacp->partner_info.system_priority =
710 710 htons(pl->PartnerOperSysPriority);
711 711 lacp->partner_info.system_id = pl->PartnerOperSystem;
712 712 lacp->partner_info.key = htons(pl->PartnerOperKey);
713 713 lacp->partner_info.port_priority =
714 714 htons(pl->PartnerOperPortPriority);
715 715 lacp->partner_info.port = htons(pl->PartnerOperPortNum);
716 716 lacp->partner_info.state.state = pl->PartnerOperPortState.state;
717 717
718 718 /* Collector Information */
719 719 lacp->tlv_collector = COLLECTOR_TLV;
720 720 lacp->collector_len = 0x10;
721 721 lacp->collector_max_delay = htons(aggrp->aggr.CollectorMaxDelay);
722 722
723 723 /* Termination Information */
724 724 lacp->tlv_terminator = TERMINATOR_TLV;
725 725 lacp->terminator_len = 0x0;
726 726
727 727 mac_perim_exit(pmph);
728 728 }
729 729
730 730 /*
731 731 * lacp_mux_sm - LACP mux state machine
732 732 * This state machine is invoked from:
733 733 * - startup upon aggregation
734 734 * - from the Selection logic
735 735 * - when the wait_while_timer pops
736 736 * - when the aggregation MAC address is changed
737 737 * - when receiving DL_NOTE_LINK_UP/DOWN
738 738 * - when receiving DL_NOTE_AGGR_AVAIL/UNAVAIL
739 739 * - when LACP mode is changed.
740 740 * - when a DL_NOTE_SPEED is received
741 741 */
742 742 static void
743 743 lacp_mux_sm(aggr_port_t *portp)
744 744 {
745 745 aggr_grp_t *aggrp = portp->lp_grp;
746 746 boolean_t NTT_updated = B_FALSE;
747 747 aggr_lacp_port_t *pl = &portp->lp_lacp;
748 748 lacp_mux_state_t oldstate = pl->sm.mux_state;
749 749
750 750 ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
751 751
752 752 /* LACP_OFF state not in specification so check here. */
753 753 if (!pl->sm.lacp_on) {
754 754 pl->sm.mux_state = LACP_DETACHED;
755 755 pl->ActorOperPortState.bit.sync = B_FALSE;
756 756
757 757 if (pl->ActorOperPortState.bit.collecting ||
758 758 pl->ActorOperPortState.bit.distributing) {
759 759 AGGR_LACP_DBG(("trunk link: (%d): "
760 760 "Collector_Distributor Disabled.\n",
761 761 portp->lp_linkid));
762 762 }
763 763
764 764 pl->ActorOperPortState.bit.collecting =
765 765 pl->ActorOperPortState.bit.distributing = B_FALSE;
766 766 return;
767 767 }
768 768
769 769 if (pl->sm.begin || !pl->sm.lacp_enabled)
770 770 pl->sm.mux_state = LACP_DETACHED;
771 771
772 772 again:
773 773 /* determine next state, or return if state unchanged */
774 774 switch (pl->sm.mux_state) {
775 775 case LACP_DETACHED:
776 776 if (pl->sm.begin) {
777 777 break;
778 778 }
779 779
780 780 if ((pl->sm.selected == AGGR_SELECTED) ||
781 781 (pl->sm.selected == AGGR_STANDBY)) {
782 782 pl->sm.mux_state = LACP_WAITING;
783 783 break;
784 784 }
785 785 return;
786 786
787 787 case LACP_WAITING:
788 788 if (pl->sm.selected == AGGR_UNSELECTED) {
789 789 pl->sm.mux_state = LACP_DETACHED;
790 790 break;
791 791 }
792 792
793 793 if ((pl->sm.selected == AGGR_SELECTED) && aggrp->aggr.ready) {
794 794 pl->sm.mux_state = LACP_ATTACHED;
795 795 break;
796 796 }
797 797 return;
798 798
799 799 case LACP_ATTACHED:
800 800 if ((pl->sm.selected == AGGR_UNSELECTED) ||
801 801 (pl->sm.selected == AGGR_STANDBY)) {
802 802 pl->sm.mux_state = LACP_DETACHED;
803 803 break;
804 804 }
805 805
806 806 if ((pl->sm.selected == AGGR_SELECTED) &&
807 807 pl->PartnerOperPortState.bit.sync) {
808 808 pl->sm.mux_state = LACP_COLLECTING_DISTRIBUTING;
809 809 break;
810 810 }
811 811 return;
812 812
813 813 case LACP_COLLECTING_DISTRIBUTING:
814 814 if ((pl->sm.selected == AGGR_UNSELECTED) ||
815 815 (pl->sm.selected == AGGR_STANDBY) ||
816 816 !pl->PartnerOperPortState.bit.sync) {
817 817 pl->sm.mux_state = LACP_ATTACHED;
818 818 break;
819 819 }
820 820 return;
821 821 }
822 822
823 823 AGGR_LACP_DBG(("lacp_mux_sm(%d):%s--->%s\n",
824 824 portp->lp_linkid, lacp_mux_str[oldstate],
825 825 lacp_mux_str[pl->sm.mux_state]));
826 826
827 827 /* perform actions on entering a new state */
828 828 switch (pl->sm.mux_state) {
829 829 case LACP_DETACHED:
830 830 if (pl->ActorOperPortState.bit.collecting ||
831 831 pl->ActorOperPortState.bit.distributing) {
832 832 AGGR_LACP_DBG(("trunk link: (%d): "
833 833 "Collector_Distributor Disabled.\n",
834 834 portp->lp_linkid));
835 835 }
836 836
837 837 pl->ActorOperPortState.bit.sync =
838 838 pl->ActorOperPortState.bit.collecting = B_FALSE;
839 839
840 840 /* Turn OFF Collector_Distributor */
841 841 aggr_set_coll_dist(portp, B_FALSE);
842 842
843 843 pl->ActorOperPortState.bit.distributing = B_FALSE;
844 844 NTT_updated = B_TRUE;
845 845 break;
846 846
847 847 case LACP_WAITING:
848 848 start_wait_while_timer(portp);
849 849 break;
850 850
851 851 case LACP_ATTACHED:
852 852 if (pl->ActorOperPortState.bit.collecting ||
853 853 pl->ActorOperPortState.bit.distributing) {
854 854 AGGR_LACP_DBG(("trunk link: (%d): "
855 855 "Collector_Distributor Disabled.\n",
856 856 portp->lp_linkid));
857 857 }
858 858
859 859 pl->ActorOperPortState.bit.sync = B_TRUE;
860 860 pl->ActorOperPortState.bit.collecting = B_FALSE;
861 861
862 862 /* Turn OFF Collector_Distributor */
863 863 aggr_set_coll_dist(portp, B_FALSE);
864 864
865 865 pl->ActorOperPortState.bit.distributing = B_FALSE;
866 866 NTT_updated = B_TRUE;
867 867 if (pl->PartnerOperPortState.bit.sync) {
868 868 /*
869 869 * We had already received an updated sync from
870 870 * the partner. Attempt to transition to
871 871 * collecting/distributing now.
872 872 */
873 873 goto again;
874 874 }
875 875 break;
876 876
877 877 case LACP_COLLECTING_DISTRIBUTING:
878 878 if (!pl->ActorOperPortState.bit.collecting &&
879 879 !pl->ActorOperPortState.bit.distributing) {
880 880 AGGR_LACP_DBG(("trunk link: (%d): "
881 881 "Collector_Distributor Enabled.\n",
882 882 portp->lp_linkid));
883 883 }
884 884 pl->ActorOperPortState.bit.distributing = B_TRUE;
885 885
886 886 /* Turn Collector_Distributor back ON */
887 887 aggr_set_coll_dist(portp, B_TRUE);
888 888
889 889 pl->ActorOperPortState.bit.collecting = B_TRUE;
890 890 NTT_updated = B_TRUE;
891 891 break;
892 892 }
893 893
894 894 /*
895 895 * If we updated the state of the NTT variable, then
896 896 * initiate a LACPDU transmission.
897 897 */
898 898 if (NTT_updated) {
899 899 pl->NTT = B_TRUE;
900 900 lacp_xmit_sm(portp);
901 901 }
902 902 } /* lacp_mux_sm */
903 903
904 904
905 905 static int
906 906 receive_marker_pdu(aggr_port_t *portp, mblk_t *mp)
907 907 {
908 908 marker_pdu_t *markerp = (marker_pdu_t *)mp->b_rptr;
909 909
910 910 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
911 911
912 912 AGGR_LACP_DBG(("trunk link: (%d): MARKER PDU received:\n",
913 913 portp->lp_linkid));
914 914
915 915 /* LACP_OFF state not in specification so check here. */
916 916 if (!portp->lp_lacp.sm.lacp_on)
917 917 return (-1);
918 918
919 919 if (MBLKL(mp) < sizeof (marker_pdu_t))
920 920 return (-1);
921 921
922 922 if (markerp->version != MARKER_VERSION) {
923 923 AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: "
924 924 "version = %d does not match s/w version %d\n",
925 925 portp->lp_linkid, markerp->version, MARKER_VERSION));
926 926 return (-1);
927 927 }
928 928
929 929 if (markerp->tlv_marker == MARKER_RESPONSE_TLV) {
930 930 /* We do not yet send out MARKER info PDUs */
931 931 AGGR_LACP_DBG(("trunk link (%d): MARKER RESPONSE PDU: "
932 932 " MARKER TLV = %d - We don't send out info type!\n",
933 933 portp->lp_linkid, markerp->tlv_marker));
934 934 return (-1);
935 935 }
936 936
937 937 if (markerp->tlv_marker != MARKER_INFO_TLV) {
938 938 AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: "
939 939 " MARKER TLV = %d \n", portp->lp_linkid,
940 940 markerp->tlv_marker));
941 941 return (-1);
942 942 }
943 943
944 944 if (markerp->marker_len != MARKER_INFO_RESPONSE_LENGTH) {
945 945 AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: "
946 946 " MARKER length = %d \n", portp->lp_linkid,
947 947 markerp->marker_len));
948 948 return (-1);
949 949 }
950 950
951 951 if (markerp->requestor_port != portp->lp_lacp.PartnerOperPortNum) {
952 952 AGGR_LACP_DBG(("trunk link (%d): MARKER PDU: "
953 953 " MARKER Port %d not equal to Partner port %d\n",
954 954 portp->lp_linkid, markerp->requestor_port,
955 955 portp->lp_lacp.PartnerOperPortNum));
956 956 return (-1);
957 957 }
958 958
959 959 if (ether_cmp(&markerp->system_id,
960 960 &portp->lp_lacp.PartnerOperSystem) != 0) {
961 961 AGGR_LACP_DBG(("trunk link (%d): MARKER PDU: "
962 962 " MARKER MAC not equal to Partner MAC\n",
963 963 portp->lp_linkid));
964 964 return (-1);
965 965 }
966 966
967 967 /*
968 968 * Turn into Marker Response PDU
969 969 * and return mblk to sending system
970 970 */
971 971 markerp->tlv_marker = MARKER_RESPONSE_TLV;
972 972
973 973 /* reuse the space that was used by received ethernet header */
974 974 ASSERT(MBLKHEAD(mp) >= sizeof (struct ether_header));
975 975 mp->b_rptr -= sizeof (struct ether_header);
976 976 fill_lacp_ether(portp, (struct ether_header *)mp->b_rptr);
977 977 return (0);
978 978 }
979 979
980 980 /*
981 981 * Update the LACP mode (off, active, or passive) of the specified group.
982 982 */
983 983 void
984 984 aggr_lacp_update_mode(aggr_grp_t *grp, aggr_lacp_mode_t mode)
985 985 {
986 986 aggr_lacp_mode_t old_mode = grp->lg_lacp_mode;
987 987 aggr_port_t *port;
988 988
989 989 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
990 990 ASSERT(!grp->lg_closing);
991 991
992 992 if (mode == old_mode)
993 993 return;
994 994
995 995 grp->lg_lacp_mode = mode;
996 996
997 997 for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
998 998 port->lp_lacp.ActorAdminPortState.bit.activity =
999 999 port->lp_lacp.ActorOperPortState.bit.activity =
1000 1000 (mode == AGGR_LACP_ACTIVE);
1001 1001
1002 1002 if (old_mode == AGGR_LACP_OFF) {
1003 1003 /* OFF -> {PASSIVE,ACTIVE} */
1004 1004 /* turn OFF Collector_Distributor */
1005 1005 aggr_set_coll_dist(port, B_FALSE);
1006 1006 lacp_on(port);
1007 1007 } else if (mode == AGGR_LACP_OFF) {
1008 1008 /* {PASSIVE,ACTIVE} -> OFF */
1009 1009 lacp_off(port);
1010 1010 /* Turn ON Collector_Distributor */
1011 1011 aggr_set_coll_dist(port, B_TRUE);
1012 1012 } else {
1013 1013 /* PASSIVE->ACTIVE or ACTIVE->PASSIVE */
1014 1014 port->lp_lacp.sm.begin = B_TRUE;
1015 1015 lacp_mux_sm(port);
1016 1016 lacp_periodic_sm(port);
1017 1017
1018 1018 /* kick off state machines */
1019 1019 lacp_receive_sm(port, NULL);
1020 1020 lacp_mux_sm(port);
1021 1021 }
1022 1022 }
1023 1023 }
1024 1024
1025 1025
1026 1026 /*
1027 1027 * Update the LACP timer (short or long) of the specified group.
1028 1028 */
1029 1029 void
1030 1030 aggr_lacp_update_timer(aggr_grp_t *grp, aggr_lacp_timer_t timer)
1031 1031 {
1032 1032 aggr_port_t *port;
1033 1033
1034 1034 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
1035 1035
1036 1036 if (timer == grp->aggr.PeriodicTimer)
1037 1037 return;
1038 1038
1039 1039 grp->aggr.PeriodicTimer = timer;
1040 1040
1041 1041 for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
1042 1042 port->lp_lacp.ActorAdminPortState.bit.timeout =
1043 1043 port->lp_lacp.ActorOperPortState.bit.timeout =
1044 1044 (timer == AGGR_LACP_TIMER_SHORT);
1045 1045 }
1046 1046 }
1047 1047
1048 1048 void
1049 1049 aggr_port_lacp_set_mode(aggr_grp_t *grp, aggr_port_t *port)
1050 1050 {
1051 1051 aggr_lacp_mode_t mode;
1052 1052 aggr_lacp_timer_t timer;
1053 1053
1054 1054 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
1055 1055
1056 1056 mode = grp->lg_lacp_mode;
1057 1057 timer = grp->aggr.PeriodicTimer;
1058 1058
1059 1059 port->lp_lacp.ActorAdminPortState.bit.activity =
1060 1060 port->lp_lacp.ActorOperPortState.bit.activity =
1061 1061 (mode == AGGR_LACP_ACTIVE);
1062 1062
1063 1063 port->lp_lacp.ActorAdminPortState.bit.timeout =
1064 1064 port->lp_lacp.ActorOperPortState.bit.timeout =
1065 1065 (timer == AGGR_LACP_TIMER_SHORT);
1066 1066
1067 1067 if (mode == AGGR_LACP_OFF) {
1068 1068 /* Turn ON Collector_Distributor */
1069 1069 aggr_set_coll_dist(port, B_TRUE);
1070 1070 } else { /* LACP_ACTIVE/PASSIVE */
1071 1071 lacp_on(port);
1072 1072 }
1073 1073 }
1074 1074
1075 1075 /*
1076 1076 * Sets the initial LACP mode (off, active, passive) and LACP timer
1077 1077 * (short, long) of the specified group.
1078 1078 */
1079 1079 void
1080 1080 aggr_lacp_set_mode(aggr_grp_t *grp, aggr_lacp_mode_t mode,
1081 1081 aggr_lacp_timer_t timer)
1082 1082 {
1083 1083 aggr_port_t *port;
1084 1084
1085 1085 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
1086 1086
1087 1087 grp->lg_lacp_mode = mode;
1088 1088 grp->aggr.PeriodicTimer = timer;
1089 1089
1090 1090 for (port = grp->lg_ports; port != NULL; port = port->lp_next)
1091 1091 aggr_port_lacp_set_mode(grp, port);
1092 1092 }
1093 1093
1094 1094 /*
1095 1095 * Verify that the Partner MAC and Key recorded by the specified
1096 1096 * port are not found in other ports that are not part of our
1097 1097 * aggregation. Returns B_TRUE if such a port is found, B_FALSE
1098 1098 * otherwise.
1099 1099 */
1100 1100 static boolean_t
1101 1101 lacp_misconfig_check(aggr_port_t *portp)
1102 1102 {
1103 1103 aggr_grp_t *grp = portp->lp_grp;
1104 1104 lacp_sel_ports_t *cport;
1105 1105
1106 1106 mutex_enter(&lacp_sel_lock);
1107 1107
1108 1108 for (cport = sel_ports; cport != NULL; cport = cport->sp_next) {
1109 1109
1110 1110 /* skip entries of the group of the port being checked */
1111 1111 if (cport->sp_grp_linkid == grp->lg_linkid)
1112 1112 continue;
1113 1113
1114 1114 if ((ether_cmp(&cport->sp_partner_system,
1115 1115 &grp->aggr.PartnerSystem) == 0) &&
1116 1116 (cport->sp_partner_key == grp->aggr.PartnerOperAggrKey)) {
1117 1117 char mac_str[ETHERADDRL*3];
1118 1118 struct ether_addr *mac = &cport->sp_partner_system;
1119 1119
1120 1120 /*
1121 1121 * The Partner port information is already in use
1122 1122 * by ports in another aggregation so disable this
1123 1123 * port.
1124 1124 */
1125 1125
1126 1126 (void) snprintf(mac_str, sizeof (mac_str),
1127 1127 "%x:%x:%x:%x:%x:%x",
1128 1128 mac->ether_addr_octet[0], mac->ether_addr_octet[1],
1129 1129 mac->ether_addr_octet[2], mac->ether_addr_octet[3],
1130 1130 mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
1131 1131
1132 1132 portp->lp_lacp.sm.selected = AGGR_UNSELECTED;
1133 1133
1134 1134 cmn_err(CE_NOTE, "aggr %d port %d: Port Partner "
1135 1135 "MAC %s and key %d in use on aggregation %d "
1136 1136 "port %d\n", grp->lg_linkid, portp->lp_linkid,
1137 1137 mac_str, portp->lp_lacp.PartnerOperKey,
1138 1138 cport->sp_grp_linkid, cport->sp_linkid);
1139 1139 break;
1140 1140 }
1141 1141 }
1142 1142
1143 1143 mutex_exit(&lacp_sel_lock);
1144 1144 return (cport != NULL);
1145 1145 }
1146 1146
1147 1147 /*
1148 1148 * Remove the specified port from the list of selected ports.
1149 1149 */
1150 1150 static void
1151 1151 lacp_sel_ports_del(aggr_port_t *portp)
1152 1152 {
1153 1153 lacp_sel_ports_t *cport, **prev = NULL;
1154 1154
1155 1155 mutex_enter(&lacp_sel_lock);
1156 1156
1157 1157 prev = &sel_ports;
1158 1158 for (cport = sel_ports; cport != NULL; prev = &cport->sp_next,
1159 1159 cport = cport->sp_next) {
1160 1160 if (portp->lp_linkid == cport->sp_linkid)
1161 1161 break;
1162 1162 }
1163 1163
1164 1164 if (cport == NULL) {
1165 1165 mutex_exit(&lacp_sel_lock);
1166 1166 return;
1167 1167 }
1168 1168
1169 1169 *prev = cport->sp_next;
1170 1170 kmem_free(cport, sizeof (*cport));
1171 1171
1172 1172 mutex_exit(&lacp_sel_lock);
1173 1173 }
1174 1174
1175 1175 /*
1176 1176 * Add the specified port to the list of selected ports. Returns B_FALSE
1177 1177 * if the operation could not be performed due to an memory allocation
1178 1178 * error.
1179 1179 */
1180 1180 static boolean_t
1181 1181 lacp_sel_ports_add(aggr_port_t *portp)
1182 1182 {
1183 1183 lacp_sel_ports_t *new_port;
1184 1184 lacp_sel_ports_t *cport, **last;
1185 1185
1186 1186 mutex_enter(&lacp_sel_lock);
1187 1187
1188 1188 /* check if port is already in the list */
1189 1189 last = &sel_ports;
1190 1190 for (cport = sel_ports; cport != NULL;
1191 1191 last = &cport->sp_next, cport = cport->sp_next) {
1192 1192 if (portp->lp_linkid == cport->sp_linkid) {
1193 1193 ASSERT(cport->sp_partner_key ==
1194 1194 portp->lp_lacp.PartnerOperKey);
1195 1195 ASSERT(ether_cmp(&cport->sp_partner_system,
1196 1196 &portp->lp_lacp.PartnerOperSystem) == 0);
1197 1197
1198 1198 mutex_exit(&lacp_sel_lock);
1199 1199 return (B_TRUE);
1200 1200 }
1201 1201 }
1202 1202
1203 1203 /* create and initialize new entry */
1204 1204 new_port = kmem_zalloc(sizeof (lacp_sel_ports_t), KM_NOSLEEP);
1205 1205 if (new_port == NULL) {
1206 1206 mutex_exit(&lacp_sel_lock);
1207 1207 return (B_FALSE);
1208 1208 }
1209 1209
1210 1210 new_port->sp_grp_linkid = portp->lp_grp->lg_linkid;
1211 1211 bcopy(&portp->lp_lacp.PartnerOperSystem,
1212 1212 &new_port->sp_partner_system, sizeof (new_port->sp_partner_system));
1213 1213 new_port->sp_partner_key = portp->lp_lacp.PartnerOperKey;
1214 1214 new_port->sp_linkid = portp->lp_linkid;
1215 1215
1216 1216 *last = new_port;
1217 1217
1218 1218 mutex_exit(&lacp_sel_lock);
1219 1219 return (B_TRUE);
1220 1220 }
1221 1221
1222 1222 /*
1223 1223 * lacp_selection_logic - LACP selection logic
1224 1224 * Sets the selected variable on a per port basis
1225 1225 * and sets Ready when all waiting ports are ready
1226 1226 * to go online.
1227 1227 *
1228 1228 * parameters:
1229 1229 * - portp - instance this applies to.
1230 1230 *
1231 1231 * invoked:
1232 1232 * - when initialization is needed
1233 1233 * - when UNSELECTED is set from the lacp_receive_sm() in LACP_CURRENT state
1234 1234 * - When the lacp_receive_sm goes to the LACP_DEFAULTED state
1235 1235 * - every time the wait_while_timer pops
1236 1236 * - everytime we turn LACP on/off
1237 1237 */
1238 1238 static void
1239 1239 lacp_selection_logic(aggr_port_t *portp)
1240 1240 {
1241 1241 aggr_port_t *tpp;
1242 1242 aggr_grp_t *aggrp = portp->lp_grp;
1243 1243 int ports_waiting;
1244 1244 boolean_t reset_mac = B_FALSE;
1245 1245 aggr_lacp_port_t *pl = &portp->lp_lacp;
1246 1246
1247 1247 ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
1248 1248
1249 1249 /* LACP_OFF state not in specification so check here. */
1250 1250 if (!pl->sm.lacp_on) {
1251 1251 lacp_port_unselect(portp);
1252 1252 aggrp->aggr.ready = B_FALSE;
1253 1253 lacp_mux_sm(portp);
1254 1254 return;
1255 1255 }
1256 1256
1257 1257 if (pl->sm.begin || !pl->sm.lacp_enabled ||
1258 1258 (portp->lp_state != AGGR_PORT_STATE_ATTACHED)) {
1259 1259
1260 1260 AGGR_LACP_DBG(("lacp_selection_logic:(%d): "
1261 1261 "selected %d-->%d (begin=%d, lacp_enabled = %d, "
1262 1262 "lp_state=%d)\n", portp->lp_linkid, pl->sm.selected,
1263 1263 AGGR_UNSELECTED, pl->sm.begin, pl->sm.lacp_enabled,
1264 1264 portp->lp_state));
1265 1265
1266 1266 lacp_port_unselect(portp);
1267 1267 aggrp->aggr.ready = B_FALSE;
1268 1268 lacp_mux_sm(portp);
1269 1269 return;
1270 1270 }
1271 1271
1272 1272 /*
1273 1273 * If LACP is not enabled then selected is never set.
1274 1274 */
1275 1275 if (!pl->sm.lacp_enabled) {
1276 1276 AGGR_LACP_DBG(("lacp_selection_logic:(%d): selected %d-->%d\n",
1277 1277 portp->lp_linkid, pl->sm.selected, AGGR_UNSELECTED));
1278 1278
1279 1279 lacp_port_unselect(portp);
1280 1280 lacp_mux_sm(portp);
1281 1281 return;
1282 1282 }
1283 1283
1284 1284 /*
1285 1285 * Check if the Partner MAC or Key are zero. If so, we have
1286 1286 * not received any LACP info or it has expired and the
1287 1287 * receive machine is in the LACP_DEFAULTED state.
1288 1288 */
1289 1289 if (ether_cmp(&pl->PartnerOperSystem, ðerzeroaddr) == 0 ||
1290 1290 (pl->PartnerOperKey == 0)) {
1291 1291
1292 1292 for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) {
1293 1293 if (ether_cmp(&tpp->lp_lacp.PartnerOperSystem,
1294 1294 ðerzeroaddr) != 0 &&
1295 1295 (tpp->lp_lacp.PartnerOperKey != 0))
1296 1296 break;
1297 1297 }
1298 1298
1299 1299 /*
1300 1300 * If all ports have no key or aggregation address,
1301 1301 * then clear the negotiated Partner MAC and key.
1302 1302 */
1303 1303 if (tpp == NULL) {
1304 1304 /* Clear the aggregation Partner MAC and key */
1305 1305 aggrp->aggr.PartnerSystem = etherzeroaddr;
1306 1306 aggrp->aggr.PartnerOperAggrKey = 0;
1307 1307 }
1308 1308
1309 1309 return;
1310 1310 }
1311 1311
1312 1312 /*
1313 1313 * Insure that at least one port in the aggregation
1314 1314 * matches the Partner aggregation MAC and key. If not,
1315 1315 * then clear the aggregation MAC and key. Later we will
1316 1316 * set the Partner aggregation MAC and key to that of the
1317 1317 * current port's Partner MAC and key.
1318 1318 */
1319 1319 if (ether_cmp(&pl->PartnerOperSystem,
1320 1320 &aggrp->aggr.PartnerSystem) != 0 ||
1321 1321 (pl->PartnerOperKey != aggrp->aggr.PartnerOperAggrKey)) {
1322 1322
1323 1323 for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) {
1324 1324 if (ether_cmp(&tpp->lp_lacp.PartnerOperSystem,
1325 1325 &aggrp->aggr.PartnerSystem) == 0 &&
1326 1326 (tpp->lp_lacp.PartnerOperKey ==
1327 1327 aggrp->aggr.PartnerOperAggrKey)) {
1328 1328 /* Set aggregation Partner MAC and key */
1329 1329 aggrp->aggr.PartnerSystem =
1330 1330 pl->PartnerOperSystem;
1331 1331 aggrp->aggr.PartnerOperAggrKey =
1332 1332 pl->PartnerOperKey;
1333 1333 break;
1334 1334 }
1335 1335 }
1336 1336
1337 1337 if (tpp == NULL) {
1338 1338 /* Clear the aggregation Partner MAC and key */
1339 1339 aggrp->aggr.PartnerSystem = etherzeroaddr;
1340 1340 aggrp->aggr.PartnerOperAggrKey = 0;
1341 1341 reset_mac = B_TRUE;
1342 1342 }
1343 1343 }
1344 1344
1345 1345 /*
1346 1346 * If our Actor MAC is found in the Partner MAC
1347 1347 * on this port then we have a loopback misconfiguration.
1348 1348 */
1349 1349 if (ether_cmp(&pl->PartnerOperSystem,
1350 1350 (struct ether_addr *)&aggrp->lg_addr) == 0) {
1351 1351 cmn_err(CE_NOTE, "trunk link: (%d): Loopback condition.\n",
1352 1352 portp->lp_linkid);
1353 1353
1354 1354 lacp_port_unselect(portp);
1355 1355 lacp_mux_sm(portp);
1356 1356 return;
1357 1357 }
1358 1358
1359 1359 /*
1360 1360 * If our Partner MAC and Key are found on any other
1361 1361 * ports that are not in our aggregation, we have
1362 1362 * a misconfiguration.
1363 1363 */
1364 1364 if (lacp_misconfig_check(portp)) {
1365 1365 lacp_mux_sm(portp);
1366 1366 return;
1367 1367 }
1368 1368
1369 1369 /*
1370 1370 * If the Aggregation Partner MAC and Key have not been
1371 1371 * set, then this is either the first port or the aggregation
1372 1372 * MAC and key have been reset. In either case we must set
1373 1373 * the values of the Partner MAC and key.
1374 1374 */
1375 1375 if (ether_cmp(&aggrp->aggr.PartnerSystem, ðerzeroaddr) == 0 &&
1376 1376 (aggrp->aggr.PartnerOperAggrKey == 0)) {
1377 1377 /* Set aggregation Partner MAC and key */
1378 1378 aggrp->aggr.PartnerSystem = pl->PartnerOperSystem;
1379 1379 aggrp->aggr.PartnerOperAggrKey = pl->PartnerOperKey;
1380 1380
1381 1381 /*
1382 1382 * If we reset Partner aggregation MAC, then restart
1383 1383 * selection_logic on ports that match new MAC address.
1384 1384 */
1385 1385 if (reset_mac) {
1386 1386 for (tpp = aggrp->lg_ports; tpp; tpp =
1387 1387 tpp->lp_next) {
1388 1388 if (tpp == portp)
1389 1389 continue;
1390 1390 if (ether_cmp(&tpp->lp_lacp.PartnerOperSystem,
1391 1391 &aggrp->aggr.PartnerSystem) == 0 &&
1392 1392 (tpp->lp_lacp.PartnerOperKey ==
1393 1393 aggrp->aggr.PartnerOperAggrKey))
1394 1394 lacp_selection_logic(tpp);
1395 1395 }
1396 1396 }
1397 1397 } else if (ether_cmp(&pl->PartnerOperSystem,
1398 1398 &aggrp->aggr.PartnerSystem) != 0 ||
1399 1399 (pl->PartnerOperKey != aggrp->aggr.PartnerOperAggrKey)) {
1400 1400 /*
1401 1401 * The Partner port information does not match
1402 1402 * that of the other ports in the aggregation
1403 1403 * so disable this port.
1404 1404 */
1405 1405 lacp_port_unselect(portp);
1406 1406
1407 1407 cmn_err(CE_NOTE, "trunk link: (%d): Port Partner MAC "
1408 1408 "or key (%d) incompatible with Aggregation Partner "
1409 1409 "MAC or key (%d)\n", portp->lp_linkid, pl->PartnerOperKey,
1410 1410 aggrp->aggr.PartnerOperAggrKey);
1411 1411
1412 1412 lacp_mux_sm(portp);
1413 1413 return;
1414 1414 }
1415 1415
1416 1416 /* If we get to here, automatically set selected */
1417 1417 if (pl->sm.selected != AGGR_SELECTED) {
1418 1418 AGGR_LACP_DBG(("lacp_selection_logic:(%d): "
1419 1419 "selected %d-->%d\n", portp->lp_linkid,
1420 1420 pl->sm.selected, AGGR_SELECTED));
1421 1421 if (!lacp_port_select(portp))
1422 1422 return;
1423 1423 lacp_mux_sm(portp);
1424 1424 }
1425 1425
1426 1426 /*
1427 1427 * From this point onward we have selected the port
1428 1428 * and are simply checking if the Ready flag should
1429 1429 * be set.
1430 1430 */
1431 1431
1432 1432 /*
1433 1433 * If at least two ports are waiting to aggregate
1434 1434 * and ready_n is set on all ports waiting to aggregate
1435 1435 * then set READY for the aggregation.
1436 1436 */
1437 1437
1438 1438 ports_waiting = 0;
1439 1439
1440 1440 if (!aggrp->aggr.ready) {
1441 1441 /*
1442 1442 * If all ports in the aggregation have received compatible
1443 1443 * partner information and they match up correctly with the
1444 1444 * switch, there is no need to wait for all the
1445 1445 * wait_while_timers to pop.
1446 1446 */
1447 1447 for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) {
1448 1448 if (((tpp->lp_lacp.sm.mux_state == LACP_WAITING) ||
1449 1449 tpp->lp_lacp.sm.begin) &&
1450 1450 !tpp->lp_lacp.PartnerOperPortState.bit.sync) {
1451 1451 /* Add up ports uninitialized or waiting */
1452 1452 ports_waiting++;
1453 1453 if (!tpp->lp_lacp.sm.ready_n) {
1454 1454 DTRACE_PROBE1(port___not__ready,
1455 1455 aggr_port_t *, tpp);
1456 1456 return;
1457 1457 }
1458 1458 }
1459 1459 }
1460 1460 }
1461 1461
1462 1462 if (aggrp->aggr.ready) {
1463 1463 AGGR_LACP_DBG(("lacp_selection_logic:(%d): "
1464 1464 "aggr.ready already set\n", portp->lp_linkid));
1465 1465 lacp_mux_sm(portp);
1466 1466 } else {
1467 1467 AGGR_LACP_DBG(("lacp_selection_logic:(%d): Ready %d-->%d\n",
1468 1468 portp->lp_linkid, aggrp->aggr.ready, B_TRUE));
1469 1469 aggrp->aggr.ready = B_TRUE;
1470 1470
1471 1471 for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next)
1472 1472 lacp_mux_sm(tpp);
1473 1473 }
1474 1474
1475 1475 }
1476 1476
1477 1477 /*
1478 1478 * wait_while_timer_pop - When the timer pops, we arrive here to
1479 1479 * set ready_n and trigger the selection logic.
1480 1480 */
1481 1481 static void
1482 1482 wait_while_timer_pop(void *data)
1483 1483 {
1484 1484 aggr_port_t *portp = data;
1485 1485 aggr_lacp_port_t *pl = &portp->lp_lacp;
1486 1486
1487 1487 mutex_enter(&pl->lacp_timer_lock);
1488 1488 pl->lacp_timer_bits |= LACP_WAIT_WHILE_TIMEOUT;
1489 1489 cv_broadcast(&pl->lacp_timer_cv);
1490 1490 mutex_exit(&pl->lacp_timer_lock);
1491 1491 }
1492 1492
1493 1493 /*
1494 1494 * wait_while_timer_pop_handler - When the timer pops, we arrive here to
1495 1495 * set ready_n and trigger the selection logic.
1496 1496 */
1497 1497 static void
1498 1498 wait_while_timer_pop_handler(aggr_port_t *portp)
1499 1499 {
1500 1500 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1501 1501
1502 1502 AGGR_LACP_DBG(("trunk link:(%d): wait_while_timer pop \n",
1503 1503 portp->lp_linkid));
1504 1504 portp->lp_lacp.sm.ready_n = B_TRUE;
1505 1505
1506 1506 lacp_selection_logic(portp);
1507 1507 }
1508 1508
1509 1509 static void
1510 1510 start_wait_while_timer(aggr_port_t *portp)
1511 1511 {
1512 1512 aggr_lacp_port_t *pl = &portp->lp_lacp;
1513 1513
1514 1514 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1515 1515
1516 1516 mutex_enter(&pl->lacp_timer_lock);
1517 1517 if (pl->wait_while_timer.id == 0) {
1518 1518 pl->wait_while_timer.id =
1519 1519 timeout(wait_while_timer_pop, portp,
1520 1520 drv_usectohz(1000000 *
1521 1521 portp->lp_lacp.wait_while_timer.val));
1522 1522 }
1523 1523 mutex_exit(&pl->lacp_timer_lock);
1524 1524 }
1525 1525
1526 1526
1527 1527 static void
1528 1528 stop_wait_while_timer(aggr_port_t *portp)
1529 1529 {
1530 1530 aggr_lacp_port_t *pl = &portp->lp_lacp;
1531 1531 timeout_id_t id;
1532 1532
1533 1533 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1534 1534
1535 1535 mutex_enter(&pl->lacp_timer_lock);
1536 1536 if ((id = pl->wait_while_timer.id) != 0) {
1537 1537 pl->lacp_timer_bits &= ~LACP_WAIT_WHILE_TIMEOUT;
1538 1538 pl->wait_while_timer.id = 0;
1539 1539 }
1540 1540 mutex_exit(&pl->lacp_timer_lock);
1541 1541
1542 1542 if (id != 0)
1543 1543 (void) untimeout(id);
1544 1544 }
1545 1545
1546 1546 /*
1547 1547 * Invoked when a port has been attached to a group.
1548 1548 * Complete the processing that couldn't be finished from lacp_on()
1549 1549 * because the port was not started. We know that the link is full
1550 1550 * duplex and ON, otherwise it wouldn't be attached.
1551 1551 */
1552 1552 void
1553 1553 aggr_lacp_port_attached(aggr_port_t *portp)
1554 1554 {
1555 1555 aggr_grp_t *grp = portp->lp_grp;
1556 1556 aggr_lacp_port_t *pl = &portp->lp_lacp;
1557 1557
1558 1558 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
1559 1559 ASSERT(MAC_PERIM_HELD(portp->lp_mh));
1560 1560 ASSERT(portp->lp_state == AGGR_PORT_STATE_ATTACHED);
1561 1561
1562 1562 AGGR_LACP_DBG(("aggr_lacp_port_attached: port %d\n",
1563 1563 portp->lp_linkid));
1564 1564
1565 1565 portp->lp_lacp.sm.port_enabled = B_TRUE; /* link on */
1566 1566
1567 1567 if (grp->lg_lacp_mode == AGGR_LACP_OFF)
1568 1568 return;
1569 1569
1570 1570 pl->sm.lacp_enabled = B_TRUE;
1571 1571 pl->ActorOperPortState.bit.aggregation = B_TRUE;
1572 1572 pl->sm.begin = B_TRUE;
1573 1573
1574 1574 lacp_receive_sm(portp, NULL);
1575 1575 lacp_mux_sm(portp);
1576 1576
1577 1577 /* Enable Multicast Slow Protocol address */
1578 1578 aggr_lacp_mcast_on(portp);
1579 1579
1580 1580 /* periodic_sm is started up from the receive machine */
1581 1581 lacp_selection_logic(portp);
1582 1582 }
1583 1583
1584 1584 /*
1585 1585 * Invoked when a port has been detached from a group. Turn off
1586 1586 * LACP processing if it was enabled.
1587 1587 */
1588 1588 void
1589 1589 aggr_lacp_port_detached(aggr_port_t *portp)
1590 1590 {
1591 1591 aggr_grp_t *grp = portp->lp_grp;
1592 1592
1593 1593 ASSERT(MAC_PERIM_HELD(grp->lg_mh));
1594 1594 ASSERT(MAC_PERIM_HELD(portp->lp_mh));
1595 1595
1596 1596 AGGR_LACP_DBG(("aggr_lacp_port_detached: port %d\n",
1597 1597 portp->lp_linkid));
1598 1598
1599 1599 portp->lp_lacp.sm.port_enabled = B_FALSE;
1600 1600
1601 1601 if (grp->lg_lacp_mode == AGGR_LACP_OFF)
1602 1602 return;
1603 1603
1604 1604 portp->lp_lacp.sm.lacp_enabled = B_FALSE;
1605 1605 lacp_selection_logic(portp);
1606 1606 lacp_mux_sm(portp);
1607 1607 lacp_periodic_sm(portp);
1608 1608
1609 1609 /*
1610 1610 * Disable Slow Protocol Timers.
1611 1611 */
1612 1612 stop_periodic_timer(portp);
1613 1613 stop_current_while_timer(portp);
1614 1614 stop_wait_while_timer(portp);
1615 1615
1616 1616 /* Disable Multicast Slow Protocol address */
1617 1617 aggr_lacp_mcast_off(portp);
1618 1618 aggr_set_coll_dist(portp, B_FALSE);
1619 1619 }
1620 1620
1621 1621 /*
1622 1622 * Enable Slow Protocol LACP and Marker PDUs.
1623 1623 */
1624 1624 static void
1625 1625 lacp_on(aggr_port_t *portp)
1626 1626 {
1627 1627 aggr_lacp_port_t *pl = &portp->lp_lacp;
1628 1628 mac_perim_handle_t mph;
1629 1629
1630 1630 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1631 1631
1632 1632 mac_perim_enter_by_mh(portp->lp_mh, &mph);
1633 1633
1634 1634 /*
1635 1635 * Reset the state machines and Partner operational
1636 1636 * information. Careful to not reset things like
1637 1637 * our link state.
1638 1638 */
1639 1639 lacp_reset_port(portp);
1640 1640 pl->sm.lacp_on = B_TRUE;
1641 1641
1642 1642 AGGR_LACP_DBG(("lacp_on:(%d): \n", portp->lp_linkid));
1643 1643
1644 1644 if (portp->lp_state == AGGR_PORT_STATE_ATTACHED) {
1645 1645 pl->sm.port_enabled = B_TRUE;
1646 1646 pl->sm.lacp_enabled = B_TRUE;
1647 1647 pl->ActorOperPortState.bit.aggregation = B_TRUE;
1648 1648 }
1649 1649
1650 1650 lacp_receive_sm(portp, NULL);
1651 1651 lacp_mux_sm(portp);
1652 1652
1653 1653 if (portp->lp_state == AGGR_PORT_STATE_ATTACHED) {
1654 1654 /* Enable Multicast Slow Protocol address */
1655 1655 aggr_lacp_mcast_on(portp);
1656 1656
1657 1657 /* periodic_sm is started up from the receive machine */
1658 1658 lacp_selection_logic(portp);
1659 1659 }
1660 1660 done:
1661 1661 mac_perim_exit(mph);
1662 1662 } /* lacp_on */
1663 1663
1664 1664 /* Disable Slow Protocol LACP and Marker PDUs */
1665 1665 static void
1666 1666 lacp_off(aggr_port_t *portp)
1667 1667 {
1668 1668 aggr_lacp_port_t *pl = &portp->lp_lacp;
1669 1669 mac_perim_handle_t mph;
1670 1670
1671 1671 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1672 1672 mac_perim_enter_by_mh(portp->lp_mh, &mph);
1673 1673
1674 1674 pl->sm.lacp_on = B_FALSE;
1675 1675
1676 1676 AGGR_LACP_DBG(("lacp_off:(%d): \n", portp->lp_linkid));
1677 1677
1678 1678 if (portp->lp_state == AGGR_PORT_STATE_ATTACHED) {
1679 1679 /*
1680 1680 * Disable Slow Protocol Timers.
1681 1681 */
1682 1682 stop_periodic_timer(portp);
1683 1683 stop_current_while_timer(portp);
1684 1684 stop_wait_while_timer(portp);
1685 1685
1686 1686 /* Disable Multicast Slow Protocol address */
1687 1687 aggr_lacp_mcast_off(portp);
1688 1688
1689 1689 pl->sm.port_enabled = B_FALSE;
1690 1690 pl->sm.lacp_enabled = B_FALSE;
1691 1691 pl->ActorOperPortState.bit.aggregation = B_FALSE;
1692 1692 }
1693 1693
1694 1694 lacp_mux_sm(portp);
1695 1695 lacp_periodic_sm(portp);
1696 1696 lacp_selection_logic(portp);
1697 1697
1698 1698 /* Turn OFF Collector_Distributor */
1699 1699 aggr_set_coll_dist(portp, B_FALSE);
1700 1700
1701 1701 lacp_reset_port(portp);
1702 1702 mac_perim_exit(mph);
1703 1703 }
1704 1704
1705 1705
1706 1706 static boolean_t
1707 1707 valid_lacp_pdu(aggr_port_t *portp, lacp_t *lacp)
1708 1708 {
1709 1709 /*
1710 1710 * 43.4.12 - "a Receive machine shall not validate
1711 1711 * the Version Number, TLV_type, or Reserved fields in received
1712 1712 * LACPDUs."
1713 1713 * ... "a Receive machine may validate the Actor_Information_Length,
1714 1714 * Partner_Information_Length, Collector_Information_Length,
1715 1715 * or Terminator_Length fields."
1716 1716 */
1717 1717 if ((lacp->actor_info.information_len != sizeof (link_info_t)) ||
1718 1718 (lacp->partner_info.information_len != sizeof (link_info_t)) ||
1719 1719 (lacp->collector_len != LACP_COLLECTOR_INFO_LEN) ||
1720 1720 (lacp->terminator_len != LACP_TERMINATOR_INFO_LEN)) {
1721 1721 AGGR_LACP_DBG(("trunk link (%d): Malformed LACPDU: "
1722 1722 " Terminator Length = %d \n", portp->lp_linkid,
1723 1723 lacp->terminator_len));
1724 1724 return (B_FALSE);
1725 1725 }
1726 1726
1727 1727 return (B_TRUE);
1728 1728 }
1729 1729
1730 1730
1731 1731 static void
1732 1732 start_current_while_timer(aggr_port_t *portp, uint_t time)
1733 1733 {
1734 1734 aggr_lacp_port_t *pl = &portp->lp_lacp;
1735 1735
1736 1736 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1737 1737
1738 1738 mutex_enter(&pl->lacp_timer_lock);
1739 1739 if (pl->current_while_timer.id == 0) {
1740 1740 if (time > 0)
1741 1741 pl->current_while_timer.val = time;
1742 1742 else if (pl->ActorOperPortState.bit.timeout)
1743 1743 pl->current_while_timer.val = SHORT_TIMEOUT_TIME;
1744 1744 else
1745 1745 pl->current_while_timer.val = LONG_TIMEOUT_TIME;
1746 1746
1747 1747 pl->current_while_timer.id =
1748 1748 timeout(current_while_timer_pop, portp,
1749 1749 drv_usectohz((clock_t)1000000 *
1750 1750 (clock_t)portp->lp_lacp.current_while_timer.val));
1751 1751 }
1752 1752 mutex_exit(&pl->lacp_timer_lock);
1753 1753 }
1754 1754
1755 1755
1756 1756 static void
1757 1757 stop_current_while_timer(aggr_port_t *portp)
1758 1758 {
1759 1759 aggr_lacp_port_t *pl = &portp->lp_lacp;
1760 1760 timeout_id_t id;
1761 1761
1762 1762 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1763 1763
1764 1764 mutex_enter(&pl->lacp_timer_lock);
1765 1765 if ((id = pl->current_while_timer.id) != 0) {
1766 1766 pl->lacp_timer_bits &= ~LACP_CURRENT_WHILE_TIMEOUT;
1767 1767 pl->current_while_timer.id = 0;
1768 1768 }
1769 1769 mutex_exit(&pl->lacp_timer_lock);
1770 1770
1771 1771 if (id != 0)
1772 1772 (void) untimeout(id);
1773 1773 }
1774 1774
1775 1775 static void
1776 1776 current_while_timer_pop(void *data)
1777 1777 {
1778 1778 aggr_port_t *portp = (aggr_port_t *)data;
1779 1779 aggr_lacp_port_t *pl = &portp->lp_lacp;
1780 1780
1781 1781 mutex_enter(&pl->lacp_timer_lock);
1782 1782 pl->lacp_timer_bits |= LACP_CURRENT_WHILE_TIMEOUT;
1783 1783 cv_broadcast(&pl->lacp_timer_cv);
1784 1784 mutex_exit(&pl->lacp_timer_lock);
1785 1785 }
1786 1786
1787 1787 static void
1788 1788 current_while_timer_pop_handler(aggr_port_t *portp)
1789 1789 {
1790 1790 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1791 1791
1792 1792 AGGR_LACP_DBG(("trunk link:(%d): current_while_timer "
1793 1793 "pop id=%p\n", portp->lp_linkid,
1794 1794 portp->lp_lacp.current_while_timer.id));
1795 1795
1796 1796 lacp_receive_sm(portp, NULL);
1797 1797 }
1798 1798
1799 1799 /*
1800 1800 * record_Default - Simply copies over administrative values
1801 1801 * to the partner operational values, and sets our state to indicate we
1802 1802 * are using defaulted values.
1803 1803 */
1804 1804 static void
1805 1805 record_Default(aggr_port_t *portp)
1806 1806 {
1807 1807 aggr_lacp_port_t *pl = &portp->lp_lacp;
1808 1808
1809 1809 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1810 1810
1811 1811 pl->PartnerOperPortNum = pl->PartnerAdminPortNum;
1812 1812 pl->PartnerOperPortPriority = pl->PartnerAdminPortPriority;
1813 1813 pl->PartnerOperSystem = pl->PartnerAdminSystem;
1814 1814 pl->PartnerOperSysPriority = pl->PartnerAdminSysPriority;
1815 1815 pl->PartnerOperKey = pl->PartnerAdminKey;
1816 1816 pl->PartnerOperPortState.state = pl->PartnerAdminPortState.state;
1817 1817
1818 1818 pl->ActorOperPortState.bit.defaulted = B_TRUE;
1819 1819 }
1820 1820
1821 1821
1822 1822 /* Returns B_TRUE on sync value changing */
1823 1823 static boolean_t
1824 1824 record_PDU(aggr_port_t *portp, lacp_t *lacp)
1825 1825 {
1826 1826 aggr_grp_t *aggrp = portp->lp_grp;
1827 1827 aggr_lacp_port_t *pl = &portp->lp_lacp;
1828 1828 uint8_t save_sync;
1829 1829
1830 1830 ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
1831 1831
1832 1832 /*
1833 1833 * Partner Information
1834 1834 */
1835 1835 pl->PartnerOperPortNum = ntohs(lacp->actor_info.port);
1836 1836 pl->PartnerOperPortPriority =
1837 1837 ntohs(lacp->actor_info.port_priority);
1838 1838 pl->PartnerOperSystem = lacp->actor_info.system_id;
1839 1839 pl->PartnerOperSysPriority =
1840 1840 htons(lacp->actor_info.system_priority);
1841 1841 pl->PartnerOperKey = ntohs(lacp->actor_info.key);
1842 1842
1843 1843 /* All state info except for Synchronization */
1844 1844 save_sync = pl->PartnerOperPortState.bit.sync;
1845 1845 pl->PartnerOperPortState.state = lacp->actor_info.state.state;
1846 1846
1847 1847 /* Defaulted set to FALSE */
1848 1848 pl->ActorOperPortState.bit.defaulted = B_FALSE;
1849 1849
1850 1850 /*
1851 1851 * 43.4.9 - (Partner_Port, Partner_Port_Priority, Partner_system,
1852 1852 * Partner_System_Priority, Partner_Key, and
1853 1853 * Partner_State.Aggregation) are compared to the
1854 1854 * corresponding operations paramters values for
1855 1855 * the Actor. If these are equal, or if this is
1856 1856 * an individual link, we are synchronized.
1857 1857 */
1858 1858 if (((ntohs(lacp->partner_info.port) == pl->ActorPortNumber) &&
1859 1859 (ntohs(lacp->partner_info.port_priority) ==
1860 1860 pl->ActorPortPriority) &&
1861 1861 (ether_cmp(&lacp->partner_info.system_id,
1862 1862 (struct ether_addr *)&aggrp->lg_addr) == 0) &&
1863 1863 (ntohs(lacp->partner_info.system_priority) ==
1864 1864 aggrp->aggr.ActorSystemPriority) &&
1865 1865 (ntohs(lacp->partner_info.key) == pl->ActorOperPortKey) &&
1866 1866 (lacp->partner_info.state.bit.aggregation ==
1867 1867 pl->ActorOperPortState.bit.aggregation)) ||
1868 1868 (!lacp->actor_info.state.bit.aggregation)) {
1869 1869
1870 1870 pl->PartnerOperPortState.bit.sync =
1871 1871 lacp->actor_info.state.bit.sync;
1872 1872 } else {
1873 1873 pl->PartnerOperPortState.bit.sync = B_FALSE;
1874 1874 }
1875 1875
1876 1876 if (save_sync != pl->PartnerOperPortState.bit.sync) {
1877 1877 AGGR_LACP_DBG(("record_PDU:(%d): partner sync "
1878 1878 "%d -->%d\n", portp->lp_linkid, save_sync,
1879 1879 pl->PartnerOperPortState.bit.sync));
1880 1880 return (B_TRUE);
1881 1881 } else {
1882 1882 return (B_FALSE);
1883 1883 }
1884 1884 }
1885 1885
1886 1886
1887 1887 /*
1888 1888 * update_selected - If any of the Partner parameters has
1889 1889 * changed from a previous value, then
1890 1890 * unselect the link from the aggregator.
1891 1891 */
1892 1892 static boolean_t
1893 1893 update_selected(aggr_port_t *portp, lacp_t *lacp)
1894 1894 {
1895 1895 aggr_lacp_port_t *pl = &portp->lp_lacp;
1896 1896
1897 1897 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1898 1898
1899 1899 if ((pl->PartnerOperPortNum != ntohs(lacp->actor_info.port)) ||
1900 1900 (pl->PartnerOperPortPriority !=
1901 1901 ntohs(lacp->actor_info.port_priority)) ||
1902 1902 (ether_cmp(&pl->PartnerOperSystem,
1903 1903 &lacp->actor_info.system_id) != 0) ||
1904 1904 (pl->PartnerOperSysPriority !=
1905 1905 ntohs(lacp->actor_info.system_priority)) ||
1906 1906 (pl->PartnerOperKey != ntohs(lacp->actor_info.key)) ||
1907 1907 (pl->PartnerOperPortState.bit.aggregation !=
1908 1908 lacp->actor_info.state.bit.aggregation)) {
1909 1909 AGGR_LACP_DBG(("update_selected:(%d): "
1910 1910 "selected %d-->%d\n", portp->lp_linkid, pl->sm.selected,
1911 1911 AGGR_UNSELECTED));
1912 1912
1913 1913 lacp_port_unselect(portp);
1914 1914 return (B_TRUE);
1915 1915 } else {
1916 1916 return (B_FALSE);
1917 1917 }
1918 1918 }
1919 1919
1920 1920
1921 1921 /*
1922 1922 * update_default_selected - If any of the operational Partner parameters
1923 1923 * is different than that of the administrative values
1924 1924 * then unselect the link from the aggregator.
1925 1925 */
1926 1926 static void
1927 1927 update_default_selected(aggr_port_t *portp)
1928 1928 {
1929 1929 aggr_lacp_port_t *pl = &portp->lp_lacp;
1930 1930
1931 1931 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
1932 1932
1933 1933 if ((pl->PartnerAdminPortNum != pl->PartnerOperPortNum) ||
1934 1934 (pl->PartnerOperPortPriority != pl->PartnerAdminPortPriority) ||
1935 1935 (ether_cmp(&pl->PartnerOperSystem, &pl->PartnerAdminSystem) != 0) ||
1936 1936 (pl->PartnerOperSysPriority != pl->PartnerAdminSysPriority) ||
1937 1937 (pl->PartnerOperKey != pl->PartnerAdminKey) ||
1938 1938 (pl->PartnerOperPortState.bit.aggregation !=
1939 1939 pl->PartnerAdminPortState.bit.aggregation)) {
1940 1940
1941 1941 AGGR_LACP_DBG(("update_default_selected:(%d): "
1942 1942 "selected %d-->%d\n", portp->lp_linkid,
1943 1943 pl->sm.selected, AGGR_UNSELECTED));
1944 1944
1945 1945 lacp_port_unselect(portp);
1946 1946 }
1947 1947 }
1948 1948
1949 1949
1950 1950 /*
1951 1951 * update_NTT - If any of the Partner values in the received LACPDU
1952 1952 * are different than that of the Actor operational
1953 1953 * values then set NTT to true.
1954 1954 */
1955 1955 static void
1956 1956 update_NTT(aggr_port_t *portp, lacp_t *lacp)
1957 1957 {
1958 1958 aggr_grp_t *aggrp = portp->lp_grp;
1959 1959 aggr_lacp_port_t *pl = &portp->lp_lacp;
1960 1960
1961 1961 ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
1962 1962
1963 1963 if ((pl->ActorPortNumber != ntohs(lacp->partner_info.port)) ||
1964 1964 (pl->ActorPortPriority !=
1965 1965 ntohs(lacp->partner_info.port_priority)) ||
1966 1966 (ether_cmp(&aggrp->lg_addr,
1967 1967 &lacp->partner_info.system_id) != 0) ||
1968 1968 (aggrp->aggr.ActorSystemPriority !=
1969 1969 ntohs(lacp->partner_info.system_priority)) ||
1970 1970 (pl->ActorOperPortKey != ntohs(lacp->partner_info.key)) ||
1971 1971 (pl->ActorOperPortState.bit.activity !=
1972 1972 lacp->partner_info.state.bit.activity) ||
1973 1973 (pl->ActorOperPortState.bit.timeout !=
1974 1974 lacp->partner_info.state.bit.timeout) ||
1975 1975 (pl->ActorOperPortState.bit.sync !=
1976 1976 lacp->partner_info.state.bit.sync) ||
1977 1977 (pl->ActorOperPortState.bit.aggregation !=
1978 1978 lacp->partner_info.state.bit.aggregation)) {
1979 1979
1980 1980 AGGR_LACP_DBG(("update_NTT:(%d): NTT %d-->%d\n",
1981 1981 portp->lp_linkid, pl->NTT, B_TRUE));
1982 1982
1983 1983 pl->NTT = B_TRUE;
1984 1984 }
1985 1985 }
1986 1986
1987 1987 /*
1988 1988 * lacp_receive_sm - LACP receive state machine
1989 1989 *
1990 1990 * parameters:
1991 1991 * - portp - instance this applies to.
1992 1992 * - lacp - pointer in the case of a received LACPDU.
1993 1993 * This value is NULL if there is no LACPDU.
1994 1994 *
1995 1995 * invoked:
1996 1996 * - when initialization is needed
1997 1997 * - upon reception of an LACPDU. This is the common case.
1998 1998 * - every time the current_while_timer pops
1999 1999 */
2000 2000 static void
2001 2001 lacp_receive_sm(aggr_port_t *portp, lacp_t *lacp)
2002 2002 {
2003 2003 boolean_t sync_updated, selected_updated, save_activity;
2004 2004 aggr_lacp_port_t *pl = &portp->lp_lacp;
2005 2005 lacp_receive_state_t oldstate = pl->sm.receive_state;
2006 2006
2007 2007 ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
2008 2008
2009 2009 /* LACP_OFF state not in specification so check here. */
2010 2010 if (!pl->sm.lacp_on)
2011 2011 return;
2012 2012
2013 2013 /* figure next state */
2014 2014 if (pl->sm.begin || pl->sm.port_moved) {
2015 2015 pl->sm.receive_state = LACP_INITIALIZE;
2016 2016 } else if (!pl->sm.port_enabled) { /* DL_NOTE_LINK_DOWN */
2017 2017 pl->sm.receive_state = LACP_PORT_DISABLED;
2018 2018 } else if (!pl->sm.lacp_enabled) { /* DL_NOTE_AGGR_UNAVAIL */
2019 2019 pl->sm.receive_state =
2020 2020 (pl->sm.receive_state == LACP_PORT_DISABLED) ?
2021 2021 LACP_DISABLED : LACP_PORT_DISABLED;
2022 2022 } else if (lacp != NULL) {
2023 2023 if ((pl->sm.receive_state == LACP_EXPIRED) ||
2024 2024 (pl->sm.receive_state == LACP_DEFAULTED)) {
2025 2025 pl->sm.receive_state = LACP_CURRENT;
2026 2026 }
2027 2027 } else if ((pl->sm.receive_state == LACP_CURRENT) &&
2028 2028 (pl->current_while_timer.id == 0)) {
2029 2029 pl->sm.receive_state = LACP_EXPIRED;
2030 2030 } else if ((pl->sm.receive_state == LACP_EXPIRED) &&
2031 2031 (pl->current_while_timer.id == 0)) {
2032 2032 pl->sm.receive_state = LACP_DEFAULTED;
2033 2033 }
2034 2034
2035 2035 if (!((lacp && (oldstate == LACP_CURRENT) &&
2036 2036 (pl->sm.receive_state == LACP_CURRENT)))) {
2037 2037 AGGR_LACP_DBG(("lacp_receive_sm(%d):%s--->%s\n",
2038 2038 portp->lp_linkid, lacp_receive_str[oldstate],
2039 2039 lacp_receive_str[pl->sm.receive_state]));
2040 2040 }
2041 2041
2042 2042 switch (pl->sm.receive_state) {
2043 2043 case LACP_INITIALIZE:
2044 2044 lacp_port_unselect(portp);
2045 2045 record_Default(portp);
2046 2046 pl->ActorOperPortState.bit.expired = B_FALSE;
2047 2047 pl->sm.port_moved = B_FALSE;
2048 2048 pl->sm.receive_state = LACP_PORT_DISABLED;
2049 2049 pl->sm.begin = B_FALSE;
2050 2050 lacp_receive_sm(portp, NULL);
2051 2051 break;
2052 2052
2053 2053 case LACP_PORT_DISABLED:
2054 2054 pl->PartnerOperPortState.bit.sync = B_FALSE;
2055 2055 /*
2056 2056 * Stop current_while_timer in case
2057 2057 * we got here from link down
2058 2058 */
2059 2059 stop_current_while_timer(portp);
2060 2060
2061 2061 if (pl->sm.port_enabled && !pl->sm.lacp_enabled) {
2062 2062 pl->sm.receive_state = LACP_DISABLED;
2063 2063 lacp_receive_sm(portp, lacp);
2064 2064 /* We goto LACP_DISABLED state */
2065 2065 break;
2066 2066 } else if (pl->sm.port_enabled && pl->sm.lacp_enabled) {
2067 2067 pl->sm.receive_state = LACP_EXPIRED;
2068 2068 /*
2069 2069 * FALL THROUGH TO LACP_EXPIRED CASE:
2070 2070 * We have no way of knowing if we get into
2071 2071 * lacp_receive_sm() from a current_while_timer
2072 2072 * expiring as it has never been kicked off yet!
2073 2073 */
2074 2074 } else {
2075 2075 /* We stay in LACP_PORT_DISABLED state */
2076 2076 break;
2077 2077 }
2078 2078 /* LACP_PORT_DISABLED -> LACP_EXPIRED */
2079 2079 /* FALLTHROUGH */
2080 2080
2081 2081 case LACP_EXPIRED:
2082 2082 /*
2083 2083 * Arrives here from LACP_PORT_DISABLED state as well as
2084 2084 * as well as current_while_timer expiring.
2085 2085 */
2086 2086 pl->PartnerOperPortState.bit.sync = B_FALSE;
2087 2087 pl->PartnerOperPortState.bit.timeout = B_TRUE;
2088 2088
2089 2089 pl->ActorOperPortState.bit.expired = B_TRUE;
2090 2090 start_current_while_timer(portp, SHORT_TIMEOUT_TIME);
2091 2091 lacp_periodic_sm(portp);
2092 2092 break;
2093 2093
2094 2094 case LACP_DISABLED:
2095 2095 /*
2096 2096 * This is the normal state for recv_sm when LACP_OFF
2097 2097 * is set or the NIC is in half duplex mode.
2098 2098 */
2099 2099 lacp_port_unselect(portp);
2100 2100 record_Default(portp);
2101 2101 pl->PartnerOperPortState.bit.aggregation = B_FALSE;
2102 2102 pl->ActorOperPortState.bit.expired = B_FALSE;
2103 2103 break;
2104 2104
2105 2105 case LACP_DEFAULTED:
2106 2106 /*
2107 2107 * Current_while_timer expired a second time.
2108 2108 */
2109 2109 update_default_selected(portp);
2110 2110 record_Default(portp); /* overwrite Partner Oper val */
2111 2111 pl->ActorOperPortState.bit.expired = B_FALSE;
2112 2112 pl->PartnerOperPortState.bit.sync = B_TRUE;
2113 2113
2114 2114 lacp_selection_logic(portp);
2115 2115 lacp_mux_sm(portp);
2116 2116 break;
2117 2117
2118 2118 case LACP_CURRENT:
2119 2119 /*
2120 2120 * Reception of LACPDU
2121 2121 */
2122 2122
2123 2123 if (!lacp) /* no LACPDU so current_while_timer popped */
2124 2124 break;
2125 2125
2126 2126 AGGR_LACP_DBG(("lacp_receive_sm: (%d): LACPDU received:\n",
2127 2127 portp->lp_linkid));
2128 2128
2129 2129 /*
2130 2130 * Validate Actor_Information_Length,
2131 2131 * Partner_Information_Length, Collector_Information_Length,
2132 2132 * and Terminator_Length fields.
2133 2133 */
2134 2134 if (!valid_lacp_pdu(portp, lacp)) {
2135 2135 AGGR_LACP_DBG(("lacp_receive_sm (%d): "
2136 2136 "Invalid LACPDU received\n",
2137 2137 portp->lp_linkid));
2138 2138 break;
2139 2139 }
2140 2140
2141 2141 save_activity = pl->PartnerOperPortState.bit.activity;
2142 2142 selected_updated = update_selected(portp, lacp);
2143 2143 update_NTT(portp, lacp);
2144 2144 sync_updated = record_PDU(portp, lacp);
2145 2145
2146 2146 pl->ActorOperPortState.bit.expired = B_FALSE;
2147 2147
2148 2148 if (selected_updated) {
2149 2149 lacp_selection_logic(portp);
2150 2150 lacp_mux_sm(portp);
2151 2151 } else if (sync_updated) {
2152 2152 lacp_mux_sm(portp);
2153 2153 }
2154 2154
2155 2155 /*
2156 2156 * If the periodic timer value bit has been modified
2157 2157 * or the partner activity bit has been changed then
2158 2158 * we need to respectively:
2159 2159 * - restart the timer with the proper timeout value.
2160 2160 * - possibly enable/disable transmission of LACPDUs.
2161 2161 */
2162 2162 if ((pl->PartnerOperPortState.bit.timeout &&
2163 2163 (pl->periodic_timer.val != FAST_PERIODIC_TIME)) ||
2164 2164 (!pl->PartnerOperPortState.bit.timeout &&
2165 2165 (pl->periodic_timer.val != SLOW_PERIODIC_TIME)) ||
2166 2166 (pl->PartnerOperPortState.bit.activity !=
2167 2167 save_activity)) {
2168 2168 lacp_periodic_sm(portp);
2169 2169 }
2170 2170
2171 2171 stop_current_while_timer(portp);
2172 2172 /* Check if we need to transmit an LACPDU */
2173 2173 if (pl->NTT)
2174 2174 lacp_xmit_sm(portp);
2175 2175 start_current_while_timer(portp, 0);
2176 2176
2177 2177 break;
2178 2178 }
2179 2179 }
2180 2180
2181 2181 static void
2182 2182 aggr_set_coll_dist(aggr_port_t *portp, boolean_t enable)
2183 2183 {
2184 2184 mac_perim_handle_t mph;
2185 2185
2186 2186 AGGR_LACP_DBG(("AGGR_SET_COLL_DIST_TYPE: (%d) %s\n",
2187 2187 portp->lp_linkid, enable ? "ENABLED" : "DISABLED"));
2188 2188
2189 2189 mac_perim_enter_by_mh(portp->lp_mh, &mph);
2190 2190 if (!enable) {
2191 2191 /*
2192 2192 * Turn OFF Collector_Distributor.
2193 2193 */
2194 2194 portp->lp_collector_enabled = B_FALSE;
2195 2195 aggr_send_port_disable(portp);
2196 2196 goto done;
2197 2197 }
2198 2198
2199 2199 /*
2200 2200 * Turn ON Collector_Distributor.
2201 2201 */
2202 2202
2203 2203 if (!portp->lp_lacp.sm.lacp_on || (portp->lp_lacp.sm.lacp_on &&
2204 2204 (portp->lp_lacp.sm.mux_state == LACP_COLLECTING_DISTRIBUTING))) {
2205 2205 /* Port is compatible and can be aggregated */
2206 2206 portp->lp_collector_enabled = B_TRUE;
2207 2207 aggr_send_port_enable(portp);
2208 2208 }
2209 2209
2210 2210 done:
2211 2211 mac_perim_exit(mph);
2212 2212 }
2213 2213
2214 2214 /*
2215 2215 * Because the LACP packet processing needs to enter the aggr's mac perimeter
2216 2216 * and that would potentially cause a deadlock with the thread in which the
2217 2217 * grp/port is deleted, we defer the packet process to a worker thread. Here
2218 2218 * we only enqueue the received Marker or LACPDU for later processing.
2219 2219 */
2220 2220 void
2221 2221 aggr_lacp_rx_enqueue(aggr_port_t *portp, mblk_t *dmp)
2222 2222 {
2223 2223 aggr_grp_t *grp = portp->lp_grp;
2224 2224 lacp_t *lacp;
2225 2225
2226 2226 dmp->b_rptr += sizeof (struct ether_header);
2227 2227
2228 2228 if (MBLKL(dmp) < sizeof (lacp_t)) {
2229 2229 freemsg(dmp);
2230 2230 return;
2231 2231 }
2232 2232
2233 2233 lacp = (lacp_t *)dmp->b_rptr;
2234 2234 if (lacp->subtype != LACP_SUBTYPE && lacp->subtype != MARKER_SUBTYPE) {
2235 2235 AGGR_LACP_DBG(("aggr_lacp_rx_enqueue: (%d): "
2236 2236 "Unknown Slow Protocol type %d\n",
2237 2237 portp->lp_linkid, lacp->subtype));
2238 2238 freemsg(dmp);
2239 2239 return;
2240 2240 }
2241 2241
2242 2242 mutex_enter(&grp->lg_lacp_lock);
2243 2243
2244 2244 /*
2245 2245 * If the lg_lacp_done is set, this aggregation is in the process of
2246 2246 * being deleted, return directly.
2247 2247 */
2248 2248 if (grp->lg_lacp_done) {
2249 2249 mutex_exit(&grp->lg_lacp_lock);
2250 2250 freemsg(dmp);
2251 2251 return;
2252 2252 }
2253 2253
2254 2254 if (grp->lg_lacp_tail == NULL) {
2255 2255 grp->lg_lacp_head = grp->lg_lacp_tail = dmp;
2256 2256 } else {
2257 2257 grp->lg_lacp_tail->b_next = dmp;
2258 2258 grp->lg_lacp_tail = dmp;
2259 2259 }
2260 2260
2261 2261 /*
2262 2262 * Hold a reference of the port so that the port won't be freed when it
2263 2263 * is removed from the aggr. The b_prev field is borrowed to save the
2264 2264 * port information.
2265 2265 */
2266 2266 AGGR_PORT_REFHOLD(portp);
2267 2267 dmp->b_prev = (mblk_t *)portp;
2268 2268 cv_broadcast(&grp->lg_lacp_cv);
2269 2269 mutex_exit(&grp->lg_lacp_lock);
2270 2270 }
2271 2271
2272 2272 static void
2273 2273 aggr_lacp_rx(mblk_t *dmp)
2274 2274 {
2275 2275 aggr_port_t *portp = (aggr_port_t *)dmp->b_prev;
2276 2276 mac_perim_handle_t mph;
2277 2277 lacp_t *lacp;
2278 2278
2279 2279 dmp->b_prev = NULL;
2280 2280
2281 2281 mac_perim_enter_by_mh(portp->lp_grp->lg_mh, &mph);
2282 2282 if (portp->lp_closing)
2283 2283 goto done;
2284 2284
2285 2285 lacp = (lacp_t *)dmp->b_rptr;
2286 2286 switch (lacp->subtype) {
2287 2287 case LACP_SUBTYPE:
2288 2288 AGGR_LACP_DBG(("aggr_lacp_rx:(%d): LACPDU received.\n",
2289 2289 portp->lp_linkid));
2290 2290
2291 2291 if (!portp->lp_lacp.sm.lacp_on) {
2292 2292 break;
2293 2293 }
2294 2294 lacp_receive_sm(portp, lacp);
2295 2295 break;
2296 2296
2297 2297 case MARKER_SUBTYPE:
2298 2298 AGGR_LACP_DBG(("aggr_lacp_rx:(%d): Marker Packet received.\n",
2299 2299 portp->lp_linkid));
2300 2300
2301 2301 if (receive_marker_pdu(portp, dmp) != 0)
2302 2302 break;
2303 2303
2304 2304 /* Send the packet over the first TX ring */
2305 2305 dmp = mac_hwring_send_priv(portp->lp_mch,
2306 2306 portp->lp_tx_rings[0], dmp);
2307 2307 if (dmp != NULL)
2308 2308 freemsg(dmp);
2309 2309 mac_perim_exit(mph);
2310 2310 AGGR_PORT_REFRELE(portp);
2311 2311 return;
2312 2312 }
2313 2313
2314 2314 done:
2315 2315 mac_perim_exit(mph);
2316 2316 AGGR_PORT_REFRELE(portp);
2317 2317 freemsg(dmp);
2318 2318 }
2319 2319
2320 2320 void
2321 2321 aggr_lacp_rx_thread(void *arg)
2322 2322 {
2323 2323 callb_cpr_t cprinfo;
2324 2324 aggr_grp_t *grp = (aggr_grp_t *)arg;
2325 2325 aggr_port_t *port;
2326 2326 mblk_t *mp, *nextmp;
2327 2327
2328 2328 CALLB_CPR_INIT(&cprinfo, &grp->lg_lacp_lock, callb_generic_cpr,
2329 2329 "aggr_lacp_rx_thread");
2330 2330
2331 2331 mutex_enter(&grp->lg_lacp_lock);
2332 2332
2333 2333 /*
2334 2334 * Quit the thread if the grp is deleted.
2335 2335 */
2336 2336 while (!grp->lg_lacp_done) {
2337 2337 if ((mp = grp->lg_lacp_head) == NULL) {
2338 2338 CALLB_CPR_SAFE_BEGIN(&cprinfo);
2339 2339 cv_wait(&grp->lg_lacp_cv, &grp->lg_lacp_lock);
2340 2340 CALLB_CPR_SAFE_END(&cprinfo, &grp->lg_lacp_lock);
2341 2341 continue;
2342 2342 }
2343 2343
2344 2344 grp->lg_lacp_head = grp->lg_lacp_tail = NULL;
2345 2345 mutex_exit(&grp->lg_lacp_lock);
2346 2346
2347 2347 while (mp != NULL) {
2348 2348 nextmp = mp->b_next;
2349 2349 mp->b_next = NULL;
2350 2350 aggr_lacp_rx(mp);
2351 2351 mp = nextmp;
2352 2352 }
2353 2353 mutex_enter(&grp->lg_lacp_lock);
2354 2354 }
2355 2355
2356 2356 /*
2357 2357 * The grp is being destroyed, simply free all of the LACP messages
2358 2358 * left in the queue which did not have the chance to be processed.
2359 2359 * We cannot use freemsgchain() here since we need to clear the
2360 2360 * b_prev field.
2361 2361 */
2362 2362 for (mp = grp->lg_lacp_head; mp != NULL; mp = nextmp) {
2363 2363 port = (aggr_port_t *)mp->b_prev;
2364 2364 AGGR_PORT_REFRELE(port);
2365 2365 nextmp = mp->b_next;
2366 2366 mp->b_next = NULL;
2367 2367 mp->b_prev = NULL;
2368 2368 freemsg(mp);
2369 2369 }
2370 2370
2371 2371 grp->lg_lacp_head = grp->lg_lacp_tail = NULL;
2372 2372 grp->lg_lacp_rx_thread = NULL;
2373 2373 cv_broadcast(&grp->lg_lacp_cv);
2374 2374 CALLB_CPR_EXIT(&cprinfo);
2375 2375 thread_exit();
2376 2376 }
↓ open down ↓ |
2306 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX