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