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