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