xref: /netbsd/sys/net/agr/ieee8023ad_lacp.c (revision 6550d01e)
1 /*	$NetBSD: ieee8023ad_lacp.c,v 1.9 2009/05/29 04:57:05 darran Exp $	*/
2 
3 /*-
4  * Copyright (c)2005 YAMAMOTO Takashi,
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ieee8023ad_lacp.c,v 1.9 2009/05/29 04:57:05 darran Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/callout.h>
34 #include <sys/mbuf.h>
35 #include <sys/systm.h>
36 #include <sys/malloc.h>
37 #include <sys/kernel.h> /* hz */
38 
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <net/if_ether.h>
42 #include <net/if_media.h>
43 
44 #include <net/agr/if_agrvar_impl.h>
45 #include <net/agr/if_agrsubr.h>
46 #include <net/agr/ieee8023_slowprotocols.h>
47 #include <net/agr/ieee8023_tlv.h>
48 #include <net/agr/ieee8023ad.h>
49 #include <net/agr/ieee8023ad_lacp.h>
50 #include <net/agr/ieee8023ad_lacp_impl.h>
51 #include <net/agr/ieee8023ad_impl.h>
52 #include <net/agr/ieee8023ad_lacp_sm.h>
53 #include <net/agr/ieee8023ad_lacp_debug.h>
54 
55 static void lacp_fill_actorinfo(struct agr_port *, struct lacp_peerinfo *);
56 
57 static uint64_t lacp_aggregator_bandwidth(struct lacp_aggregator *);
58 static void lacp_suppress_distributing(struct lacp_softc *,
59     struct lacp_aggregator *);
60 static void lacp_transit_expire(void *);
61 static void lacp_select_active_aggregator(struct lacp_softc *);
62 static uint16_t lacp_compose_key(struct lacp_port *);
63 
64 /*
65  * actor system priority and port priority.
66  * XXX should be configurable.
67  */
68 
69 #define	LACP_SYSTEM_PRIO	0x8000
70 #define	LACP_PORT_PRIO		0x8000
71 
72 static const struct tlv_template lacp_info_tlv_template[] = {
73 	{ LACP_TYPE_ACTORINFO,
74 	    sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) },
75 	{ LACP_TYPE_PARTNERINFO,
76 	    sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) },
77 	{ LACP_TYPE_COLLECTORINFO,
78 	    sizeof(struct tlvhdr) + sizeof(struct lacp_collectorinfo) },
79 	{ 0, 0 },
80 };
81 
82 /*
83  * ieee8023ad_lacp_input: process lacpdu
84  *
85  * => called from ether_input.  (ie. at IPL_NET)
86  *
87  * XXX is it better to defer processing to lower IPL?
88  * XXX anyway input rate should be very low...
89  */
90 
91 int
92 ieee8023ad_lacp_input(struct ifnet *ifp, struct mbuf *m)
93 {
94 	struct lacpdu *du;
95 	struct agr_softc *sc;
96 	struct agr_port *port;
97 	struct lacp_port *lp;
98 	int error = 0;
99 
100 	port = ifp->if_agrprivate; /* XXX race with agr_remport. */
101 	if (__predict_false(port->port_flags & AGRPORT_DETACHING)) {
102 		goto bad;
103 	}
104 
105 	sc = AGR_SC_FROM_PORT(port);
106 	KASSERT(port);
107 
108 	/* running static config? */
109 	if (AGR_STATIC(sc)) {
110 		/* static config, no lacp */
111 		goto bad;
112 	}
113 
114 
115 	if (m->m_pkthdr.len != sizeof(*du)) {
116 		goto bad;
117 	}
118 
119 	if ((m->m_flags & M_MCAST) == 0) {
120 		goto bad;
121 	}
122 
123 	if (m->m_len < sizeof(*du)) {
124 		m = m_pullup(m, sizeof(*du));
125 		if (m == NULL) {
126 			return ENOMEM;
127 		}
128 	}
129 
130 	du = mtod(m, struct lacpdu *);
131 
132 	if (memcmp(&du->ldu_eh.ether_dhost,
133 	    &ethermulticastaddr_slowprotocols, ETHER_ADDR_LEN)) {
134 		goto bad;
135 	}
136 
137 	KASSERT(du->ldu_sph.sph_subtype == SLOWPROTOCOLS_SUBTYPE_LACP);
138 
139 	/*
140 	 * ignore the version for compatibility with
141 	 * the future protocol revisions.
142 	 */
143 
144 #if 0
145 	if (du->ldu_sph.sph_version != 1) {
146 		goto bad;
147 	}
148 #endif
149 
150 	/*
151 	 * ignore tlv types for compatibility with
152 	 * the future protocol revisions.
153 	 */
154 
155 	if (tlv_check(du, sizeof(*du), &du->ldu_tlv_actor,
156 	    lacp_info_tlv_template, false)) {
157 		goto bad;
158 	}
159 
160 	AGR_LOCK(sc);
161 	lp = LACP_PORT(port);
162 
163 #if defined(LACP_DEBUG)
164 	if (lacpdebug) {
165 		LACP_DPRINTF((lp, "lacpdu receive\n"));
166 		lacp_dump_lacpdu(du);
167 	}
168 #endif /* defined(LACP_DEBUG) */
169 	lacp_sm_rx(lp, du);
170 
171 	AGR_UNLOCK(sc);
172 
173 	m_freem(m);
174 
175 	return error;
176 
177 bad:
178 	m_freem(m);
179 	return EINVAL;
180 }
181 
182 static void
183 lacp_fill_actorinfo(struct agr_port *port, struct lacp_peerinfo *info)
184 {
185 	struct lacp_port *lp = LACP_PORT(port);
186 
187 	info->lip_systemid.lsi_prio = htobe16(LACP_SYSTEM_PRIO);
188 	memcpy(&info->lip_systemid.lsi_mac,
189 	    CLLADDR(port->port_ifp->if_sadl), ETHER_ADDR_LEN);
190 	info->lip_portid.lpi_prio = htobe16(LACP_PORT_PRIO);
191 	info->lip_portid.lpi_portno = htobe16(port->port_ifp->if_index);
192 	info->lip_state = lp->lp_state;
193 }
194 
195 int
196 lacp_xmit_lacpdu(struct lacp_port *lp)
197 {
198 	struct agr_port *port = lp->lp_agrport;
199 	struct mbuf *m;
200 	struct lacpdu *du;
201 	int error;
202 
203 	/* running static config? */
204 	if (AGR_STATIC(AGR_SC_FROM_PORT(port))) {
205 		/* static config, no lacp transmit */
206 		return 0;
207 	}
208 
209 	KDASSERT(MHLEN >= sizeof(*du));
210 
211 	m = m_gethdr(M_DONTWAIT, MT_DATA);
212 	if (m == NULL) {
213 		return ENOMEM;
214 	}
215 	m->m_len = m->m_pkthdr.len = sizeof(*du);
216 
217 	du = mtod(m, struct lacpdu *);
218 	memset(du, 0, sizeof(*du));
219 
220 	memcpy(&du->ldu_eh.ether_dhost, ethermulticastaddr_slowprotocols,
221 	    ETHER_ADDR_LEN);
222 	memcpy(&du->ldu_eh.ether_shost, &port->port_origlladdr, ETHER_ADDR_LEN);
223 	du->ldu_eh.ether_type = htobe16(ETHERTYPE_SLOWPROTOCOLS);
224 
225 	du->ldu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_LACP;
226 	du->ldu_sph.sph_version = 1;
227 
228 	TLV_SET(&du->ldu_tlv_actor, LACP_TYPE_ACTORINFO, sizeof(du->ldu_actor));
229 	du->ldu_actor = lp->lp_actor;
230 
231 	TLV_SET(&du->ldu_tlv_partner, LACP_TYPE_PARTNERINFO,
232 	    sizeof(du->ldu_partner));
233 	du->ldu_partner = lp->lp_partner;
234 
235 	TLV_SET(&du->ldu_tlv_collector, LACP_TYPE_COLLECTORINFO,
236 	    sizeof(du->ldu_collector));
237 	du->ldu_collector.lci_maxdelay = 0;
238 
239 #if defined(LACP_DEBUG)
240 	if (lacpdebug) {
241 		LACP_DPRINTF((lp, "lacpdu transmit\n"));
242 		lacp_dump_lacpdu(du);
243 	}
244 #endif /* defined(LACP_DEBUG) */
245 
246 	m->m_flags |= M_MCAST;
247 
248 	/*
249 	 * XXX should use higher priority queue.
250 	 * otherwise network congestion can break aggregation.
251 	 */
252 
253 	error = agr_xmit_frame(port->port_ifp, m);
254 	return error;
255 }
256 
257 void
258 ieee8023ad_lacp_portstate(struct agr_port *port)
259 {
260 	struct lacp_port *lp = LACP_PORT(port);
261 	u_int media = port->port_media;
262 	uint8_t old_state;
263 	uint16_t old_key;
264 
265 	AGR_ASSERT_LOCKED(AGR_SC_FROM_PORT(port));
266 
267 	LACP_DPRINTF((lp, "media changed 0x%x -> 0x%x\n", lp->lp_media, media));
268 
269 	old_state = lp->lp_state;
270 	old_key = lp->lp_key;
271 
272 	lp->lp_media = media;
273 	if ((media & IFM_HDX) != 0) {
274 		lp->lp_state &= ~LACP_STATE_AGGREGATION;
275 	} else {
276 		lp->lp_state |= LACP_STATE_AGGREGATION;
277 	}
278 	lp->lp_key = lacp_compose_key(lp);
279 
280 	if (old_state != lp->lp_state || old_key != lp->lp_key) {
281 		LACP_DPRINTF((lp, "-> UNSELECTED\n"));
282 		lp->lp_selected = LACP_UNSELECTED;
283 	}
284 }
285 
286 void
287 ieee8023ad_lacp_porttick(struct agr_softc *sc, struct agr_port *port)
288 {
289 	struct lacp_port *lp = LACP_PORT(port);
290 
291 	AGR_ASSERT_LOCKED(sc);
292 
293 	lacp_run_timers(lp);
294 
295 	lacp_select(lp);
296 	lacp_sm_mux(lp);
297 	lacp_sm_tx(lp);
298 	lacp_sm_ptx_tx_schedule(lp);
299 }
300 
301 void
302 lacp_portinit(struct agr_port *port)
303 {
304 	struct lacp_port *lp = LACP_PORT(port);
305 	bool active = true; /* XXX should be configurable */
306 	bool fast = false; /* XXX should be configurable */
307 
308 	lp->lp_agrport = port;
309 	lacp_fill_actorinfo(port, &lp->lp_actor);
310 	lp->lp_state =
311 	    (active ? LACP_STATE_ACTIVITY : 0) |
312 	    (fast ? LACP_STATE_TIMEOUT : 0);
313 	lp->lp_aggregator = NULL;
314 	lp->lp_media = port->port_media; /* XXX */
315 	lp->lp_key = lacp_compose_key(lp);
316 	lacp_sm_rx_set_expired(lp);
317 }
318 
319 void
320 lacp_portfini(struct agr_port *port)
321 {
322 	struct lacp_port *lp = LACP_PORT(port);
323 	struct lacp_aggregator *la = lp->lp_aggregator;
324 	int i;
325 
326 	LACP_DPRINTF((lp, "portfini\n"));
327 
328 	for (i = 0; i < LACP_NTIMER; i++) {
329 		LACP_TIMER_DISARM(lp, i);
330 	}
331 
332 	if (la == NULL) {
333 		return;
334 	}
335 
336 	lacp_disable_distributing(lp);
337 	lacp_unselect(lp);
338 }
339 
340 /* -------------------- */
341 void
342 lacp_disable_collecting(struct lacp_port *lp)
343 {
344 	struct agr_port *port = lp->lp_agrport;
345 
346 	lp->lp_state &= ~LACP_STATE_COLLECTING;
347 	port->port_flags &= ~AGRPORT_COLLECTING;
348 }
349 
350 void
351 lacp_enable_collecting(struct lacp_port *lp)
352 {
353 	struct agr_port *port = lp->lp_agrport;
354 
355 	lp->lp_state |= LACP_STATE_COLLECTING;
356 	port->port_flags |= AGRPORT_COLLECTING;
357 }
358 
359 void
360 lacp_disable_distributing(struct lacp_port *lp)
361 {
362 	struct agr_port *port = lp->lp_agrport;
363 	struct lacp_aggregator *la = lp->lp_aggregator;
364 	struct lacp_softc *lsc = LACP_SOFTC(AGR_SC_FROM_PORT(port));
365 #if defined(LACP_DEBUG)
366 	char buf[LACP_LAGIDSTR_MAX+1];
367 #endif /* defined(LACP_DEBUG) */
368 
369 	if ((lp->lp_state & LACP_STATE_DISTRIBUTING) == 0) {
370 		return;
371 	}
372 
373 	KASSERT(la);
374 	KASSERT(!TAILQ_EMPTY(&la->la_ports));
375 	KASSERT(la->la_nports > 0);
376 	KASSERT(la->la_refcnt >= la->la_nports);
377 
378 	LACP_DPRINTF((lp, "disable distributing on aggregator %s, "
379 	    "nports %d -> %d\n",
380 	    lacp_format_lagid_aggregator(la, buf, sizeof(buf)),
381 	    la->la_nports, la->la_nports - 1));
382 
383 	TAILQ_REMOVE(&la->la_ports, lp, lp_dist_q);
384 	la->la_nports--;
385 
386 	lacp_suppress_distributing(lsc, la);
387 
388 	lp->lp_state &= ~LACP_STATE_DISTRIBUTING;
389 	port->port_flags &= ~AGRPORT_DISTRIBUTING;
390 
391 	if (lsc->lsc_active_aggregator == la) {
392 		lacp_select_active_aggregator(lsc);
393 	}
394 }
395 
396 void
397 lacp_enable_distributing(struct lacp_port *lp)
398 {
399 	struct agr_port *port = lp->lp_agrport;
400 	struct lacp_aggregator *la = lp->lp_aggregator;
401 	struct lacp_softc *lsc = LACP_SOFTC(AGR_SC_FROM_PORT(port));
402 #if defined(LACP_DEBUG)
403 	char buf[LACP_LAGIDSTR_MAX+1];
404 #endif /* defined(LACP_DEBUG) */
405 
406 	if ((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0) {
407 		return;
408 	}
409 
410 	KASSERT(la);
411 
412 	LACP_DPRINTF((lp, "enable distributing on aggregator %s, "
413 	    "nports %d -> %d\n",
414 	    lacp_format_lagid_aggregator(la, buf, sizeof(buf)),
415 	    la->la_nports, la->la_nports + 1));
416 
417 	KASSERT(la->la_refcnt > la->la_nports);
418 	TAILQ_INSERT_HEAD(&la->la_ports, lp, lp_dist_q);
419 	la->la_nports++;
420 
421 	lacp_suppress_distributing(lsc, la);
422 
423 	lp->lp_state |= LACP_STATE_DISTRIBUTING;
424 	port->port_flags |= AGRPORT_DISTRIBUTING;
425 
426 	if (lsc->lsc_active_aggregator != la) {
427 		lacp_select_active_aggregator(lsc);
428 	}
429 }
430 
431 static void
432 lacp_transit_expire(void *vp)
433 {
434 	struct agr_softc *sc = vp;
435 	struct lacp_softc *lsc = LACP_SOFTC(sc);
436 
437 	AGR_LOCK(sc);
438 	LACP_DPRINTF((NULL, "%s\n", __func__));
439 	lsc->lsc_suppress_distributing = false;
440 	AGR_UNLOCK(sc);
441 }
442 
443 /* -------------------- */
444 /* XXX */
445 void
446 ieee8023ad_portinit(struct agr_port *port)
447 {
448 	struct ieee8023ad_port *iport = IEEE8023AD_PORT(port);
449 
450 	memset(iport, 0, sizeof(iport));
451 
452 	lacp_portinit(port);
453 }
454 
455 void
456 ieee8023ad_portfini(struct agr_port *port)
457 {
458 	struct agr_softc *sc = AGR_SC_FROM_PORT(port);
459 
460 	AGR_LOCK(sc);
461 
462 	lacp_portfini(port);
463 
464 	AGR_UNLOCK(sc);
465 }
466 
467 void
468 ieee8023ad_ctor(struct agr_softc *sc)
469 {
470 	struct ieee8023ad_softc *isc = IEEE8023AD_SOFTC(sc);
471 	struct lacp_softc *lsc = &isc->isc_lacpsc;
472 
473 	lsc->lsc_active_aggregator = NULL;
474 	TAILQ_INIT(&lsc->lsc_aggregators);
475 	callout_init(&lsc->lsc_transit_callout, 0);
476 	callout_setfunc(&lsc->lsc_transit_callout, lacp_transit_expire, sc);
477 }
478 
479 void
480 ieee8023ad_dtor(struct agr_softc *sc)
481 {
482 	struct ieee8023ad_softc *isc = IEEE8023AD_SOFTC(sc);
483 	struct lacp_softc *lsc = &isc->isc_lacpsc;
484 
485 	LACP_DPRINTF((NULL, "%s\n", __func__));
486 
487 	callout_stop(&lsc->lsc_transit_callout);
488 	KASSERT(TAILQ_EMPTY(&lsc->lsc_aggregators));
489 	KASSERT(lsc->lsc_active_aggregator == NULL);
490 }
491 
492 /* -------------------- */
493 
494 struct agr_port *
495 ieee8023ad_select_tx_port(struct agr_softc *sc, struct mbuf *m)
496 {
497 	const struct lacp_softc *lsc = LACP_SOFTC(sc);
498 	const struct lacp_aggregator *la;
499 	const struct lacp_port *lp;
500 	uint32_t hash;
501 	int nports;
502 
503 	if (__predict_false(lsc->lsc_suppress_distributing &&
504 	    !AGR_ROUNDROBIN(sc))) {
505 		LACP_DPRINTF((NULL, "%s: waiting transit\n", __func__));
506 		sc->sc_if.if_collisions++; /* XXX abuse */
507 		return NULL;
508 	}
509 
510 	la = lsc->lsc_active_aggregator;
511 	if (__predict_false(la == NULL)) {
512 		LACP_DPRINTF((NULL, "%s: no active aggregator\n", __func__));
513 		return NULL;
514 	}
515 
516 	nports = la->la_nports;
517 	KASSERT(nports > 0);
518 
519 	if (AGR_ROUNDROBIN(sc)) {
520 		/* packet ordering rule violation */
521 		hash = sc->sc_rr_counter++;
522 	} else {
523 		hash = (*sc->sc_iftop->iftop_hashmbuf)(sc, m);
524 	}
525 	hash %= nports;
526 	lp = TAILQ_FIRST(&la->la_ports);
527 	KASSERT(lp != NULL);
528 	while (hash--) {
529 		lp = TAILQ_NEXT(lp, lp_dist_q);
530 		KASSERT(lp != NULL);
531 	}
532 
533 	KASSERT((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0);
534 
535 	return lp->lp_agrport;
536 }
537 
538 /*
539  * lacp_suppress_distributing: drop transmit packets for a while
540  * to preserve packet ordering.
541  */
542 
543 static void
544 lacp_suppress_distributing(struct lacp_softc *lsc, struct lacp_aggregator *la)
545 {
546 
547 	if (lsc->lsc_active_aggregator != la) {
548 		return;
549 	}
550 
551 	LACP_DPRINTF((NULL, "%s\n", __func__));
552 	lsc->lsc_suppress_distributing = true;
553 	/* XXX should consider collector max delay */
554 	callout_schedule(&lsc->lsc_transit_callout,
555 	    LACP_TRANSIT_DELAY * hz / 1000);
556 }
557 
558 /* -------------------- */
559 
560 int
561 lacp_compare_peerinfo(const struct lacp_peerinfo *a,
562     const struct lacp_peerinfo *b)
563 {
564 
565 	return memcmp(a, b, offsetof(struct lacp_peerinfo, lip_state));
566 }
567 
568 int
569 lacp_compare_systemid(const struct lacp_systemid *a,
570     const struct lacp_systemid *b)
571 {
572 
573 	return memcmp(a, b, sizeof(*a));
574 }
575 
576 int
577 lacp_compare_portid(const struct lacp_portid *a,
578     const struct lacp_portid *b)
579 {
580 
581 	return memcmp(a, b, sizeof(*a));
582 }
583 
584 /* -------------------- */
585 
586 static uint64_t
587 lacp_aggregator_bandwidth(struct lacp_aggregator *la)
588 {
589 	struct lacp_port *lp;
590 	uint64_t speed;
591 
592 	lp = TAILQ_FIRST(&la->la_ports);
593 	if (lp == NULL) {
594 		return 0;
595 	}
596 
597 	speed = ifmedia_baudrate(lp->lp_media);
598 	speed *= la->la_nports;
599 	if (speed == 0) {
600 		LACP_DPRINTF((lp, "speed 0? media=0x%x nports=%d\n",
601 		    lp->lp_media, la->la_nports));
602 	}
603 
604 	return speed;
605 }
606 
607 /*
608  * lacp_select_active_aggregator: select an aggregator to be used to transmit
609  * packets from agr(4) interface.
610  */
611 
612 static void
613 lacp_select_active_aggregator(struct lacp_softc *lsc)
614 {
615 	struct lacp_aggregator *la;
616 	struct lacp_aggregator *best_la = NULL;
617 	uint64_t best_speed = 0;
618 #if defined(LACP_DEBUG)
619 	char buf[LACP_LAGIDSTR_MAX+1];
620 #endif /* defined(LACP_DEBUG) */
621 
622 	LACP_DPRINTF((NULL, "%s:\n", __func__));
623 
624 	TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) {
625 		uint64_t speed;
626 
627 		if (la->la_nports == 0) {
628 			continue;
629 		}
630 
631 		speed = lacp_aggregator_bandwidth(la);
632 		LACP_DPRINTF((NULL, "%s, speed=%" PRIu64 ", nports=%d\n",
633 		    lacp_format_lagid_aggregator(la, buf, sizeof(buf)),
634 		    speed, la->la_nports));
635 		if (speed > best_speed ||
636 		    (speed == best_speed &&
637 		    la == lsc->lsc_active_aggregator)) {
638 			best_la = la;
639 			best_speed = speed;
640 		}
641 	}
642 
643 	KASSERT(best_la == NULL || best_la->la_nports > 0);
644 	KASSERT(best_la == NULL || !TAILQ_EMPTY(&best_la->la_ports));
645 
646 #if defined(LACP_DEBUG)
647 	if (lsc->lsc_active_aggregator != best_la) {
648 		LACP_DPRINTF((NULL, "active aggregator changed\n"));
649 		LACP_DPRINTF((NULL, "old %s\n",
650 		    lacp_format_lagid_aggregator(lsc->lsc_active_aggregator,
651 		    buf, sizeof(buf))));
652 	} else {
653 		LACP_DPRINTF((NULL, "active aggregator not changed\n"));
654 	}
655 	LACP_DPRINTF((NULL, "new %s\n",
656 	    lacp_format_lagid_aggregator(best_la, buf, sizeof(buf))));
657 #endif /* defined(LACP_DEBUG) */
658 
659 	if (lsc->lsc_active_aggregator != best_la) {
660 		lsc->lsc_active_aggregator = best_la;
661 		if (best_la) {
662 			lacp_suppress_distributing(lsc, best_la);
663 		}
664 	}
665 }
666 
667 uint16_t
668 lacp_compose_key(struct lacp_port *lp)
669 {
670 	u_int media = lp->lp_media;
671 	uint16_t key;
672 
673 	KASSERT(IFM_TYPE(media) == IFM_ETHER);
674 
675 	if (!(lp->lp_state & LACP_STATE_AGGREGATION)) {
676 
677 		/*
678 		 * non-aggregatable links should have unique keys.
679 		 *
680 		 * XXX this isn't really unique as if_index is 16 bit.
681 		 */
682 
683 		/* bit 0..14:	(some bits of) if_index of this port */
684 		key = lp->lp_agrport->port_ifp->if_index;
685 		/* bit 15:	1 */
686 		key |= 0x8000;
687 	} else {
688 		u_int subtype = IFM_SUBTYPE(media);
689 
690 		KASSERT((media & IFM_HDX) == 0); /* should be handled above */
691 		KASSERT((subtype & 0x1f) == subtype);
692 
693 		/* bit 0..4:	IFM_SUBTYPE */
694 		key = subtype;
695 		/* bit 5..14:	(some bits of) if_index of agr device */
696 		key |= 0x7fe0 & ((lp->lp_agrport->port_agrifp->if_index) << 5);
697 		/* bit 15:	0 */
698 	}
699 
700 	return htobe16(key);
701 }
702