xref: /openbsd/sys/net/trunklacp.c (revision a6445c1d)
1 /*	$OpenBSD: trunklacp.c,v 1.17 2014/11/23 07:39:02 deraadt Exp $ */
2 /*	$NetBSD: ieee8023ad_lacp.c,v 1.3 2005/12/11 12:24:54 christos Exp $ */
3 /*	$FreeBSD:ieee8023ad_lacp.c,v 1.15 2008/03/16 19:25:30 thompsa Exp $ */
4 
5 /*
6  * Copyright (c)2005 YAMAMOTO Takashi,
7  * Copyright (c)2008 Andrew Thompson <thompsa@FreeBSD.org>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/mbuf.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/lock.h>
40 #include <sys/rwlock.h>
41 #include <sys/queue.h>
42 #include <sys/timeout.h>
43 
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <net/ethertypes.h>
47 #include <net/if_media.h>
48 #include <net/if_types.h>
49 
50 #include <netinet/in.h>
51 #include <netinet/if_ether.h>
52 
53 #include "if_trunk.h"
54 #include "trunklacp.h"
55 
56 /*
57  * actor system priority and port priority.
58  * XXX should be configurable.
59  */
60 #define	LACP_SYSTEM_PRIO	0x8000
61 #define	LACP_PORT_PRIO		0x8000
62 #define	LACP_IFQ_PRIO		6
63 
64 const u_int8_t ethermulticastaddr_slowprotocols[ETHER_ADDR_LEN] =
65     { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
66 
67 const struct tlv_template lacp_info_tlv_template[] = {
68 	{ LACP_TYPE_ACTORINFO,
69 	    sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) },
70 	{ LACP_TYPE_PARTNERINFO,
71 	    sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) },
72 	{ LACP_TYPE_COLLECTORINFO,
73 	    sizeof(struct tlvhdr) + sizeof(struct lacp_collectorinfo) },
74 	{ 0, 0 },
75 };
76 
77 const struct tlv_template marker_info_tlv_template[] = {
78 	{ MARKER_TYPE_INFO,
79 	    sizeof(struct tlvhdr) + sizeof(struct lacp_markerinfo) },
80 	{ 0, 0 },
81 };
82 
83 const struct tlv_template marker_response_tlv_template[] = {
84 	{ MARKER_TYPE_RESPONSE,
85 	    sizeof(struct tlvhdr) + sizeof(struct lacp_markerinfo) },
86 	{ 0, 0 },
87 };
88 
89 typedef void (*lacp_timer_func_t)(struct lacp_port *);
90 
91 void		lacp_fill_actorinfo(struct lacp_port *, struct lacp_peerinfo *);
92 void		lacp_fill_markerinfo(struct lacp_port *,
93 		    struct lacp_markerinfo *);
94 
95 u_int64_t	lacp_aggregator_bandwidth(struct lacp_aggregator *);
96 void		lacp_suppress_distributing(struct lacp_softc *,
97 		    struct lacp_aggregator *);
98 void		lacp_transit_expire(void *);
99 void		lacp_update_portmap(struct lacp_softc *);
100 void		lacp_select_active_aggregator(struct lacp_softc *);
101 u_int16_t	lacp_compose_key(struct lacp_port *);
102 int		tlv_check(const void *, size_t, const struct tlvhdr *,
103 		    const struct tlv_template *, int);
104 void		lacp_tick(void *);
105 
106 void		lacp_fill_aggregator_id(struct lacp_aggregator *,
107 		    const struct lacp_port *);
108 void		lacp_fill_aggregator_id_peer(struct lacp_peerinfo *,
109 		    const struct lacp_peerinfo *);
110 int		lacp_aggregator_is_compatible(const struct lacp_aggregator *,
111 		    const struct lacp_port *);
112 int		lacp_peerinfo_is_compatible(const struct lacp_peerinfo *,
113 		    const struct lacp_peerinfo *);
114 
115 struct lacp_aggregator *lacp_aggregator_get(struct lacp_softc *,
116 		    struct lacp_port *);
117 void		lacp_aggregator_addref(struct lacp_softc *,
118 		    struct lacp_aggregator *);
119 void		lacp_aggregator_delref(struct lacp_softc *,
120 		    struct lacp_aggregator *);
121 
122 /* receive machine */
123 
124 int		lacp_pdu_input(struct lacp_port *,
125 		    struct ether_header *, struct mbuf *);
126 int		lacp_marker_input(struct lacp_port *,
127 		    struct ether_header *, struct mbuf *);
128 void		lacp_sm_rx(struct lacp_port *, const struct lacpdu *);
129 void		lacp_sm_rx_timer(struct lacp_port *);
130 void		lacp_sm_rx_set_expired(struct lacp_port *);
131 void		lacp_sm_rx_update_ntt(struct lacp_port *,
132 		    const struct lacpdu *);
133 void		lacp_sm_rx_record_pdu(struct lacp_port *,
134 		    const struct lacpdu *);
135 void		lacp_sm_rx_update_selected(struct lacp_port *,
136 		    const struct lacpdu *);
137 void		lacp_sm_rx_record_default(struct lacp_port *);
138 void		lacp_sm_rx_update_default_selected(struct lacp_port *);
139 void		lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *,
140 		    const struct lacp_peerinfo *);
141 
142 /* mux machine */
143 
144 void		lacp_sm_mux(struct lacp_port *);
145 void		lacp_set_mux(struct lacp_port *, enum lacp_mux_state);
146 void		lacp_sm_mux_timer(struct lacp_port *);
147 
148 /* periodic transmit machine */
149 
150 void		lacp_sm_ptx_update_timeout(struct lacp_port *, u_int8_t);
151 void		lacp_sm_ptx_tx_schedule(struct lacp_port *);
152 void		lacp_sm_ptx_timer(struct lacp_port *);
153 
154 /* transmit machine */
155 
156 void		lacp_sm_tx(struct lacp_port *);
157 void		lacp_sm_assert_ntt(struct lacp_port *);
158 
159 void		lacp_run_timers(struct lacp_port *);
160 int		lacp_compare_peerinfo(const struct lacp_peerinfo *,
161 		    const struct lacp_peerinfo *);
162 int		lacp_compare_systemid(const struct lacp_systemid *,
163 		    const struct lacp_systemid *);
164 void		lacp_port_enable(struct lacp_port *);
165 void		lacp_port_disable(struct lacp_port *);
166 void		lacp_select(struct lacp_port *);
167 void		lacp_unselect(struct lacp_port *);
168 void		lacp_disable_collecting(struct lacp_port *);
169 void		lacp_enable_collecting(struct lacp_port *);
170 void		lacp_disable_distributing(struct lacp_port *);
171 void		lacp_enable_distributing(struct lacp_port *);
172 int		lacp_xmit_lacpdu(struct lacp_port *);
173 int		lacp_xmit_marker(struct lacp_port *);
174 
175 #if defined(LACP_DEBUG)
176 void		lacp_dump_lacpdu(const struct lacpdu *);
177 const char	*lacp_format_partner(const struct lacp_peerinfo *, char *,
178 		    size_t);
179 const char	*lacp_format_lagid(const struct lacp_peerinfo *,
180 		    const struct lacp_peerinfo *, char *, size_t);
181 const char	*lacp_format_lagid_aggregator(const struct lacp_aggregator *,
182 		    char *, size_t);
183 const char	*lacp_format_state(u_int8_t, char *, size_t);
184 const char	*lacp_format_mac(const u_int8_t *, char *, size_t);
185 const char	*lacp_format_systemid(const struct lacp_systemid *, char *,
186 		    size_t);
187 const char	*lacp_format_portid(const struct lacp_portid *, char *,
188 		    size_t);
189 void		lacp_dprintf(const struct lacp_port *, const char *, ...)
190 		    __attribute__((__format__(__printf__, 2, 3)));
191 #define	LACP_DPRINTF(a)	lacp_dprintf a
192 #else
193 #define LACP_DPRINTF(a) /* nothing */
194 #endif
195 
196 /*
197  * partner administration variables.
198  * XXX should be configurable.
199  */
200 
201 const struct lacp_peerinfo lacp_partner_admin = {
202 	{ 0xffff },	/* lip_systemid.lsi_prio */
203 	0,		/* lip_key */
204 	{ 0xffff },	/* lip_portid.lpi_prio */
205 #if 1
206 	/* optimistic lip_state */
207 	LACP_STATE_SYNC | LACP_STATE_AGGREGATION |
208 	    LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING
209 #else
210 	/* pessimistic lip_state */
211 	0
212 #endif
213 };
214 
215 const lacp_timer_func_t lacp_timer_funcs[LACP_NTIMER] = {
216 	[LACP_TIMER_CURRENT_WHILE] = lacp_sm_rx_timer,
217 	[LACP_TIMER_PERIODIC] = lacp_sm_ptx_timer,
218 	[LACP_TIMER_WAIT_WHILE] = lacp_sm_mux_timer,
219 };
220 
221 struct mbuf *
222 lacp_input(struct trunk_port *tp, struct ether_header *eh, struct mbuf *m)
223 {
224 	struct lacp_port *lp = LACP_PORT(tp);
225 	struct lacp_softc *lsc = lp->lp_lsc;
226 	struct lacp_aggregator *la = lp->lp_aggregator;
227 	u_int8_t subtype;
228 
229 	if (ntohs(eh->ether_type) == ETHERTYPE_SLOW) {
230 		if (m->m_pkthdr.len < sizeof(subtype)) {
231 			m_freem(m);
232 			return (NULL);
233 		}
234 		subtype = *mtod(m, u_int8_t *);
235 
236 		switch (subtype) {
237 		case SLOWPROTOCOLS_SUBTYPE_LACP:
238 			lacp_pdu_input(lp, eh, m);
239 			return (NULL);
240 
241 		case SLOWPROTOCOLS_SUBTYPE_MARKER:
242 			lacp_marker_input(lp, eh, m);
243 			return (NULL);
244 		}
245 	}
246 
247 	/*
248 	 * If the port is not collecting or not in the active aggregator then
249 	 * free and return.
250 	 */
251 	/* This port is joined to the active aggregator */
252 	if ((lp->lp_state & LACP_STATE_COLLECTING) == 0 ||
253 	    la == NULL || la != lsc->lsc_active_aggregator) {
254 		m_freem(m);
255 		return (NULL);
256 	}
257 
258 	/* Not a subtype we are interested in */
259 	return (m);
260 }
261 
262 /*
263  * lacp_pdu_input: process lacpdu
264  */
265 int
266 lacp_pdu_input(struct lacp_port *lp, struct ether_header *eh, struct mbuf *m)
267 {
268 	struct lacpdu *du;
269 	int error = 0;
270 
271 	if (m->m_pkthdr.len != sizeof(*du))
272 		goto bad;
273 
274 	if (m->m_len < sizeof(*du)) {
275 		m = m_pullup(m, sizeof(*du));
276 		if (m == NULL) {
277 			return (ENOMEM);
278 		}
279 	}
280 	du = mtod(m, struct lacpdu *);
281 
282 	if (memcmp(&eh->ether_dhost,
283 	    &ethermulticastaddr_slowprotocols, ETHER_ADDR_LEN))
284 		goto bad;
285 
286 	/*
287 	 * ignore the version for compatibility with
288 	 * the future protocol revisions.
289 	 */
290 #if 0
291 	if (du->ldu_sph.sph_version != 1)
292 		goto bad;
293 #endif
294 
295 	/*
296 	 * ignore tlv types for compatibility with the
297 	 * future protocol revisions. (IEEE 802.3-2005 43.4.12)
298 	 */
299 	if (tlv_check(du, sizeof(*du), &du->ldu_tlv_actor,
300 	    lacp_info_tlv_template, 0))
301 		goto bad;
302 
303 #if defined(LACP_DEBUG)
304 	LACP_DPRINTF((lp, "lacpdu receive\n"));
305 	lacp_dump_lacpdu(du);
306 #endif /* defined(LACP_DEBUG) */
307 
308 	lacp_sm_rx(lp, du);
309 
310 	m_freem(m);
311 	return (error);
312 
313 bad:
314 	m_freem(m);
315 	return (EINVAL);
316 }
317 
318 void
319 lacp_fill_actorinfo(struct lacp_port *lp, struct lacp_peerinfo *info)
320 {
321 	struct trunk_port *tp = lp->lp_trunk;
322 	struct trunk_softc *sc = tp->tp_trunk;
323 
324 	info->lip_systemid.lsi_prio = htons(LACP_SYSTEM_PRIO);
325 	memcpy(&info->lip_systemid.lsi_mac,
326 	    sc->tr_ac.ac_enaddr, ETHER_ADDR_LEN);
327 	info->lip_portid.lpi_prio = htons(LACP_PORT_PRIO);
328 	info->lip_portid.lpi_portno = htons(lp->lp_ifp->if_index);
329 	info->lip_state = lp->lp_state;
330 }
331 
332 void
333 lacp_fill_markerinfo(struct lacp_port *lp, struct lacp_markerinfo *info)
334 {
335 	struct ifnet *ifp = lp->lp_ifp;
336 
337 	/* Fill in the port index and system id (encoded as the MAC) */
338 	info->mi_rq_port = htons(ifp->if_index);
339 	memcpy(&info->mi_rq_system, lp->lp_systemid.lsi_mac, ETHER_ADDR_LEN);
340 	info->mi_rq_xid = htonl(0);
341 }
342 
343 int
344 lacp_xmit_lacpdu(struct lacp_port *lp)
345 {
346 	struct trunk_port *tp = lp->lp_trunk;
347 	struct mbuf *m;
348 	struct ether_header *eh;
349 	struct lacpdu *du;
350 	int error, s;
351 
352 	m = m_gethdr(M_DONTWAIT, MT_DATA);
353 	if (m == NULL)
354 		return (ENOMEM);
355 	m->m_len = m->m_pkthdr.len = sizeof(*eh) + sizeof(*du);
356 	m->m_pkthdr.pf.prio = LACP_IFQ_PRIO;
357 
358 	eh = mtod(m, struct ether_header *);
359 	memcpy(&eh->ether_dhost, ethermulticastaddr_slowprotocols,
360 	    ETHER_ADDR_LEN);
361 	memcpy(&eh->ether_shost, tp->tp_lladdr, ETHER_ADDR_LEN);
362 	eh->ether_type = htons(ETHERTYPE_SLOW);
363 
364 	m->m_data += sizeof(*eh);
365 	du = mtod(m, struct lacpdu *);
366 	m->m_data -= sizeof(*eh);
367 
368 	memset(du, 0, sizeof(*du));
369 
370 	du->ldu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_LACP;
371 	du->ldu_sph.sph_version = 1;
372 
373 	TLV_SET(&du->ldu_tlv_actor, LACP_TYPE_ACTORINFO, sizeof(du->ldu_actor));
374 	du->ldu_actor = lp->lp_actor;
375 
376 	TLV_SET(&du->ldu_tlv_partner, LACP_TYPE_PARTNERINFO,
377 	    sizeof(du->ldu_partner));
378 	du->ldu_partner = lp->lp_partner;
379 
380 	TLV_SET(&du->ldu_tlv_collector, LACP_TYPE_COLLECTORINFO,
381 	    sizeof(du->ldu_collector));
382 	du->ldu_collector.lci_maxdelay = 0;
383 
384 #if defined(LACP_DEBUG)
385 	LACP_DPRINTF((lp, "lacpdu transmit\n"));
386 	lacp_dump_lacpdu(du);
387 #endif /* defined(LACP_DEBUG) */
388 
389 	m->m_flags |= M_MCAST;
390 
391 	/*
392 	 * XXX should use higher priority queue.
393 	 * otherwise network congestion can break aggregation.
394 	 */
395 	s = splnet();
396 	error = trunk_enqueue(lp->lp_ifp, m);
397 	splx(s);
398 	return (error);
399 }
400 
401 int
402 lacp_xmit_marker(struct lacp_port *lp)
403 {
404 	struct trunk_port *tp = lp->lp_trunk;
405 	struct mbuf *m;
406 	struct ether_header *eh;
407 	struct markerdu *mdu;
408 	int error, s;
409 
410 	m = m_gethdr(M_DONTWAIT, MT_DATA);
411 	if (m == NULL)
412 		return (ENOMEM);
413 	m->m_len = m->m_pkthdr.len = sizeof(*eh) + sizeof(*mdu);
414 	m->m_pkthdr.pf.prio = LACP_IFQ_PRIO;
415 
416 	eh = mtod(m, struct ether_header *);
417 	memcpy(&eh->ether_dhost, ethermulticastaddr_slowprotocols,
418 	    ETHER_ADDR_LEN);
419 	memcpy(&eh->ether_shost, tp->tp_lladdr, ETHER_ADDR_LEN);
420 	eh->ether_type = htons(ETHERTYPE_SLOW);
421 
422 	m->m_data += sizeof(*eh);
423 	mdu = mtod(m, struct markerdu *);
424 	m->m_data -= sizeof(*eh);
425 
426 	memset(mdu, 0, sizeof(*mdu));
427 
428 	mdu->mdu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_MARKER;
429 	mdu->mdu_sph.sph_version = 1;
430 
431 	/* Bump the transaction id and copy over the marker info */
432 	lp->lp_marker.mi_rq_xid = htonl(ntohl(lp->lp_marker.mi_rq_xid) + 1);
433 	TLV_SET(&mdu->mdu_tlv, MARKER_TYPE_INFO, sizeof(mdu->mdu_info));
434 	mdu->mdu_info = lp->lp_marker;
435 
436 	LACP_DPRINTF((lp, "marker transmit, port=%u, sys=%6D, id=%u\n",
437 	    ntohs(mdu->mdu_info.mi_rq_port), mdu->mdu_info.mi_rq_system, ":",
438 	    ntohl(mdu->mdu_info.mi_rq_xid)));
439 
440 	m->m_flags |= M_MCAST;
441 	s = splnet();
442 	error = trunk_enqueue(lp->lp_ifp, m);
443 	splx(s);
444 	return (error);
445 }
446 
447 void
448 lacp_linkstate(struct trunk_port *tp)
449 {
450 	struct lacp_port *lp = LACP_PORT(tp);
451 	u_int8_t old_state;
452 	u_int16_t old_key;
453 
454 	old_state = lp->lp_state;
455 	old_key = lp->lp_key;
456 
457 	/*
458 	 * If the port is not an active full duplex Ethernet link then it can
459 	 * not be aggregated.
460 	 */
461 	if (tp->tp_link_state == LINK_STATE_UNKNOWN ||
462 	    tp->tp_link_state == LINK_STATE_FULL_DUPLEX)
463 		lacp_port_enable(lp);
464 	else
465 		lacp_port_disable(lp);
466 
467 	lp->lp_key = lacp_compose_key(lp);
468 
469 	if (old_state != lp->lp_state || old_key != lp->lp_key) {
470 		LACP_DPRINTF((lp, "-> UNSELECTED\n"));
471 		lp->lp_selected = LACP_UNSELECTED;
472 	}
473 }
474 
475 void
476 lacp_tick(void *arg)
477 {
478 	struct lacp_softc *lsc = arg;
479 	struct lacp_port *lp;
480 
481 	LIST_FOREACH(lp, &lsc->lsc_ports, lp_next) {
482 		if ((lp->lp_state & LACP_STATE_AGGREGATION) == 0)
483 			continue;
484 
485 		lacp_run_timers(lp);
486 
487 		lacp_select(lp);
488 		lacp_sm_mux(lp);
489 		lacp_sm_tx(lp);
490 		lacp_sm_ptx_tx_schedule(lp);
491 	}
492 	timeout_add_sec(&lsc->lsc_callout, 1);
493 }
494 
495 int
496 lacp_port_create(struct trunk_port *tp)
497 {
498 	struct trunk_softc *sc = tp->tp_trunk;
499 	struct lacp_softc *lsc = LACP_SOFTC(sc);
500 	struct lacp_port *lp;
501 	struct ifnet *ifp = tp->tp_if;
502 	struct ifreq ifr;
503 	int error;
504 
505 	int active = 1; /* XXX should be configurable */
506 	int fast = 0; /* XXX should be configurable */
507 
508 	bzero(&ifr, sizeof(ifr));
509 	ifr.ifr_addr.sa_family = AF_UNSPEC;
510 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
511 	bcopy(&ethermulticastaddr_slowprotocols,
512 	    ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
513 
514 	error = ether_addmulti(&ifr, (struct arpcom *)ifp);
515 	if (error && error != ENETRESET) {
516 		printf("%s: ADDMULTI failed on %s\n", __func__, tp->tp_ifname);
517 		return (error);
518 	}
519 
520 	lp = malloc(sizeof(struct lacp_port),
521 	    M_DEVBUF, M_NOWAIT|M_ZERO);
522 	if (lp == NULL)
523 		return (ENOMEM);
524 
525 	tp->tp_psc = (caddr_t)lp;
526 	lp->lp_ifp = ifp;
527 	lp->lp_trunk = tp;
528 	lp->lp_lsc = lsc;
529 
530 	LIST_INSERT_HEAD(&lsc->lsc_ports, lp, lp_next);
531 
532 	lacp_fill_actorinfo(lp, &lp->lp_actor);
533 	lacp_fill_markerinfo(lp, &lp->lp_marker);
534 	lp->lp_state =
535 	    (active ? LACP_STATE_ACTIVITY : 0) |
536 	    (fast ? LACP_STATE_TIMEOUT : 0);
537 	lp->lp_aggregator = NULL;
538 	lacp_sm_rx_set_expired(lp);
539 
540 	lacp_linkstate(tp);
541 
542 	return (0);
543 }
544 
545 void
546 lacp_port_destroy(struct trunk_port *tp)
547 {
548 	struct lacp_port *lp = LACP_PORT(tp);
549 	int i;
550 
551 	for (i = 0; i < LACP_NTIMER; i++)
552 		LACP_TIMER_DISARM(lp, i);
553 
554 	lacp_disable_collecting(lp);
555 	lacp_disable_distributing(lp);
556 	lacp_unselect(lp);
557 
558 	LIST_REMOVE(lp, lp_next);
559 	free(lp, M_DEVBUF, sizeof(*lp));
560 }
561 
562 void
563 lacp_req(struct trunk_softc *sc, caddr_t data)
564 {
565 	struct lacp_opreq *req = (struct lacp_opreq *)data;
566 	struct lacp_softc *lsc = LACP_SOFTC(sc);
567 	struct lacp_aggregator *la = lsc->lsc_active_aggregator;
568 
569 	bzero(req, sizeof(struct lacp_opreq));
570 	if (la != NULL) {
571 		req->actor_prio = ntohs(la->la_actor.lip_systemid.lsi_prio);
572 		memcpy(&req->actor_mac, &la->la_actor.lip_systemid.lsi_mac,
573 		    ETHER_ADDR_LEN);
574 		req->actor_key = ntohs(la->la_actor.lip_key);
575 		req->actor_portprio = ntohs(la->la_actor.lip_portid.lpi_prio);
576 		req->actor_portno = ntohs(la->la_actor.lip_portid.lpi_portno);
577 		req->actor_state = la->la_actor.lip_state;
578 
579 		req->partner_prio = ntohs(la->la_partner.lip_systemid.lsi_prio);
580 		memcpy(&req->partner_mac, &la->la_partner.lip_systemid.lsi_mac,
581 		    ETHER_ADDR_LEN);
582 		req->partner_key = ntohs(la->la_partner.lip_key);
583 		req->partner_portprio =
584 		    ntohs(la->la_partner.lip_portid.lpi_prio);
585 		req->partner_portno =
586 		    ntohs(la->la_partner.lip_portid.lpi_portno);
587 		req->partner_state = la->la_partner.lip_state;
588 	}
589 }
590 
591 u_int
592 lacp_port_status(struct trunk_port *lgp)
593 {
594 	struct lacp_port	*lp = LACP_PORT(lgp);
595 	struct lacp_softc	*lsc = lp->lp_lsc;
596 	struct lacp_aggregator	*la = lp->lp_aggregator;
597 	u_int			 flags = 0;
598 
599 	/* This port is joined to the active aggregator */
600 	if (la != NULL && la == lsc->lsc_active_aggregator)
601 		flags |= TRUNK_PORT_ACTIVE;
602 
603 	if (lp->lp_state & LACP_STATE_COLLECTING)
604 		flags |= TRUNK_PORT_COLLECTING;
605 	if (lp->lp_state & LACP_STATE_DISTRIBUTING)
606 		flags |= TRUNK_PORT_DISTRIBUTING;
607 
608 	return (flags);
609 }
610 
611 void
612 lacp_portreq(struct trunk_port *tp, caddr_t data)
613 {
614 	struct lacp_opreq *req = (struct lacp_opreq *)data;
615 	struct lacp_port *lp = LACP_PORT(tp);
616 
617 	req->actor_prio = ntohs(lp->lp_actor.lip_systemid.lsi_prio);
618 	memcpy(&req->actor_mac, &lp->lp_actor.lip_systemid.lsi_mac,
619 	    ETHER_ADDR_LEN);
620 	req->actor_key = ntohs(lp->lp_actor.lip_key);
621 	req->actor_portprio = ntohs(lp->lp_actor.lip_portid.lpi_prio);
622 	req->actor_portno = ntohs(lp->lp_actor.lip_portid.lpi_portno);
623 	req->actor_state = lp->lp_actor.lip_state;
624 
625 	req->partner_prio = ntohs(lp->lp_partner.lip_systemid.lsi_prio);
626 	memcpy(&req->partner_mac, &lp->lp_partner.lip_systemid.lsi_mac,
627 	    ETHER_ADDR_LEN);
628 	req->partner_key = ntohs(lp->lp_partner.lip_key);
629 	req->partner_portprio = ntohs(lp->lp_partner.lip_portid.lpi_prio);
630 	req->partner_portno = ntohs(lp->lp_partner.lip_portid.lpi_portno);
631 	req->partner_state = lp->lp_partner.lip_state;
632 }
633 
634 void
635 lacp_disable_collecting(struct lacp_port *lp)
636 {
637 	LACP_DPRINTF((lp, "collecting disabled\n"));
638 	lp->lp_state &= ~LACP_STATE_COLLECTING;
639 }
640 
641 void
642 lacp_enable_collecting(struct lacp_port *lp)
643 {
644 	LACP_DPRINTF((lp, "collecting enabled\n"));
645 	lp->lp_state |= LACP_STATE_COLLECTING;
646 }
647 
648 void
649 lacp_disable_distributing(struct lacp_port *lp)
650 {
651 	struct lacp_aggregator *la = lp->lp_aggregator;
652 	struct lacp_softc *lsc = lp->lp_lsc;
653 #if defined(LACP_DEBUG)
654 	char buf[LACP_LAGIDSTR_MAX+1];
655 #endif /* defined(LACP_DEBUG) */
656 
657 	if (la == NULL || (lp->lp_state & LACP_STATE_DISTRIBUTING) == 0)
658 		return;
659 
660 	KASSERT(!TAILQ_EMPTY(&la->la_ports));
661 	KASSERT(la->la_nports > 0);
662 	KASSERT(la->la_refcnt >= la->la_nports);
663 
664 	LACP_DPRINTF((lp, "disable distributing on aggregator %s, "
665 	    "nports %d -> %d\n",
666 	    lacp_format_lagid_aggregator(la, buf, sizeof(buf)),
667 	    la->la_nports, la->la_nports - 1));
668 
669 	TAILQ_REMOVE(&la->la_ports, lp, lp_dist_q);
670 	la->la_nports--;
671 
672 	if (lsc->lsc_active_aggregator == la) {
673 		lacp_suppress_distributing(lsc, la);
674 		lacp_select_active_aggregator(lsc);
675 		/* regenerate the port map, the active aggregator has changed */
676 		lacp_update_portmap(lsc);
677 	}
678 
679 	lp->lp_state &= ~LACP_STATE_DISTRIBUTING;
680 }
681 
682 void
683 lacp_enable_distributing(struct lacp_port *lp)
684 {
685 	struct lacp_aggregator *la = lp->lp_aggregator;
686 	struct lacp_softc *lsc = lp->lp_lsc;
687 #if defined(LACP_DEBUG)
688 	char buf[LACP_LAGIDSTR_MAX+1];
689 #endif /* defined(LACP_DEBUG) */
690 
691 	if ((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0)
692 		return;
693 
694 	LACP_DPRINTF((lp, "enable distributing on aggregator %s, "
695 	    "nports %d -> %d\n",
696 	    lacp_format_lagid_aggregator(la, buf, sizeof(buf)),
697 	    la->la_nports, la->la_nports + 1));
698 
699 	KASSERT(la->la_refcnt > la->la_nports);
700 	TAILQ_INSERT_HEAD(&la->la_ports, lp, lp_dist_q);
701 	la->la_nports++;
702 
703 	lp->lp_state |= LACP_STATE_DISTRIBUTING;
704 
705 	if (lsc->lsc_active_aggregator == la) {
706 		lacp_suppress_distributing(lsc, la);
707 		lacp_update_portmap(lsc);
708 	} else
709 		/* try to become the active aggregator */
710 		lacp_select_active_aggregator(lsc);
711 }
712 
713 void
714 lacp_transit_expire(void *vp)
715 {
716 	struct lacp_softc *lsc = vp;
717 
718 	LACP_DPRINTF((NULL, "%s\n", __func__));
719 	lsc->lsc_suppress_distributing = 0;
720 }
721 
722 int
723 lacp_attach(struct trunk_softc *sc)
724 {
725 	struct lacp_softc *lsc;
726 
727 	lsc = malloc(sizeof(struct lacp_softc),
728 	    M_DEVBUF, M_NOWAIT|M_ZERO);
729 	if (lsc == NULL)
730 		return (ENOMEM);
731 
732 	sc->tr_psc = (caddr_t)lsc;
733 	lsc->lsc_softc = sc;
734 
735 	lsc->lsc_hashkey = arc4random();
736 	lsc->lsc_active_aggregator = NULL;
737 	TAILQ_INIT(&lsc->lsc_aggregators);
738 	LIST_INIT(&lsc->lsc_ports);
739 
740 	timeout_set(&lsc->lsc_transit_callout, lacp_transit_expire, lsc);
741 	timeout_set(&lsc->lsc_callout, lacp_tick, lsc);
742 
743 	/* if the trunk is already up then do the same */
744 	if (sc->tr_ac.ac_if.if_flags & IFF_RUNNING)
745 		lacp_init(sc);
746 
747 	return (0);
748 }
749 
750 int
751 lacp_detach(struct trunk_softc *sc)
752 {
753 	struct lacp_softc *lsc = LACP_SOFTC(sc);
754 
755 	KASSERT(TAILQ_EMPTY(&lsc->lsc_aggregators));
756 	KASSERT(lsc->lsc_active_aggregator == NULL);
757 
758 	sc->tr_psc = NULL;
759 	timeout_del(&lsc->lsc_transit_callout);
760 	timeout_del(&lsc->lsc_callout);
761 
762 	free(lsc, M_DEVBUF, sizeof(*lsc));
763 	return (0);
764 }
765 
766 void
767 lacp_init(struct trunk_softc *sc)
768 {
769 	struct lacp_softc *lsc = LACP_SOFTC(sc);
770 
771 	timeout_add_sec(&lsc->lsc_callout, 1);
772 }
773 
774 void
775 lacp_stop(struct trunk_softc *sc)
776 {
777 	struct lacp_softc *lsc = LACP_SOFTC(sc);
778 
779 	timeout_del(&lsc->lsc_transit_callout);
780 	timeout_del(&lsc->lsc_callout);
781 }
782 
783 struct trunk_port *
784 lacp_select_tx_port(struct trunk_softc *sc, struct mbuf *m)
785 {
786 	struct lacp_softc *lsc = LACP_SOFTC(sc);
787 	struct lacp_portmap *pm;
788 	struct lacp_port *lp;
789 	u_int32_t hash;
790 
791 	if (__predict_false(lsc->lsc_suppress_distributing)) {
792 		LACP_DPRINTF((NULL, "%s: waiting transit\n", __func__));
793 		return (NULL);
794 	}
795 
796 	pm = &lsc->lsc_pmap[lsc->lsc_activemap];
797 	if (pm->pm_count == 0) {
798 		LACP_DPRINTF((NULL, "%s: no active aggregator\n", __func__));
799 		return (NULL);
800 	}
801 
802 	hash = trunk_hashmbuf(m, lsc->lsc_hashkey);
803 	hash %= pm->pm_count;
804 	lp = pm->pm_map[hash];
805 
806 	KASSERT((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0);
807 
808 	return (lp->lp_trunk);
809 }
810 
811 /*
812  * lacp_suppress_distributing: drop transmit packets for a while
813  * to preserve packet ordering.
814  */
815 void
816 lacp_suppress_distributing(struct lacp_softc *lsc, struct lacp_aggregator *la)
817 {
818 	struct lacp_port *lp;
819 
820 	if (lsc->lsc_active_aggregator != la)
821 		return;
822 
823 	LACP_DPRINTF((NULL, "%s\n", __func__));
824 	lsc->lsc_suppress_distributing = 1;
825 
826 	/* send a marker frame down each port to verify the queues are empty */
827 	LIST_FOREACH(lp, &lsc->lsc_ports, lp_next) {
828 		lp->lp_flags |= LACP_PORT_MARK;
829 		lacp_xmit_marker(lp);
830 	}
831 
832 	/* set a timeout for the marker frames */
833 	timeout_add_msec(&lsc->lsc_transit_callout, LACP_TRANSIT_DELAY);
834 }
835 
836 int
837 lacp_compare_peerinfo(const struct lacp_peerinfo *a,
838     const struct lacp_peerinfo *b)
839 {
840 	return (memcmp(a, b, offsetof(struct lacp_peerinfo, lip_state)));
841 }
842 
843 int
844 lacp_compare_systemid(const struct lacp_systemid *a,
845     const struct lacp_systemid *b)
846 {
847 	return (memcmp(a, b, sizeof(*a)));
848 }
849 
850 #if 0	/* unused */
851 int
852 lacp_compare_portid(const struct lacp_portid *a,
853     const struct lacp_portid *b)
854 {
855 	return (memcmp(a, b, sizeof(*a)));
856 }
857 #endif
858 
859 u_int64_t
860 lacp_aggregator_bandwidth(struct lacp_aggregator *la)
861 {
862 	struct lacp_port *lp;
863 	u_int64_t speed;
864 
865 	lp = TAILQ_FIRST(&la->la_ports);
866 	if (lp == NULL)
867 		return (0);
868 
869 	speed = lp->lp_ifp->if_baudrate;
870 	speed *= la->la_nports;
871 	if (speed == 0) {
872 		LACP_DPRINTF((lp, "speed 0? media=0x%x nports=%d\n",
873 		    lp->lp_media, la->la_nports));
874 	}
875 
876 	return (speed);
877 }
878 
879 /*
880  * lacp_select_active_aggregator: select an aggregator to be used to transmit
881  * packets from trunk(4) interface.
882  */
883 void
884 lacp_select_active_aggregator(struct lacp_softc *lsc)
885 {
886 	struct lacp_aggregator *la;
887 	struct lacp_aggregator *best_la = NULL;
888 	u_int64_t best_speed = 0;
889 #if defined(LACP_DEBUG)
890 	char buf[LACP_LAGIDSTR_MAX+1];
891 #endif /* defined(LACP_DEBUG) */
892 
893 	LACP_DPRINTF((NULL, "%s:\n", __func__));
894 
895 	TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) {
896 		u_int64_t speed;
897 
898 		if (la->la_nports == 0)
899 			continue;
900 
901 		speed = lacp_aggregator_bandwidth(la);
902 		LACP_DPRINTF((NULL, "%s, speed=%jd, nports=%d\n",
903 		    lacp_format_lagid_aggregator(la, buf, sizeof(buf)),
904 		    speed, la->la_nports));
905 
906 		/*
907 		 * This aggregator is chosen if
908 		 *      the partner has a better system priority
909 		 *  or, the total aggregated speed is higher
910 		 *  or, it is already the chosen aggregator
911 		 */
912 		if ((best_la != NULL && LACP_SYS_PRI(la->la_partner) <
913 		     LACP_SYS_PRI(best_la->la_partner)) ||
914 		    speed > best_speed ||
915 		    (speed == best_speed &&
916 		    la == lsc->lsc_active_aggregator)) {
917 			best_la = la;
918 			best_speed = speed;
919 		}
920 	}
921 
922 	KASSERT(best_la == NULL || best_la->la_nports > 0);
923 	KASSERT(best_la == NULL || !TAILQ_EMPTY(&best_la->la_ports));
924 
925 #if defined(LACP_DEBUG)
926 	if (lsc->lsc_active_aggregator != best_la) {
927 		LACP_DPRINTF((NULL, "active aggregator changed\n"));
928 		LACP_DPRINTF((NULL, "old %s\n",
929 		    lacp_format_lagid_aggregator(lsc->lsc_active_aggregator,
930 		    buf, sizeof(buf))));
931 	} else
932 		LACP_DPRINTF((NULL, "active aggregator not changed\n"));
933 
934 	LACP_DPRINTF((NULL, "new %s\n",
935 	    lacp_format_lagid_aggregator(best_la, buf, sizeof(buf))));
936 #endif /* defined(LACP_DEBUG) */
937 
938 	if (lsc->lsc_active_aggregator != best_la) {
939 		lsc->lsc_active_aggregator = best_la;
940 		lacp_update_portmap(lsc);
941 		if (best_la)
942 			lacp_suppress_distributing(lsc, best_la);
943 	}
944 }
945 
946 /*
947  * Updated the inactive portmap array with the new list of ports and
948  * make it live.
949  */
950 void
951 lacp_update_portmap(struct lacp_softc *lsc)
952 {
953 	struct lacp_aggregator *la;
954 	struct lacp_portmap *p;
955 	struct lacp_port *lp;
956 	u_int newmap;
957 	int i;
958 
959 	newmap = lsc->lsc_activemap == 0 ? 1 : 0;
960 	p = &lsc->lsc_pmap[newmap];
961 	la = lsc->lsc_active_aggregator;
962 	bzero(p, sizeof(struct lacp_portmap));
963 
964 	if (la != NULL && la->la_nports > 0) {
965 		p->pm_count = la->la_nports;
966 		i = 0;
967 		TAILQ_FOREACH(lp, &la->la_ports, lp_dist_q)
968 			p->pm_map[i++] = lp;
969 		KASSERT(i == p->pm_count);
970 	}
971 
972 	/* switch the active portmap over */
973 	lsc->lsc_activemap = newmap;
974 	LACP_DPRINTF((NULL, "Set table %d with %d ports\n",
975 		    lsc->lsc_activemap,
976 		    lsc->lsc_pmap[lsc->lsc_activemap].pm_count));
977 }
978 
979 u_int16_t
980 lacp_compose_key(struct lacp_port *lp)
981 {
982 	struct trunk_port *tp = lp->lp_trunk;
983 	struct trunk_softc *sc = tp->tp_trunk;
984 	u_int64_t speed;
985 	u_int16_t key;
986 
987 	if ((lp->lp_state & LACP_STATE_AGGREGATION) == 0) {
988 		/* bit 0..14: (some bits of) if_index of this port */
989 		key = lp->lp_ifp->if_index;
990 
991 		/* non-aggregatable */
992 		key |= 0x8000;
993 	} else {
994 		/* bit 0..2: speed indication */
995 		speed = lp->lp_ifp->if_baudrate;
996 		if (speed == 0)
997 			key = 0;
998 		else if (speed <= IF_Mbps(1))
999 			key = 1;
1000 		else if (speed <= IF_Mbps(10))
1001 			key = 2;
1002 		else if (speed <= IF_Mbps(100))
1003 			key = 3;
1004 		else if (speed <= IF_Gbps(1))
1005 			key = 4;
1006 		else if (speed <= IF_Gbps(10))
1007 			key = 5;
1008 		else if (speed <= IF_Gbps(100))
1009 			key = 6;
1010 		else
1011 			key = 7;
1012 
1013 		/* bit 3..13: (some bits of) if_index of the trunk device */
1014 		key |= sc->tr_ac.ac_if.if_index << 3;
1015 
1016 		/* bit 14: the port active flag (includes link state) */
1017 		if (TRUNK_PORTACTIVE(tp))
1018 			key |= 0x4000;
1019 		else
1020 			key &= ~0x4000;
1021 
1022 		/* clear the non-aggregatable bit */
1023 		key &= ~0x8000;
1024 	}
1025 	return (htons(key));
1026 }
1027 
1028 void
1029 lacp_aggregator_addref(struct lacp_softc *lsc, struct lacp_aggregator *la)
1030 {
1031 #if defined(LACP_DEBUG)
1032 	char buf[LACP_LAGIDSTR_MAX+1];
1033 #endif
1034 
1035 	LACP_DPRINTF((NULL, "%s: lagid=%s, refcnt %d -> %d\n",
1036 	    __func__,
1037 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
1038 	    buf, sizeof(buf)),
1039 	    la->la_refcnt, la->la_refcnt + 1));
1040 
1041 	KASSERT(la->la_refcnt > 0);
1042 	la->la_refcnt++;
1043 	KASSERT(la->la_refcnt > la->la_nports);
1044 }
1045 
1046 void
1047 lacp_aggregator_delref(struct lacp_softc *lsc, struct lacp_aggregator *la)
1048 {
1049 #if defined(LACP_DEBUG)
1050 	char buf[LACP_LAGIDSTR_MAX+1];
1051 #endif
1052 
1053 	LACP_DPRINTF((NULL, "%s: lagid=%s, refcnt %d -> %d\n",
1054 	    __func__,
1055 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
1056 	    buf, sizeof(buf)),
1057 	    la->la_refcnt, la->la_refcnt - 1));
1058 
1059 	KASSERT(la->la_refcnt > la->la_nports);
1060 	la->la_refcnt--;
1061 	if (la->la_refcnt > 0)
1062 		return;
1063 
1064 	KASSERT(la->la_refcnt == 0);
1065 	KASSERT(lsc->lsc_active_aggregator != la);
1066 
1067 	TAILQ_REMOVE(&lsc->lsc_aggregators, la, la_q);
1068 
1069 	free(la, M_DEVBUF, sizeof(*la));
1070 }
1071 
1072 /*
1073  * lacp_aggregator_get: allocate an aggregator.
1074  */
1075 struct lacp_aggregator *
1076 lacp_aggregator_get(struct lacp_softc *lsc, struct lacp_port *lp)
1077 {
1078 	struct lacp_aggregator *la;
1079 
1080 	la = malloc(sizeof(*la), M_DEVBUF, M_NOWAIT);
1081 	if (la) {
1082 		la->la_refcnt = 1;
1083 		la->la_nports = 0;
1084 		TAILQ_INIT(&la->la_ports);
1085 		la->la_pending = 0;
1086 		TAILQ_INSERT_TAIL(&lsc->lsc_aggregators, la, la_q);
1087 	}
1088 
1089 	return (la);
1090 }
1091 
1092 /*
1093  * lacp_fill_aggregator_id: setup a newly allocated aggregator from a port.
1094  */
1095 void
1096 lacp_fill_aggregator_id(struct lacp_aggregator *la, const struct lacp_port *lp)
1097 {
1098 	lacp_fill_aggregator_id_peer(&la->la_partner, &lp->lp_partner);
1099 	lacp_fill_aggregator_id_peer(&la->la_actor, &lp->lp_actor);
1100 
1101 	la->la_actor.lip_state = lp->lp_state & LACP_STATE_AGGREGATION;
1102 }
1103 
1104 void
1105 lacp_fill_aggregator_id_peer(struct lacp_peerinfo *lpi_aggr,
1106     const struct lacp_peerinfo *lpi_port)
1107 {
1108 	memset(lpi_aggr, 0, sizeof(*lpi_aggr));
1109 	lpi_aggr->lip_systemid = lpi_port->lip_systemid;
1110 	lpi_aggr->lip_key = lpi_port->lip_key;
1111 }
1112 
1113 /*
1114  * lacp_aggregator_is_compatible: check if a port can join to an aggregator.
1115  */
1116 int
1117 lacp_aggregator_is_compatible(const struct lacp_aggregator *la,
1118     const struct lacp_port *lp)
1119 {
1120 	if (!(lp->lp_state & LACP_STATE_AGGREGATION) ||
1121 	    !(lp->lp_partner.lip_state & LACP_STATE_AGGREGATION))
1122 		return (0);
1123 
1124 	if (!(la->la_actor.lip_state & LACP_STATE_AGGREGATION))
1125 		return (0);
1126 
1127 	if (!lacp_peerinfo_is_compatible(&la->la_partner, &lp->lp_partner))
1128 		return (0);
1129 
1130 	if (!lacp_peerinfo_is_compatible(&la->la_actor, &lp->lp_actor))
1131 		return (0);
1132 
1133 	return (1);
1134 }
1135 
1136 int
1137 lacp_peerinfo_is_compatible(const struct lacp_peerinfo *a,
1138     const struct lacp_peerinfo *b)
1139 {
1140 	if (memcmp(&a->lip_systemid, &b->lip_systemid,
1141 	    sizeof(a->lip_systemid)))
1142 		return (0);
1143 
1144 	if (memcmp(&a->lip_key, &b->lip_key, sizeof(a->lip_key)))
1145 		return (0);
1146 
1147 	return (1);
1148 }
1149 
1150 void
1151 lacp_port_enable(struct lacp_port *lp)
1152 {
1153 	lp->lp_state |= LACP_STATE_AGGREGATION;
1154 }
1155 
1156 void
1157 lacp_port_disable(struct lacp_port *lp)
1158 {
1159 	lacp_set_mux(lp, LACP_MUX_DETACHED);
1160 
1161 	lp->lp_state &= ~LACP_STATE_AGGREGATION;
1162 	lp->lp_selected = LACP_UNSELECTED;
1163 	lacp_sm_rx_record_default(lp);
1164 	lp->lp_partner.lip_state &= ~LACP_STATE_AGGREGATION;
1165 	lp->lp_state &= ~LACP_STATE_EXPIRED;
1166 }
1167 
1168 /*
1169  * lacp_select: select an aggregator.  create one if necessary.
1170  */
1171 void
1172 lacp_select(struct lacp_port *lp)
1173 {
1174 	struct lacp_softc *lsc = lp->lp_lsc;
1175 	struct lacp_aggregator *la;
1176 #if defined(LACP_DEBUG)
1177 	char buf[LACP_LAGIDSTR_MAX+1];
1178 #endif
1179 
1180 	if (lp->lp_aggregator)
1181 		return;
1182 
1183 	KASSERT(!LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE));
1184 
1185 	LACP_DPRINTF((lp, "port lagid=%s\n",
1186 	    lacp_format_lagid(&lp->lp_actor, &lp->lp_partner,
1187 	    buf, sizeof(buf))));
1188 
1189 	TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) {
1190 		if (lacp_aggregator_is_compatible(la, lp))
1191 			break;
1192 	}
1193 
1194 	if (la == NULL) {
1195 		la = lacp_aggregator_get(lsc, lp);
1196 		if (la == NULL) {
1197 			LACP_DPRINTF((lp, "aggregator creation failed\n"));
1198 
1199 			/*
1200 			 * will retry on the next tick.
1201 			 */
1202 
1203 			return;
1204 		}
1205 		lacp_fill_aggregator_id(la, lp);
1206 		LACP_DPRINTF((lp, "aggregator created\n"));
1207 	} else {
1208 		LACP_DPRINTF((lp, "compatible aggregator found\n"));
1209 		if (la->la_refcnt == LACP_MAX_PORTS)
1210 			return;
1211 		lacp_aggregator_addref(lsc, la);
1212 	}
1213 
1214 	LACP_DPRINTF((lp, "aggregator lagid=%s\n",
1215 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
1216 	    buf, sizeof(buf))));
1217 
1218 	lp->lp_aggregator = la;
1219 	lp->lp_selected = LACP_SELECTED;
1220 }
1221 
1222 /*
1223  * lacp_unselect: finish unselect/detach process.
1224  */
1225 void
1226 lacp_unselect(struct lacp_port *lp)
1227 {
1228 	struct lacp_softc *lsc = lp->lp_lsc;
1229 	struct lacp_aggregator *la = lp->lp_aggregator;
1230 
1231 	KASSERT(!LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE));
1232 
1233 	if (la == NULL)
1234 		return;
1235 
1236 	lp->lp_aggregator = NULL;
1237 	lacp_aggregator_delref(lsc, la);
1238 }
1239 
1240 /* mux machine */
1241 void
1242 lacp_sm_mux(struct lacp_port *lp)
1243 {
1244 	enum lacp_mux_state new_state;
1245 	int p_sync =
1246 	    (lp->lp_partner.lip_state & LACP_STATE_SYNC) != 0;
1247 	int p_collecting =
1248 	    (lp->lp_partner.lip_state & LACP_STATE_COLLECTING) != 0;
1249 	enum lacp_selected selected = lp->lp_selected;
1250 	struct lacp_aggregator *la;
1251 
1252 	/* LACP_DPRINTF((lp, "%s: state %d\n", __func__, lp->lp_mux_state)); */
1253 
1254 re_eval:
1255 	la = lp->lp_aggregator;
1256 	KASSERT(lp->lp_mux_state == LACP_MUX_DETACHED || la != NULL);
1257 	new_state = lp->lp_mux_state;
1258 	switch (lp->lp_mux_state) {
1259 	case LACP_MUX_DETACHED:
1260 		if (selected != LACP_UNSELECTED)
1261 			new_state = LACP_MUX_WAITING;
1262 		break;
1263 	case LACP_MUX_WAITING:
1264 		KASSERT(la->la_pending > 0 ||
1265 		    !LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE));
1266 		if (selected == LACP_SELECTED && la->la_pending == 0)
1267 			new_state = LACP_MUX_ATTACHED;
1268 		else if (selected == LACP_UNSELECTED)
1269 			new_state = LACP_MUX_DETACHED;
1270 		break;
1271 	case LACP_MUX_ATTACHED:
1272 		if (selected == LACP_SELECTED && p_sync)
1273 			new_state = LACP_MUX_COLLECTING;
1274 		else if (selected != LACP_SELECTED)
1275 			new_state = LACP_MUX_DETACHED;
1276 		break;
1277 	case LACP_MUX_COLLECTING:
1278 		if (selected == LACP_SELECTED && p_sync && p_collecting)
1279 			new_state = LACP_MUX_DISTRIBUTING;
1280 		else if (selected != LACP_SELECTED || !p_sync)
1281 			new_state = LACP_MUX_ATTACHED;
1282 		break;
1283 	case LACP_MUX_DISTRIBUTING:
1284 		if (selected != LACP_SELECTED || !p_sync || !p_collecting)
1285 			new_state = LACP_MUX_COLLECTING;
1286 		break;
1287 	default:
1288 		panic("%s: unknown state", __func__);
1289 	}
1290 
1291 	if (lp->lp_mux_state == new_state)
1292 		return;
1293 
1294 	lacp_set_mux(lp, new_state);
1295 	goto re_eval;
1296 }
1297 
1298 void
1299 lacp_set_mux(struct lacp_port *lp, enum lacp_mux_state new_state)
1300 {
1301 	struct lacp_aggregator *la = lp->lp_aggregator;
1302 
1303 	if (lp->lp_mux_state == new_state)
1304 		return;
1305 
1306 	switch (new_state) {
1307 	case LACP_MUX_DETACHED:
1308 		lp->lp_state &= ~LACP_STATE_SYNC;
1309 		lacp_disable_distributing(lp);
1310 		lacp_disable_collecting(lp);
1311 		lacp_sm_assert_ntt(lp);
1312 		/* cancel timer */
1313 		if (LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE)) {
1314 			KASSERT(la->la_pending > 0);
1315 			la->la_pending--;
1316 		}
1317 		LACP_TIMER_DISARM(lp, LACP_TIMER_WAIT_WHILE);
1318 		lacp_unselect(lp);
1319 		break;
1320 	case LACP_MUX_WAITING:
1321 		LACP_TIMER_ARM(lp, LACP_TIMER_WAIT_WHILE,
1322 		    LACP_AGGREGATE_WAIT_TIME);
1323 		la->la_pending++;
1324 		break;
1325 	case LACP_MUX_ATTACHED:
1326 		lp->lp_state |= LACP_STATE_SYNC;
1327 		lacp_disable_collecting(lp);
1328 		lacp_sm_assert_ntt(lp);
1329 		break;
1330 	case LACP_MUX_COLLECTING:
1331 		lacp_enable_collecting(lp);
1332 		lacp_disable_distributing(lp);
1333 		lacp_sm_assert_ntt(lp);
1334 		break;
1335 	case LACP_MUX_DISTRIBUTING:
1336 		lacp_enable_distributing(lp);
1337 		break;
1338 	default:
1339 		panic("%s: unknown state", __func__);
1340 	}
1341 
1342 	LACP_DPRINTF((lp, "mux_state %d -> %d\n", lp->lp_mux_state, new_state));
1343 
1344 	lp->lp_mux_state = new_state;
1345 }
1346 
1347 void
1348 lacp_sm_mux_timer(struct lacp_port *lp)
1349 {
1350 	struct lacp_aggregator *la = lp->lp_aggregator;
1351 #if defined(LACP_DEBUG)
1352 	char buf[LACP_LAGIDSTR_MAX+1];
1353 #endif
1354 
1355 	KASSERT(la->la_pending > 0);
1356 
1357 	LACP_DPRINTF((lp, "%s: aggregator %s, pending %d -> %d\n", __func__,
1358 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
1359 	    buf, sizeof(buf)),
1360 	    la->la_pending, la->la_pending - 1));
1361 
1362 	la->la_pending--;
1363 }
1364 
1365 /* periodic transmit machine */
1366 void
1367 lacp_sm_ptx_update_timeout(struct lacp_port *lp, u_int8_t oldpstate)
1368 {
1369 	if (LACP_STATE_EQ(oldpstate, lp->lp_partner.lip_state,
1370 	    LACP_STATE_TIMEOUT))
1371 		return;
1372 
1373 	LACP_DPRINTF((lp, "partner timeout changed\n"));
1374 
1375 	/*
1376 	 * FAST_PERIODIC -> SLOW_PERIODIC
1377 	 * or
1378 	 * SLOW_PERIODIC (-> PERIODIC_TX) -> FAST_PERIODIC
1379 	 *
1380 	 * let lacp_sm_ptx_tx_schedule to update timeout.
1381 	 */
1382 
1383 	LACP_TIMER_DISARM(lp, LACP_TIMER_PERIODIC);
1384 
1385 	/* if timeout has been shortened, assert NTT. */
1386 	if ((lp->lp_partner.lip_state & LACP_STATE_TIMEOUT))
1387 		lacp_sm_assert_ntt(lp);
1388 }
1389 
1390 void
1391 lacp_sm_ptx_tx_schedule(struct lacp_port *lp)
1392 {
1393 	int timeout;
1394 
1395 	if (!(lp->lp_state & LACP_STATE_ACTIVITY) &&
1396 	    !(lp->lp_partner.lip_state & LACP_STATE_ACTIVITY)) {
1397 
1398 		/* NO_PERIODIC */
1399 		LACP_TIMER_DISARM(lp, LACP_TIMER_PERIODIC);
1400 		return;
1401 	}
1402 
1403 	if (LACP_TIMER_ISARMED(lp, LACP_TIMER_PERIODIC))
1404 		return;
1405 
1406 	timeout = (lp->lp_partner.lip_state & LACP_STATE_TIMEOUT) ?
1407 	    LACP_FAST_PERIODIC_TIME : LACP_SLOW_PERIODIC_TIME;
1408 
1409 	LACP_TIMER_ARM(lp, LACP_TIMER_PERIODIC, timeout);
1410 }
1411 
1412 void
1413 lacp_sm_ptx_timer(struct lacp_port *lp)
1414 {
1415 	lacp_sm_assert_ntt(lp);
1416 }
1417 
1418 void
1419 lacp_sm_rx(struct lacp_port *lp, const struct lacpdu *du)
1420 {
1421 	int timeout;
1422 
1423 	/* check LACP_DISABLED first */
1424 	if (!(lp->lp_state & LACP_STATE_AGGREGATION))
1425 		return;
1426 
1427 	/* check loopback condition. */
1428 	if (!lacp_compare_systemid(&du->ldu_actor.lip_systemid,
1429 	    &lp->lp_actor.lip_systemid))
1430 		return;
1431 
1432 	/*
1433 	 * EXPIRED, DEFAULTED, CURRENT -> CURRENT
1434 	 */
1435 	lacp_sm_rx_update_selected(lp, du);
1436 	lacp_sm_rx_update_ntt(lp, du);
1437 	lacp_sm_rx_record_pdu(lp, du);
1438 
1439 	timeout = (lp->lp_state & LACP_STATE_TIMEOUT) ?
1440 	    LACP_SHORT_TIMEOUT_TIME : LACP_LONG_TIMEOUT_TIME;
1441 	LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, timeout);
1442 
1443 	lp->lp_state &= ~LACP_STATE_EXPIRED;
1444 
1445 	/* kick transmit machine without waiting the next tick. */
1446 	lacp_sm_tx(lp);
1447 }
1448 
1449 void
1450 lacp_sm_rx_set_expired(struct lacp_port *lp)
1451 {
1452 	lp->lp_partner.lip_state &= ~LACP_STATE_SYNC;
1453 	lp->lp_partner.lip_state |= LACP_STATE_TIMEOUT;
1454 	LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, LACP_SHORT_TIMEOUT_TIME);
1455 	lp->lp_state |= LACP_STATE_EXPIRED;
1456 }
1457 
1458 void
1459 lacp_sm_rx_timer(struct lacp_port *lp)
1460 {
1461 	if ((lp->lp_state & LACP_STATE_EXPIRED) == 0) {
1462 		/* CURRENT -> EXPIRED */
1463 		LACP_DPRINTF((lp, "%s: CURRENT -> EXPIRED\n", __func__));
1464 		lacp_sm_rx_set_expired(lp);
1465 	} else {
1466 		/* EXPIRED -> DEFAULTED */
1467 		LACP_DPRINTF((lp, "%s: EXPIRED -> DEFAULTED\n", __func__));
1468 		lacp_sm_rx_update_default_selected(lp);
1469 		lacp_sm_rx_record_default(lp);
1470 		lp->lp_state &= ~LACP_STATE_EXPIRED;
1471 	}
1472 }
1473 
1474 void
1475 lacp_sm_rx_record_pdu(struct lacp_port *lp, const struct lacpdu *du)
1476 {
1477 	int active;
1478 	u_int8_t oldpstate;
1479 #if defined(LACP_DEBUG)
1480 	char buf[LACP_STATESTR_MAX+1];
1481 #endif
1482 
1483 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
1484 
1485 	oldpstate = lp->lp_partner.lip_state;
1486 
1487 	active = (du->ldu_actor.lip_state & LACP_STATE_ACTIVITY)
1488 	    || ((lp->lp_state & LACP_STATE_ACTIVITY) &&
1489 	    (du->ldu_partner.lip_state & LACP_STATE_ACTIVITY));
1490 
1491 	lp->lp_partner = du->ldu_actor;
1492 	if (active &&
1493 	    ((LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state,
1494 	    LACP_STATE_AGGREGATION) &&
1495 	    !lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner))
1496 	    || (du->ldu_partner.lip_state & LACP_STATE_AGGREGATION) == 0)) {
1497 		/* XXX nothing? */
1498 	} else
1499 		lp->lp_partner.lip_state &= ~LACP_STATE_SYNC;
1500 
1501 	lp->lp_state &= ~LACP_STATE_DEFAULTED;
1502 
1503 	if (oldpstate != lp->lp_partner.lip_state) {
1504 		LACP_DPRINTF((lp, "old pstate %s\n",
1505 		    lacp_format_state(oldpstate, buf, sizeof(buf))));
1506 		LACP_DPRINTF((lp, "new pstate %s\n",
1507 		    lacp_format_state(lp->lp_partner.lip_state, buf,
1508 		    sizeof(buf))));
1509 	}
1510 
1511 	lacp_sm_ptx_update_timeout(lp, oldpstate);
1512 }
1513 
1514 void
1515 lacp_sm_rx_update_ntt(struct lacp_port *lp, const struct lacpdu *du)
1516 {
1517 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
1518 
1519 	if (lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner) ||
1520 	    !LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state,
1521 	    LACP_STATE_ACTIVITY | LACP_STATE_SYNC | LACP_STATE_AGGREGATION)) {
1522 		LACP_DPRINTF((lp, "%s: assert ntt\n", __func__));
1523 		lacp_sm_assert_ntt(lp);
1524 	}
1525 }
1526 
1527 void
1528 lacp_sm_rx_record_default(struct lacp_port *lp)
1529 {
1530 	u_int8_t oldpstate;
1531 
1532 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
1533 
1534 	oldpstate = lp->lp_partner.lip_state;
1535 	lp->lp_partner = lacp_partner_admin;
1536 	lp->lp_state |= LACP_STATE_DEFAULTED;
1537 	lacp_sm_ptx_update_timeout(lp, oldpstate);
1538 }
1539 
1540 void
1541 lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *lp,
1542     const struct lacp_peerinfo *info)
1543 {
1544 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
1545 
1546 	if (lacp_compare_peerinfo(&lp->lp_partner, info) ||
1547 	    !LACP_STATE_EQ(lp->lp_partner.lip_state, info->lip_state,
1548 	    LACP_STATE_AGGREGATION)) {
1549 		lp->lp_selected = LACP_UNSELECTED;
1550 		/* mux machine will clean up lp->lp_aggregator */
1551 	}
1552 }
1553 
1554 void
1555 lacp_sm_rx_update_selected(struct lacp_port *lp, const struct lacpdu *du)
1556 {
1557 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
1558 
1559 	lacp_sm_rx_update_selected_from_peerinfo(lp, &du->ldu_actor);
1560 }
1561 
1562 void
1563 lacp_sm_rx_update_default_selected(struct lacp_port *lp)
1564 {
1565 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
1566 
1567 	lacp_sm_rx_update_selected_from_peerinfo(lp, &lacp_partner_admin);
1568 }
1569 
1570 /* transmit machine */
1571 
1572 void
1573 lacp_sm_tx(struct lacp_port *lp)
1574 {
1575 	int error;
1576 
1577 	if (!(lp->lp_state & LACP_STATE_AGGREGATION)
1578 #if 1
1579 	    || (!(lp->lp_state & LACP_STATE_ACTIVITY)
1580 	    && !(lp->lp_partner.lip_state & LACP_STATE_ACTIVITY))
1581 #endif
1582 	    ) {
1583 		lp->lp_flags &= ~LACP_PORT_NTT;
1584 	}
1585 
1586 	if (!(lp->lp_flags & LACP_PORT_NTT))
1587 		return;
1588 
1589 	/* Rate limit to 3 PDUs per LACP_FAST_PERIODIC_TIME */
1590 	if (ppsratecheck(&lp->lp_last_lacpdu, &lp->lp_lacpdu_sent,
1591 		    (3 / LACP_FAST_PERIODIC_TIME)) == 0) {
1592 		LACP_DPRINTF((lp, "rate limited pdu\n"));
1593 		return;
1594 	}
1595 
1596 	error = lacp_xmit_lacpdu(lp);
1597 
1598 	if (error == 0)
1599 		lp->lp_flags &= ~LACP_PORT_NTT;
1600 	else
1601 		LACP_DPRINTF((lp, "lacpdu transmit failure, error %d\n",
1602 		    error));
1603 }
1604 
1605 void
1606 lacp_sm_assert_ntt(struct lacp_port *lp)
1607 {
1608 	lp->lp_flags |= LACP_PORT_NTT;
1609 }
1610 
1611 void
1612 lacp_run_timers(struct lacp_port *lp)
1613 {
1614 	int i;
1615 
1616 	for (i = 0; i < LACP_NTIMER; i++) {
1617 		KASSERT(lp->lp_timer[i] >= 0);
1618 		if (lp->lp_timer[i] == 0)
1619 			continue;
1620 		else if (--lp->lp_timer[i] <= 0) {
1621 			if (lacp_timer_funcs[i])
1622 				(*lacp_timer_funcs[i])(lp);
1623 		}
1624 	}
1625 }
1626 
1627 int
1628 lacp_marker_input(struct lacp_port *lp, struct ether_header *eh, struct mbuf *m)
1629 {
1630 	struct lacp_softc *lsc = lp->lp_lsc;
1631 	struct trunk_port *tp = lp->lp_trunk;
1632 	struct lacp_port *lp2;
1633 	struct markerdu *mdu;
1634 	int error = 0;
1635 	int pending = 0;
1636 
1637 	if (m->m_pkthdr.len != sizeof(*mdu))
1638 		goto bad;
1639 
1640 	if ((m->m_flags & M_MCAST) == 0)
1641 		goto bad;
1642 
1643 	if (m->m_len < sizeof(*mdu)) {
1644 		m = m_pullup(m, sizeof(*mdu));
1645 		if (m == NULL)
1646 			return (ENOMEM);
1647 	}
1648 
1649 	mdu = mtod(m, struct markerdu *);
1650 
1651 	if (memcmp(&eh->ether_dhost,
1652 	    &ethermulticastaddr_slowprotocols, ETHER_ADDR_LEN))
1653 		goto bad;
1654 
1655 	if (mdu->mdu_sph.sph_version != 1)
1656 		goto bad;
1657 
1658 	switch (mdu->mdu_tlv.tlv_type) {
1659 	case MARKER_TYPE_INFO:
1660 		if (tlv_check(mdu, sizeof(*mdu), &mdu->mdu_tlv,
1661 		    marker_info_tlv_template, 1))
1662 			goto bad;
1663 
1664 		mdu->mdu_tlv.tlv_type = MARKER_TYPE_RESPONSE;
1665 		memcpy(&eh->ether_dhost,
1666 		    &ethermulticastaddr_slowprotocols, ETHER_ADDR_LEN);
1667 		memcpy(&eh->ether_shost,
1668 		    tp->tp_lladdr, ETHER_ADDR_LEN);
1669 		error = trunk_enqueue(lp->lp_ifp, m);
1670 		break;
1671 
1672 	case MARKER_TYPE_RESPONSE:
1673 		if (tlv_check(mdu, sizeof(*mdu), &mdu->mdu_tlv,
1674 		    marker_response_tlv_template, 1))
1675 			goto bad;
1676 
1677 		LACP_DPRINTF((lp, "marker response, port=%u, sys=%6D, id=%u\n",
1678 		    ntohs(mdu->mdu_info.mi_rq_port), mdu->mdu_info.mi_rq_system,
1679 		    ":", ntohl(mdu->mdu_info.mi_rq_xid)));
1680 
1681 		/* Verify that it is the last marker we sent out */
1682 		if (memcmp(&mdu->mdu_info, &lp->lp_marker,
1683 		    sizeof(struct lacp_markerinfo)))
1684 			goto bad;
1685 
1686 		lp->lp_flags &= ~LACP_PORT_MARK;
1687 
1688 		if (lsc->lsc_suppress_distributing) {
1689 			/* Check if any ports are waiting for a response */
1690 			LIST_FOREACH(lp2, &lsc->lsc_ports, lp_next) {
1691 				if (lp2->lp_flags & LACP_PORT_MARK) {
1692 					pending = 1;
1693 					break;
1694 				}
1695 			}
1696 
1697 			if (pending == 0) {
1698 				/* All interface queues are clear */
1699 				LACP_DPRINTF((NULL, "queue flush complete\n"));
1700 				lsc->lsc_suppress_distributing = 0;
1701 			}
1702 		}
1703 		m_freem(m);
1704 		break;
1705 
1706 	default:
1707 		goto bad;
1708 	}
1709 
1710 	return (error);
1711 
1712 bad:
1713 	LACP_DPRINTF((lp, "bad marker frame\n"));
1714 	m_freem(m);
1715 	return (EINVAL);
1716 }
1717 
1718 int
1719 tlv_check(const void *p, size_t size, const struct tlvhdr *tlv,
1720     const struct tlv_template *tmpl, int check_type)
1721 {
1722 	while (/* CONSTCOND */ 1) {
1723 		if ((const char *)tlv - (const char *)p + sizeof(*tlv) > size)
1724 			return (EINVAL);
1725 
1726 		if ((check_type && tlv->tlv_type != tmpl->tmpl_type) ||
1727 		    tlv->tlv_length != tmpl->tmpl_length)
1728 			return (EINVAL);
1729 
1730 		if (tmpl->tmpl_type == 0)
1731 			break;
1732 
1733 		tlv = (const struct tlvhdr *)
1734 		    ((const char *)tlv + tlv->tlv_length);
1735 		tmpl++;
1736 	}
1737 
1738 	return (0);
1739 }
1740 
1741 #if defined(LACP_DEBUG)
1742 const char *
1743 lacp_format_mac(const u_int8_t *mac, char *buf, size_t buflen)
1744 {
1745 	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
1746 	    (int)mac[0],
1747 	    (int)mac[1],
1748 	    (int)mac[2],
1749 	    (int)mac[3],
1750 	    (int)mac[4],
1751 	    (int)mac[5]);
1752 
1753 	return (buf);
1754 }
1755 
1756 const char *
1757 lacp_format_systemid(const struct lacp_systemid *sysid,
1758     char *buf, size_t buflen)
1759 {
1760 	char macbuf[LACP_MACSTR_MAX+1];
1761 
1762 	snprintf(buf, buflen, "%04X,%s",
1763 	    ntohs(sysid->lsi_prio),
1764 	    lacp_format_mac(sysid->lsi_mac, macbuf, sizeof(macbuf)));
1765 
1766 	return (buf);
1767 }
1768 
1769 const char *
1770 lacp_format_portid(const struct lacp_portid *portid, char *buf, size_t buflen)
1771 {
1772 	snprintf(buf, buflen, "%04X,%04X",
1773 	    ntohs(portid->lpi_prio),
1774 	    ntohs(portid->lpi_portno));
1775 
1776 	return (buf);
1777 }
1778 
1779 const char *
1780 lacp_format_partner(const struct lacp_peerinfo *peer, char *buf, size_t buflen)
1781 {
1782 	char sysid[LACP_SYSTEMIDSTR_MAX+1];
1783 	char portid[LACP_PORTIDSTR_MAX+1];
1784 
1785 	snprintf(buf, buflen, "(%s,%04X,%s)",
1786 	    lacp_format_systemid(&peer->lip_systemid, sysid, sizeof(sysid)),
1787 	    ntohs(peer->lip_key),
1788 	    lacp_format_portid(&peer->lip_portid, portid, sizeof(portid)));
1789 
1790 	return (buf);
1791 }
1792 
1793 const char *
1794 lacp_format_lagid(const struct lacp_peerinfo *a,
1795     const struct lacp_peerinfo *b, char *buf, size_t buflen)
1796 {
1797 	char astr[LACP_PARTNERSTR_MAX+1];
1798 	char bstr[LACP_PARTNERSTR_MAX+1];
1799 
1800 #if 0
1801 	/*
1802 	 * there's a convention to display small numbered peer
1803 	 * in the left.
1804 	 */
1805 	if (lacp_compare_peerinfo(a, b) > 0) {
1806 		const struct lacp_peerinfo *t;
1807 
1808 		t = a;
1809 		a = b;
1810 		b = t;
1811 	}
1812 #endif
1813 
1814 	snprintf(buf, buflen, "[%s,%s]",
1815 	    lacp_format_partner(a, astr, sizeof(astr)),
1816 	    lacp_format_partner(b, bstr, sizeof(bstr)));
1817 
1818 	return (buf);
1819 }
1820 
1821 const char *
1822 lacp_format_lagid_aggregator(const struct lacp_aggregator *la,
1823     char *buf, size_t buflen)
1824 {
1825 	if (la == NULL)
1826 		return ("(none)");
1827 
1828 	return (lacp_format_lagid(&la->la_actor, &la->la_partner, buf, buflen));
1829 }
1830 
1831 const char *
1832 lacp_format_state(u_int8_t state, char *buf, size_t buflen)
1833 {
1834 	snprintf(buf, buflen, "%b", state, LACP_STATE_BITS);
1835 	return (buf);
1836 }
1837 
1838 void
1839 lacp_dump_lacpdu(const struct lacpdu *du)
1840 {
1841 	char buf[LACP_PARTNERSTR_MAX+1];
1842 	char buf2[LACP_STATESTR_MAX+1];
1843 
1844 	printf("actor=%s\n",
1845 	    lacp_format_partner(&du->ldu_actor, buf, sizeof(buf)));
1846 	printf("actor.state=%s\n",
1847 	    lacp_format_state(du->ldu_actor.lip_state, buf2, sizeof(buf2)));
1848 	printf("partner=%s\n",
1849 	    lacp_format_partner(&du->ldu_partner, buf, sizeof(buf)));
1850 	printf("partner.state=%s\n",
1851 	    lacp_format_state(du->ldu_partner.lip_state, buf2, sizeof(buf2)));
1852 
1853 	printf("maxdelay=%d\n", ntohs(du->ldu_collector.lci_maxdelay));
1854 }
1855 
1856 void
1857 lacp_dprintf(const struct lacp_port *lp, const char *fmt, ...)
1858 {
1859 	va_list va;
1860 
1861 	if (lp)
1862 		printf("%s: ", lp->lp_ifp->if_xname);
1863 
1864 	va_start(va, fmt);
1865 	vprintf(fmt, va);
1866 	va_end(va);
1867 }
1868 #endif
1869