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