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