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