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