ieee8023ad_lacp.c revision 169569
1168561Sthompsa/* $NetBSD: ieee8023ad_lacp.c,v 1.3 2005/12/11 12:24:54 christos Exp $ */ 2168561Sthompsa 3168561Sthompsa/*- 4168561Sthompsa * Copyright (c)2005 YAMAMOTO Takashi, 5168561Sthompsa * All rights reserved. 6168561Sthompsa * 7168561Sthompsa * Redistribution and use in source and binary forms, with or without 8168561Sthompsa * modification, are permitted provided that the following conditions 9168561Sthompsa * are met: 10168561Sthompsa * 1. Redistributions of source code must retain the above copyright 11168561Sthompsa * notice, this list of conditions and the following disclaimer. 12168561Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 13168561Sthompsa * notice, this list of conditions and the following disclaimer in the 14168561Sthompsa * documentation and/or other materials provided with the distribution. 15168561Sthompsa * 16168561Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17168561Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18168561Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19168561Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20168561Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21168561Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22168561Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23168561Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24168561Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25168561Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26168561Sthompsa * SUCH DAMAGE. 27168561Sthompsa */ 28168561Sthompsa 29168561Sthompsa#include <sys/cdefs.h> 30168561Sthompsa__FBSDID("$FreeBSD: head/sys/net/ieee8023ad_lacp.c 169569 2007-05-15 07:41:46Z thompsa $"); 31168561Sthompsa 32168561Sthompsa#include <sys/param.h> 33168561Sthompsa#include <sys/callout.h> 34168561Sthompsa#include <sys/mbuf.h> 35168561Sthompsa#include <sys/systm.h> 36168561Sthompsa#include <sys/malloc.h> 37168561Sthompsa#include <sys/kernel.h> /* hz */ 38168561Sthompsa#include <sys/socket.h> /* for net/if.h */ 39168561Sthompsa#include <sys/sockio.h> 40168561Sthompsa#include <machine/stdarg.h> 41169569Sthompsa#include <sys/lock.h> 42169569Sthompsa#include <sys/rwlock.h> 43169569Sthompsa#include <sys/taskqueue.h> 44168561Sthompsa 45168561Sthompsa#include <net/if.h> 46168561Sthompsa#include <net/if_dl.h> 47168561Sthompsa#include <net/ethernet.h> 48168561Sthompsa#include <net/if_media.h> 49168561Sthompsa#include <net/if_types.h> 50168561Sthompsa 51168793Sthompsa#include <net/if_lagg.h> 52168561Sthompsa#include <net/ieee8023ad_lacp.h> 53168561Sthompsa 54168561Sthompsa/* 55168561Sthompsa * actor system priority and port priority. 56168561Sthompsa * XXX should be configurable. 57168561Sthompsa */ 58168561Sthompsa 59168561Sthompsa#define LACP_SYSTEM_PRIO 0x8000 60168561Sthompsa#define LACP_PORT_PRIO 0x8000 61168561Sthompsa 62168561Sthompsaconst uint8_t ethermulticastaddr_slowprotocols[ETHER_ADDR_LEN] = 63168561Sthompsa { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }; 64168561Sthompsa 65168561Sthompsastatic const struct tlv_template lacp_info_tlv_template[] = { 66168561Sthompsa { LACP_TYPE_ACTORINFO, 67168561Sthompsa sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) }, 68168561Sthompsa { LACP_TYPE_PARTNERINFO, 69168561Sthompsa sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) }, 70168561Sthompsa { LACP_TYPE_COLLECTORINFO, 71168561Sthompsa sizeof(struct tlvhdr) + sizeof(struct lacp_collectorinfo) }, 72168561Sthompsa { 0, 0 }, 73168561Sthompsa}; 74168561Sthompsa 75168561Sthompsatypedef void (*lacp_timer_func_t)(struct lacp_port *); 76168561Sthompsa 77168561Sthompsastatic const struct tlv_template marker_info_tlv_template[] = { 78168561Sthompsa { MARKER_TYPE_INFO, 16 }, 79168561Sthompsa { 0, 0 }, 80168561Sthompsa}; 81168561Sthompsa 82168561Sthompsastatic const struct tlv_template marker_response_tlv_template[] = { 83168561Sthompsa { MARKER_TYPE_RESPONSE, 16 }, 84168561Sthompsa { 0, 0 }, 85168561Sthompsa}; 86168561Sthompsa 87168561Sthompsastatic void lacp_fill_actorinfo(struct lacp_port *, struct lacp_peerinfo *); 88168561Sthompsa 89168561Sthompsastatic uint64_t lacp_aggregator_bandwidth(struct lacp_aggregator *); 90168561Sthompsastatic void lacp_suppress_distributing(struct lacp_softc *, 91168561Sthompsa struct lacp_aggregator *); 92168561Sthompsastatic void lacp_transit_expire(void *); 93168561Sthompsastatic void lacp_select_active_aggregator(struct lacp_softc *); 94168561Sthompsastatic uint16_t lacp_compose_key(struct lacp_port *); 95168561Sthompsastatic int tlv_check(const void *, size_t, const struct tlvhdr *, 96168561Sthompsa const struct tlv_template *, boolean_t); 97168561Sthompsastatic void lacp_tick(void *); 98168561Sthompsa 99168561Sthompsastatic void lacp_fill_aggregator_id(struct lacp_aggregator *, 100168561Sthompsa const struct lacp_port *); 101168561Sthompsastatic void lacp_fill_aggregator_id_peer(struct lacp_peerinfo *, 102168561Sthompsa const struct lacp_peerinfo *); 103168561Sthompsastatic int lacp_aggregator_is_compatible(const struct lacp_aggregator *, 104168561Sthompsa const struct lacp_port *); 105168561Sthompsastatic int lacp_peerinfo_is_compatible(const struct lacp_peerinfo *, 106168561Sthompsa const struct lacp_peerinfo *); 107168561Sthompsa 108168561Sthompsastatic struct lacp_aggregator *lacp_aggregator_get(struct lacp_softc *, 109168561Sthompsa struct lacp_port *); 110168561Sthompsastatic void lacp_aggregator_addref(struct lacp_softc *, 111168561Sthompsa struct lacp_aggregator *); 112168561Sthompsastatic void lacp_aggregator_delref(struct lacp_softc *, 113168561Sthompsa struct lacp_aggregator *); 114168561Sthompsa 115168561Sthompsa/* receive machine */ 116168561Sthompsa 117169569Sthompsastatic void lacp_dequeue(void *, int); 118169569Sthompsastatic int lacp_pdu_input(struct lagg_port *, struct mbuf *); 119169569Sthompsastatic int lacp_marker_input(struct lagg_port *, struct mbuf *); 120168561Sthompsastatic void lacp_sm_rx(struct lacp_port *, const struct lacpdu *); 121168561Sthompsastatic void lacp_sm_rx_timer(struct lacp_port *); 122168561Sthompsastatic void lacp_sm_rx_set_expired(struct lacp_port *); 123168561Sthompsastatic void lacp_sm_rx_update_ntt(struct lacp_port *, 124168561Sthompsa const struct lacpdu *); 125168561Sthompsastatic void lacp_sm_rx_record_pdu(struct lacp_port *, 126168561Sthompsa const struct lacpdu *); 127168561Sthompsastatic void lacp_sm_rx_update_selected(struct lacp_port *, 128168561Sthompsa const struct lacpdu *); 129168561Sthompsastatic void lacp_sm_rx_record_default(struct lacp_port *); 130168561Sthompsastatic void lacp_sm_rx_update_default_selected(struct lacp_port *); 131168561Sthompsastatic void lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *, 132168561Sthompsa const struct lacp_peerinfo *); 133168561Sthompsa 134168561Sthompsa/* mux machine */ 135168561Sthompsa 136168561Sthompsastatic void lacp_sm_mux(struct lacp_port *); 137168561Sthompsastatic void lacp_set_mux(struct lacp_port *, enum lacp_mux_state); 138168561Sthompsastatic void lacp_sm_mux_timer(struct lacp_port *); 139168561Sthompsa 140168561Sthompsa/* periodic transmit machine */ 141168561Sthompsa 142168561Sthompsastatic void lacp_sm_ptx_update_timeout(struct lacp_port *, uint8_t); 143168561Sthompsastatic void lacp_sm_ptx_tx_schedule(struct lacp_port *); 144168561Sthompsastatic void lacp_sm_ptx_timer(struct lacp_port *); 145168561Sthompsa 146168561Sthompsa/* transmit machine */ 147168561Sthompsa 148168561Sthompsastatic void lacp_sm_tx(struct lacp_port *); 149168561Sthompsastatic void lacp_sm_assert_ntt(struct lacp_port *); 150168561Sthompsa 151168561Sthompsastatic void lacp_run_timers(struct lacp_port *); 152168561Sthompsastatic int lacp_compare_peerinfo(const struct lacp_peerinfo *, 153168561Sthompsa const struct lacp_peerinfo *); 154168561Sthompsastatic int lacp_compare_systemid(const struct lacp_systemid *, 155168561Sthompsa const struct lacp_systemid *); 156168561Sthompsastatic void lacp_port_enable(struct lacp_port *); 157168561Sthompsastatic void lacp_port_disable(struct lacp_port *); 158168561Sthompsastatic void lacp_select(struct lacp_port *); 159168561Sthompsastatic void lacp_unselect(struct lacp_port *); 160168561Sthompsastatic void lacp_disable_collecting(struct lacp_port *); 161168561Sthompsastatic void lacp_enable_collecting(struct lacp_port *); 162168561Sthompsastatic void lacp_disable_distributing(struct lacp_port *); 163168561Sthompsastatic void lacp_enable_distributing(struct lacp_port *); 164168561Sthompsastatic int lacp_xmit_lacpdu(struct lacp_port *); 165168561Sthompsa 166168561Sthompsa#if defined(LACP_DEBUG) 167168561Sthompsastatic void lacp_dump_lacpdu(const struct lacpdu *); 168168561Sthompsastatic const char *lacp_format_partner(const struct lacp_peerinfo *, char *, 169168561Sthompsa size_t); 170168561Sthompsastatic const char *lacp_format_lagid(const struct lacp_peerinfo *, 171168561Sthompsa const struct lacp_peerinfo *, char *, size_t); 172168561Sthompsastatic const char *lacp_format_lagid_aggregator(const struct lacp_aggregator *, 173168561Sthompsa char *, size_t); 174168561Sthompsastatic const char *lacp_format_state(uint8_t, char *, size_t); 175168561Sthompsastatic const char *lacp_format_mac(const uint8_t *, char *, size_t); 176168561Sthompsastatic const char *lacp_format_systemid(const struct lacp_systemid *, char *, 177168561Sthompsa size_t); 178168561Sthompsastatic const char *lacp_format_portid(const struct lacp_portid *, char *, 179168561Sthompsa size_t); 180168561Sthompsastatic void lacp_dprintf(const struct lacp_port *, const char *, ...) 181168561Sthompsa __attribute__((__format__(__printf__, 2, 3))); 182168561Sthompsa#define LACP_DPRINTF(a) lacp_dprintf a 183168561Sthompsa#else 184168561Sthompsa#define LACP_DPRINTF(a) /* nothing */ 185168561Sthompsa#endif 186168561Sthompsa 187168561Sthompsa/* 188168561Sthompsa * partner administration variables. 189168561Sthompsa * XXX should be configurable. 190168561Sthompsa */ 191168561Sthompsa 192168561Sthompsastatic const struct lacp_peerinfo lacp_partner_admin = { 193168561Sthompsa .lip_systemid = { .lsi_prio = 0xffff }, 194168561Sthompsa .lip_portid = { .lpi_prio = 0xffff }, 195168561Sthompsa#if 1 196168561Sthompsa /* optimistic */ 197168561Sthompsa .lip_state = LACP_STATE_SYNC | LACP_STATE_AGGREGATION | 198168561Sthompsa LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING, 199168561Sthompsa#else 200168561Sthompsa /* pessimistic */ 201168561Sthompsa .lip_state = 0, 202168561Sthompsa#endif 203168561Sthompsa}; 204168561Sthompsa 205168561Sthompsastatic const lacp_timer_func_t lacp_timer_funcs[LACP_NTIMER] = { 206168561Sthompsa [LACP_TIMER_CURRENT_WHILE] = lacp_sm_rx_timer, 207168561Sthompsa [LACP_TIMER_PERIODIC] = lacp_sm_ptx_timer, 208168561Sthompsa [LACP_TIMER_WAIT_WHILE] = lacp_sm_mux_timer, 209168561Sthompsa}; 210168561Sthompsa 211169569Sthompsavoid 212169569Sthompsalacp_input(struct lagg_port *lgp, struct mbuf *m) 213169569Sthompsa{ 214169569Sthompsa struct lagg_softc *lgs = lgp->lp_lagg; 215169569Sthompsa struct lacp_softc *lsc = LACP_SOFTC(lgs); 216169569Sthompsa uint8_t subtype; 217169569Sthompsa 218169569Sthompsa if (m->m_pkthdr.len < sizeof(struct ether_header) + sizeof(subtype)) { 219169569Sthompsa m_freem(m); 220169569Sthompsa return; 221169569Sthompsa } 222169569Sthompsa 223169569Sthompsa m_copydata(m, sizeof(struct ether_header), sizeof(subtype), &subtype); 224169569Sthompsa switch (subtype) { 225169569Sthompsa case SLOWPROTOCOLS_SUBTYPE_LACP: 226169569Sthompsa IF_HANDOFF(&lsc->lsc_queue, m, NULL); 227169569Sthompsa taskqueue_enqueue(taskqueue_swi, &lsc->lsc_qtask); 228169569Sthompsa break; 229169569Sthompsa 230169569Sthompsa case SLOWPROTOCOLS_SUBTYPE_MARKER: 231169569Sthompsa lacp_marker_input(lgp, m); 232169569Sthompsa break; 233169569Sthompsa 234169569Sthompsa default: 235169569Sthompsa /* Unknown LACP packet type */ 236169569Sthompsa m_freem(m); 237169569Sthompsa break; 238169569Sthompsa } 239169569Sthompsa} 240169569Sthompsa 241169569Sthompsastatic void 242169569Sthompsalacp_dequeue(void *arg, int pending) 243169569Sthompsa{ 244169569Sthompsa struct lacp_softc *lsc = (struct lacp_softc *)arg; 245169569Sthompsa struct lagg_softc *sc = lsc->lsc_lagg; 246169569Sthompsa struct lagg_port *lgp; 247169569Sthompsa struct mbuf *m; 248169569Sthompsa 249169569Sthompsa LAGG_WLOCK(sc); 250169569Sthompsa for (;;) { 251169569Sthompsa IF_DEQUEUE(&lsc->lsc_queue, m); 252169569Sthompsa if (m == NULL) 253169569Sthompsa break; 254169569Sthompsa lgp = m->m_pkthdr.rcvif->if_lagg; 255169569Sthompsa lacp_pdu_input(lgp, m); 256169569Sthompsa } 257169569Sthompsa LAGG_WUNLOCK(sc); 258169569Sthompsa} 259169569Sthompsa 260168561Sthompsa/* 261169569Sthompsa * lacp_pdu_input: process lacpdu 262168561Sthompsa */ 263169569Sthompsastatic int 264169569Sthompsalacp_pdu_input(struct lagg_port *lgp, struct mbuf *m) 265168561Sthompsa{ 266168793Sthompsa struct lacp_port *lp = LACP_PORT(lgp); 267168561Sthompsa struct lacpdu *du; 268168561Sthompsa int error = 0; 269168561Sthompsa 270169569Sthompsa LAGG_WLOCK_ASSERT(lgp->lp_lagg); 271168561Sthompsa 272168561Sthompsa if (__predict_false(lp->lp_flags & LACP_PORT_DETACHING)) { 273168561Sthompsa goto bad; 274168561Sthompsa } 275168561Sthompsa 276168561Sthompsa if (m->m_pkthdr.len != sizeof(*du)) { 277168561Sthompsa goto bad; 278168561Sthompsa } 279168561Sthompsa 280168561Sthompsa if ((m->m_flags & M_MCAST) == 0) { 281168561Sthompsa goto bad; 282168561Sthompsa } 283168561Sthompsa 284168561Sthompsa if (m->m_len < sizeof(*du)) { 285168561Sthompsa m = m_pullup(m, sizeof(*du)); 286168561Sthompsa if (m == NULL) { 287168561Sthompsa return (ENOMEM); 288168561Sthompsa } 289168561Sthompsa } 290168561Sthompsa 291168561Sthompsa du = mtod(m, struct lacpdu *); 292168561Sthompsa 293168561Sthompsa if (memcmp(&du->ldu_eh.ether_dhost, 294168561Sthompsa ðermulticastaddr_slowprotocols, ETHER_ADDR_LEN)) { 295168561Sthompsa goto bad; 296168561Sthompsa } 297168561Sthompsa 298168561Sthompsa /* XXX 299168561Sthompsa KASSERT(du->ldu_sph.sph_subtype == SLOWPROTOCOLS_SUBTYPE_LACP, 300168561Sthompsa ("a very bad kassert!")); 301168561Sthompsa */ 302168561Sthompsa 303168561Sthompsa /* 304168561Sthompsa * ignore the version for compatibility with 305168561Sthompsa * the future protocol revisions. 306168561Sthompsa */ 307168561Sthompsa 308168561Sthompsa#if 0 309168561Sthompsa if (du->ldu_sph.sph_version != 1) { 310168561Sthompsa goto bad; 311168561Sthompsa } 312168561Sthompsa#endif 313168561Sthompsa 314168561Sthompsa /* 315168561Sthompsa * ignore tlv types for compatibility with 316168561Sthompsa * the future protocol revisions. 317168561Sthompsa */ 318168561Sthompsa 319168561Sthompsa if (tlv_check(du, sizeof(*du), &du->ldu_tlv_actor, 320168561Sthompsa lacp_info_tlv_template, FALSE)) { 321168561Sthompsa goto bad; 322168561Sthompsa } 323168561Sthompsa 324168561Sthompsa#if defined(LACP_DEBUG) 325168561Sthompsa LACP_DPRINTF((lp, "lacpdu receive\n")); 326168561Sthompsa lacp_dump_lacpdu(du); 327168561Sthompsa#endif /* defined(LACP_DEBUG) */ 328168561Sthompsa lacp_sm_rx(lp, du); 329168561Sthompsa 330168561Sthompsa m_freem(m); 331168561Sthompsa 332168561Sthompsa return (error); 333168561Sthompsa 334168561Sthompsabad: 335168561Sthompsa m_freem(m); 336168561Sthompsa return (EINVAL); 337168561Sthompsa} 338168561Sthompsa 339168561Sthompsastatic void 340168561Sthompsalacp_fill_actorinfo(struct lacp_port *lp, struct lacp_peerinfo *info) 341168561Sthompsa{ 342168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 343168793Sthompsa struct lagg_softc *lgs = lgp->lp_lagg; 344168561Sthompsa 345168561Sthompsa info->lip_systemid.lsi_prio = htons(LACP_SYSTEM_PRIO); 346168561Sthompsa memcpy(&info->lip_systemid.lsi_mac, 347168793Sthompsa IF_LLADDR(lgs->sc_ifp), ETHER_ADDR_LEN); 348168561Sthompsa info->lip_portid.lpi_prio = htons(LACP_PORT_PRIO); 349168561Sthompsa info->lip_portid.lpi_portno = htons(lp->lp_ifp->if_index); 350168561Sthompsa info->lip_state = lp->lp_state; 351168561Sthompsa} 352168561Sthompsa 353168561Sthompsastatic int 354168561Sthompsalacp_xmit_lacpdu(struct lacp_port *lp) 355168561Sthompsa{ 356168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 357168561Sthompsa struct mbuf *m; 358168561Sthompsa struct lacpdu *du; 359168561Sthompsa int error; 360168561Sthompsa 361169569Sthompsa LAGG_WLOCK_ASSERT(lgp->lp_lagg); 362168561Sthompsa 363168561Sthompsa m = m_gethdr(M_DONTWAIT, MT_DATA); 364168561Sthompsa if (m == NULL) { 365168561Sthompsa return (ENOMEM); 366168561Sthompsa } 367168561Sthompsa m->m_len = m->m_pkthdr.len = sizeof(*du); 368168561Sthompsa 369168561Sthompsa du = mtod(m, struct lacpdu *); 370168561Sthompsa memset(du, 0, sizeof(*du)); 371168561Sthompsa 372168561Sthompsa memcpy(&du->ldu_eh.ether_dhost, ethermulticastaddr_slowprotocols, 373168561Sthompsa ETHER_ADDR_LEN); 374168793Sthompsa memcpy(&du->ldu_eh.ether_shost, lgp->lp_lladdr, ETHER_ADDR_LEN); 375168561Sthompsa du->ldu_eh.ether_type = htons(ETHERTYPE_SLOW); 376168561Sthompsa 377168561Sthompsa du->ldu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_LACP; 378168561Sthompsa du->ldu_sph.sph_version = 1; 379168561Sthompsa 380168561Sthompsa TLV_SET(&du->ldu_tlv_actor, LACP_TYPE_ACTORINFO, sizeof(du->ldu_actor)); 381168561Sthompsa du->ldu_actor = lp->lp_actor; 382168561Sthompsa 383168561Sthompsa TLV_SET(&du->ldu_tlv_partner, LACP_TYPE_PARTNERINFO, 384168561Sthompsa sizeof(du->ldu_partner)); 385168561Sthompsa du->ldu_partner = lp->lp_partner; 386168561Sthompsa 387168561Sthompsa TLV_SET(&du->ldu_tlv_collector, LACP_TYPE_COLLECTORINFO, 388168561Sthompsa sizeof(du->ldu_collector)); 389168561Sthompsa du->ldu_collector.lci_maxdelay = 0; 390168561Sthompsa 391168561Sthompsa#if defined(LACP_DEBUG) 392168561Sthompsa LACP_DPRINTF((lp, "lacpdu transmit\n")); 393168561Sthompsa lacp_dump_lacpdu(du); 394168561Sthompsa#endif /* defined(LACP_DEBUG) */ 395168561Sthompsa 396168561Sthompsa m->m_flags |= M_MCAST; 397168561Sthompsa 398168561Sthompsa /* 399168561Sthompsa * XXX should use higher priority queue. 400168561Sthompsa * otherwise network congestion can break aggregation. 401168561Sthompsa */ 402168561Sthompsa 403168793Sthompsa error = lagg_enqueue(lp->lp_ifp, m); 404168561Sthompsa return (error); 405168561Sthompsa} 406168561Sthompsa 407168561Sthompsavoid 408168793Sthompsalacp_linkstate(struct lagg_port *lgp) 409168561Sthompsa{ 410168793Sthompsa struct lacp_port *lp = LACP_PORT(lgp); 411168793Sthompsa struct ifnet *ifp = lgp->lp_ifp; 412168561Sthompsa struct ifmediareq ifmr; 413168561Sthompsa int error = 0; 414168561Sthompsa u_int media; 415168561Sthompsa uint8_t old_state; 416168561Sthompsa uint16_t old_key; 417168561Sthompsa 418169569Sthompsa LAGG_WLOCK_ASSERT(lgp->lp_lagg); 419168561Sthompsa 420168561Sthompsa bzero((char *)&ifmr, sizeof(ifmr)); 421168561Sthompsa error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); 422168561Sthompsa if (error != 0) 423168561Sthompsa return; 424168561Sthompsa 425168561Sthompsa media = ifmr.ifm_active; 426169227Sthompsa LACP_DPRINTF((lp, "media changed 0x%x -> 0x%x, ether = %d, fdx = %d, " 427169227Sthompsa "link = %d\n", lp->lp_media, media, IFM_TYPE(media) == IFM_ETHER, 428169227Sthompsa (media & IFM_FDX) != 0, ifp->if_link_state == LINK_STATE_UP)); 429168561Sthompsa old_state = lp->lp_state; 430168561Sthompsa old_key = lp->lp_key; 431168561Sthompsa 432168561Sthompsa lp->lp_media = media; 433169227Sthompsa /* 434169227Sthompsa * If the port is not an active full duplex Ethernet link then it can 435169227Sthompsa * not be aggregated. 436169227Sthompsa */ 437169227Sthompsa if (IFM_TYPE(media) != IFM_ETHER || (media & IFM_FDX) == 0 || 438169227Sthompsa ifp->if_link_state != LINK_STATE_UP) { 439168561Sthompsa lacp_port_disable(lp); 440168561Sthompsa } else { 441168561Sthompsa lacp_port_enable(lp); 442168561Sthompsa } 443168561Sthompsa lp->lp_key = lacp_compose_key(lp); 444168561Sthompsa 445168561Sthompsa if (old_state != lp->lp_state || old_key != lp->lp_key) { 446168561Sthompsa LACP_DPRINTF((lp, "-> UNSELECTED\n")); 447168561Sthompsa lp->lp_selected = LACP_UNSELECTED; 448168561Sthompsa } 449168561Sthompsa} 450168561Sthompsa 451168561Sthompsastatic void 452168561Sthompsalacp_tick(void *arg) 453168561Sthompsa{ 454168561Sthompsa struct lacp_softc *lsc = arg; 455169569Sthompsa struct lagg_softc *sc = lsc->lsc_lagg; 456168561Sthompsa struct lacp_port *lp; 457168561Sthompsa 458169569Sthompsa LAGG_WLOCK(sc); 459168561Sthompsa LIST_FOREACH(lp, &lsc->lsc_ports, lp_next) { 460168561Sthompsa if ((lp->lp_state & LACP_STATE_AGGREGATION) == 0) 461168561Sthompsa continue; 462168561Sthompsa 463168561Sthompsa lacp_run_timers(lp); 464168561Sthompsa 465168561Sthompsa lacp_select(lp); 466168561Sthompsa lacp_sm_mux(lp); 467168561Sthompsa lacp_sm_tx(lp); 468168561Sthompsa lacp_sm_ptx_tx_schedule(lp); 469168561Sthompsa } 470169569Sthompsa LAGG_WUNLOCK(sc); 471168561Sthompsa callout_reset(&lsc->lsc_callout, hz, lacp_tick, lsc); 472168561Sthompsa} 473168561Sthompsa 474168561Sthompsaint 475168793Sthompsalacp_port_create(struct lagg_port *lgp) 476168561Sthompsa{ 477168793Sthompsa struct lagg_softc *lgs = lgp->lp_lagg; 478168793Sthompsa struct lacp_softc *lsc = LACP_SOFTC(lgs); 479168561Sthompsa struct lacp_port *lp; 480168793Sthompsa struct ifnet *ifp = lgp->lp_ifp; 481168561Sthompsa struct sockaddr_dl sdl; 482168561Sthompsa struct ifmultiaddr *rifma = NULL; 483168561Sthompsa int error; 484168561Sthompsa 485168561Sthompsa boolean_t active = TRUE; /* XXX should be configurable */ 486168561Sthompsa boolean_t fast = FALSE; /* XXX should be configurable */ 487168561Sthompsa 488169569Sthompsa LAGG_WLOCK_ASSERT(lgs); 489168561Sthompsa 490168561Sthompsa bzero((char *)&sdl, sizeof(sdl)); 491168561Sthompsa sdl.sdl_len = sizeof(sdl); 492168561Sthompsa sdl.sdl_family = AF_LINK; 493168561Sthompsa sdl.sdl_index = ifp->if_index; 494168561Sthompsa sdl.sdl_type = IFT_ETHER; 495168561Sthompsa sdl.sdl_alen = ETHER_ADDR_LEN; 496168561Sthompsa 497168561Sthompsa bcopy(ðermulticastaddr_slowprotocols, 498168561Sthompsa LLADDR(&sdl), ETHER_ADDR_LEN); 499168561Sthompsa error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma); 500168561Sthompsa if (error) { 501168793Sthompsa printf("%s: ADDMULTI failed on %s\n", __func__, lgp->lp_ifname); 502168561Sthompsa return (error); 503168561Sthompsa } 504168561Sthompsa 505168561Sthompsa lp = malloc(sizeof(struct lacp_port), 506168561Sthompsa M_DEVBUF, M_NOWAIT|M_ZERO); 507168561Sthompsa if (lp == NULL) 508168561Sthompsa return (ENOMEM); 509168561Sthompsa 510168793Sthompsa lgp->lp_psc = (caddr_t)lp; 511168561Sthompsa lp->lp_ifp = ifp; 512168793Sthompsa lp->lp_lagg = lgp; 513168561Sthompsa lp->lp_lsc = lsc; 514169327Sthompsa lp->lp_ifma = rifma; 515168561Sthompsa 516168561Sthompsa LIST_INSERT_HEAD(&lsc->lsc_ports, lp, lp_next); 517168561Sthompsa 518168561Sthompsa lacp_fill_actorinfo(lp, &lp->lp_actor); 519168561Sthompsa lp->lp_state = 520168561Sthompsa (active ? LACP_STATE_ACTIVITY : 0) | 521168561Sthompsa (fast ? LACP_STATE_TIMEOUT : 0); 522168561Sthompsa lp->lp_aggregator = NULL; 523168793Sthompsa lacp_linkstate(lgp); 524168561Sthompsa lacp_sm_rx_set_expired(lp); 525168561Sthompsa 526168561Sthompsa return (0); 527168561Sthompsa} 528168561Sthompsa 529168561Sthompsavoid 530168793Sthompsalacp_port_destroy(struct lagg_port *lgp) 531168561Sthompsa{ 532168793Sthompsa struct lacp_port *lp = LACP_PORT(lgp); 533169327Sthompsa int i; 534168561Sthompsa 535169569Sthompsa LAGG_WLOCK_ASSERT(lgp->lp_lagg); 536168561Sthompsa 537168561Sthompsa for (i = 0; i < LACP_NTIMER; i++) { 538168561Sthompsa LACP_TIMER_DISARM(lp, i); 539168561Sthompsa } 540168561Sthompsa 541168561Sthompsa lacp_disable_collecting(lp); 542168561Sthompsa lacp_disable_distributing(lp); 543168561Sthompsa lacp_unselect(lp); 544169227Sthompsa lgp->lp_flags &= ~LAGG_PORT_DISABLED; 545168561Sthompsa 546169328Sthompsa /* The address may have already been removed by if_purgemaddrs() */ 547169328Sthompsa if (!lgp->lp_detaching) 548169328Sthompsa if_delmulti_ifma(lp->lp_ifma); 549168561Sthompsa 550168561Sthompsa LIST_REMOVE(lp, lp_next); 551168561Sthompsa free(lp, M_DEVBUF); 552168561Sthompsa} 553168561Sthompsa 554168561Sthompsaint 555168793Sthompsalacp_port_isactive(struct lagg_port *lgp) 556168561Sthompsa{ 557168793Sthompsa struct lacp_port *lp = LACP_PORT(lgp); 558168561Sthompsa struct lacp_softc *lsc = lp->lp_lsc; 559168561Sthompsa struct lacp_aggregator *la = lp->lp_aggregator; 560168561Sthompsa 561168561Sthompsa /* This port is joined to the active aggregator */ 562168561Sthompsa if (la != NULL && la == lsc->lsc_active_aggregator) 563168561Sthompsa return (1); 564168561Sthompsa 565168561Sthompsa return (0); 566168561Sthompsa} 567168561Sthompsa 568168561Sthompsastatic void 569168561Sthompsalacp_disable_collecting(struct lacp_port *lp) 570168561Sthompsa{ 571168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 572168561Sthompsa 573168561Sthompsa LACP_DPRINTF((lp, "collecting disabled\n")); 574168561Sthompsa 575168561Sthompsa lp->lp_state &= ~LACP_STATE_COLLECTING; 576168793Sthompsa lgp->lp_flags &= ~LAGG_PORT_COLLECTING; 577168561Sthompsa} 578168561Sthompsa 579168561Sthompsastatic void 580168561Sthompsalacp_enable_collecting(struct lacp_port *lp) 581168561Sthompsa{ 582168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 583168561Sthompsa 584168561Sthompsa LACP_DPRINTF((lp, "collecting enabled\n")); 585168561Sthompsa 586168561Sthompsa lp->lp_state |= LACP_STATE_COLLECTING; 587168793Sthompsa lgp->lp_flags |= LAGG_PORT_COLLECTING; 588168561Sthompsa} 589168561Sthompsa 590168561Sthompsastatic void 591168561Sthompsalacp_disable_distributing(struct lacp_port *lp) 592168561Sthompsa{ 593168561Sthompsa struct lacp_aggregator *la = lp->lp_aggregator; 594168561Sthompsa struct lacp_softc *lsc = lp->lp_lsc; 595168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 596168561Sthompsa#if defined(LACP_DEBUG) 597168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 598168561Sthompsa#endif /* defined(LACP_DEBUG) */ 599168561Sthompsa 600169569Sthompsa LAGG_WLOCK_ASSERT(lgp->lp_lagg); 601168561Sthompsa 602168561Sthompsa if (la == NULL || (lp->lp_state & LACP_STATE_DISTRIBUTING) == 0) { 603168561Sthompsa return; 604168561Sthompsa } 605168561Sthompsa 606168561Sthompsa KASSERT(!TAILQ_EMPTY(&la->la_ports), ("no aggregator ports")); 607168561Sthompsa KASSERT(la->la_nports > 0, ("nports invalid (%d)", la->la_nports)); 608168561Sthompsa KASSERT(la->la_refcnt >= la->la_nports, ("aggregator refcnt invalid")); 609168561Sthompsa 610168561Sthompsa LACP_DPRINTF((lp, "disable distributing on aggregator %s, " 611168561Sthompsa "nports %d -> %d\n", 612168561Sthompsa lacp_format_lagid_aggregator(la, buf, sizeof(buf)), 613168561Sthompsa la->la_nports, la->la_nports - 1)); 614168561Sthompsa 615168561Sthompsa TAILQ_REMOVE(&la->la_ports, lp, lp_dist_q); 616168561Sthompsa la->la_nports--; 617168561Sthompsa 618168561Sthompsa lacp_suppress_distributing(lsc, la); 619168561Sthompsa 620168561Sthompsa lp->lp_state &= ~LACP_STATE_DISTRIBUTING; 621168793Sthompsa lgp->lp_flags &= ~LAGG_PORT_DISTRIBUTING; 622168561Sthompsa 623168561Sthompsa if (lsc->lsc_active_aggregator == la) { 624168561Sthompsa lacp_select_active_aggregator(lsc); 625168561Sthompsa } 626168561Sthompsa} 627168561Sthompsa 628168561Sthompsastatic void 629168561Sthompsalacp_enable_distributing(struct lacp_port *lp) 630168561Sthompsa{ 631168561Sthompsa struct lacp_aggregator *la = lp->lp_aggregator; 632168561Sthompsa struct lacp_softc *lsc = lp->lp_lsc; 633168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 634168561Sthompsa#if defined(LACP_DEBUG) 635168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 636168561Sthompsa#endif /* defined(LACP_DEBUG) */ 637168561Sthompsa 638169569Sthompsa LAGG_WLOCK_ASSERT(lgp->lp_lagg); 639168561Sthompsa 640168561Sthompsa if ((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0) { 641168561Sthompsa return; 642168561Sthompsa } 643168561Sthompsa 644168561Sthompsa LACP_DPRINTF((lp, "enable distributing on aggregator %s, " 645168561Sthompsa "nports %d -> %d\n", 646168561Sthompsa lacp_format_lagid_aggregator(la, buf, sizeof(buf)), 647168561Sthompsa la->la_nports, la->la_nports + 1)); 648168561Sthompsa 649168561Sthompsa KASSERT(la->la_refcnt > la->la_nports, ("aggregator refcnt invalid")); 650168561Sthompsa TAILQ_INSERT_HEAD(&la->la_ports, lp, lp_dist_q); 651168561Sthompsa la->la_nports++; 652168561Sthompsa 653168561Sthompsa lacp_suppress_distributing(lsc, la); 654168561Sthompsa 655168561Sthompsa lp->lp_state |= LACP_STATE_DISTRIBUTING; 656168793Sthompsa lgp->lp_flags |= LAGG_PORT_DISTRIBUTING; 657168561Sthompsa 658168561Sthompsa if (lsc->lsc_active_aggregator != la) { 659168561Sthompsa lacp_select_active_aggregator(lsc); 660168561Sthompsa } 661168561Sthompsa} 662168561Sthompsa 663168561Sthompsastatic void 664168561Sthompsalacp_transit_expire(void *vp) 665168561Sthompsa{ 666168561Sthompsa struct lacp_softc *lsc = vp; 667168561Sthompsa 668168561Sthompsa LACP_DPRINTF((NULL, "%s\n", __func__)); 669168561Sthompsa lsc->lsc_suppress_distributing = FALSE; 670168561Sthompsa} 671168561Sthompsa 672168561Sthompsaint 673168793Sthompsalacp_attach(struct lagg_softc *lgs) 674168561Sthompsa{ 675168561Sthompsa struct lacp_softc *lsc; 676168561Sthompsa 677169569Sthompsa LAGG_WLOCK_ASSERT(lgs); 678168561Sthompsa 679168561Sthompsa lsc = malloc(sizeof(struct lacp_softc), 680168561Sthompsa M_DEVBUF, M_NOWAIT|M_ZERO); 681168561Sthompsa if (lsc == NULL) 682168561Sthompsa return (ENOMEM); 683168561Sthompsa 684168793Sthompsa lgs->sc_psc = (caddr_t)lsc; 685168793Sthompsa lsc->lsc_lagg = lgs; 686168561Sthompsa 687168561Sthompsa lsc->lsc_hashkey = arc4random(); 688168561Sthompsa lsc->lsc_active_aggregator = NULL; 689168561Sthompsa TAILQ_INIT(&lsc->lsc_aggregators); 690168561Sthompsa LIST_INIT(&lsc->lsc_ports); 691168561Sthompsa 692169569Sthompsa TASK_INIT(&lsc->lsc_qtask, 0, lacp_dequeue, lsc); 693169569Sthompsa mtx_init(&lsc->lsc_queue.ifq_mtx, "lacp queue", NULL, MTX_DEF); 694169569Sthompsa lsc->lsc_queue.ifq_maxlen = ifqmaxlen; 695168561Sthompsa 696169569Sthompsa callout_init(&lsc->lsc_transit_callout, CALLOUT_MPSAFE); 697169569Sthompsa callout_init(&lsc->lsc_callout, CALLOUT_MPSAFE); 698169569Sthompsa 699168793Sthompsa /* if the lagg is already up then do the same */ 700168793Sthompsa if (lgs->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) 701168793Sthompsa lacp_init(lgs); 702168561Sthompsa 703168561Sthompsa return (0); 704168561Sthompsa} 705168561Sthompsa 706168561Sthompsaint 707168793Sthompsalacp_detach(struct lagg_softc *lgs) 708168561Sthompsa{ 709168793Sthompsa struct lacp_softc *lsc = LACP_SOFTC(lgs); 710168561Sthompsa 711168561Sthompsa KASSERT(TAILQ_EMPTY(&lsc->lsc_aggregators), 712168561Sthompsa ("aggregators still active")); 713168561Sthompsa KASSERT(lsc->lsc_active_aggregator == NULL, 714168561Sthompsa ("aggregator still attached")); 715168561Sthompsa 716168793Sthompsa lgs->sc_psc = NULL; 717168561Sthompsa callout_drain(&lsc->lsc_transit_callout); 718168561Sthompsa callout_drain(&lsc->lsc_callout); 719169569Sthompsa taskqueue_drain(taskqueue_swi, &lsc->lsc_qtask); 720169569Sthompsa IF_DRAIN(&lsc->lsc_queue); 721169569Sthompsa mtx_destroy(&lsc->lsc_queue.ifq_mtx); 722168561Sthompsa 723168561Sthompsa free(lsc, M_DEVBUF); 724168561Sthompsa return (0); 725168561Sthompsa} 726168561Sthompsa 727168561Sthompsavoid 728168793Sthompsalacp_init(struct lagg_softc *lgs) 729168561Sthompsa{ 730168793Sthompsa struct lacp_softc *lsc = LACP_SOFTC(lgs); 731168561Sthompsa 732168561Sthompsa callout_reset(&lsc->lsc_callout, hz, lacp_tick, lsc); 733168561Sthompsa} 734168561Sthompsa 735168561Sthompsavoid 736168793Sthompsalacp_stop(struct lagg_softc *lgs) 737168561Sthompsa{ 738168793Sthompsa struct lacp_softc *lsc = LACP_SOFTC(lgs); 739168561Sthompsa 740168561Sthompsa callout_stop(&lsc->lsc_transit_callout); 741168561Sthompsa callout_stop(&lsc->lsc_callout); 742168561Sthompsa} 743168561Sthompsa 744168793Sthompsastruct lagg_port * 745168793Sthompsalacp_select_tx_port(struct lagg_softc *lgs, struct mbuf *m) 746168561Sthompsa{ 747168793Sthompsa struct lacp_softc *lsc = LACP_SOFTC(lgs); 748168561Sthompsa struct lacp_aggregator *la; 749168561Sthompsa struct lacp_port *lp; 750168561Sthompsa uint32_t hash; 751168561Sthompsa int nports; 752168561Sthompsa 753169569Sthompsa LAGG_WLOCK_ASSERT(lgs); 754168561Sthompsa 755168561Sthompsa if (__predict_false(lsc->lsc_suppress_distributing)) { 756168561Sthompsa LACP_DPRINTF((NULL, "%s: waiting transit\n", __func__)); 757168561Sthompsa return (NULL); 758168561Sthompsa } 759168561Sthompsa 760168561Sthompsa la = lsc->lsc_active_aggregator; 761168561Sthompsa if (__predict_false(la == NULL)) { 762168561Sthompsa LACP_DPRINTF((NULL, "%s: no active aggregator\n", __func__)); 763168561Sthompsa return (NULL); 764168561Sthompsa } 765168561Sthompsa 766168561Sthompsa nports = la->la_nports; 767168561Sthompsa KASSERT(nports > 0, ("no ports available")); 768168561Sthompsa 769168793Sthompsa hash = lagg_hashmbuf(m, lsc->lsc_hashkey); 770168561Sthompsa hash %= nports; 771168561Sthompsa lp = TAILQ_FIRST(&la->la_ports); 772168561Sthompsa while (hash--) { 773168561Sthompsa lp = TAILQ_NEXT(lp, lp_dist_q); 774168561Sthompsa } 775168561Sthompsa 776168561Sthompsa KASSERT((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0, 777168561Sthompsa ("aggregated port is not distributing")); 778168561Sthompsa 779168793Sthompsa return (lp->lp_lagg); 780168561Sthompsa} 781168561Sthompsa/* 782168561Sthompsa * lacp_suppress_distributing: drop transmit packets for a while 783168561Sthompsa * to preserve packet ordering. 784168561Sthompsa */ 785168561Sthompsa 786168561Sthompsastatic void 787168561Sthompsalacp_suppress_distributing(struct lacp_softc *lsc, struct lacp_aggregator *la) 788168561Sthompsa{ 789168561Sthompsa if (lsc->lsc_active_aggregator != la) { 790168561Sthompsa return; 791168561Sthompsa } 792168561Sthompsa 793168561Sthompsa LACP_DPRINTF((NULL, "%s\n", __func__)); 794168561Sthompsa lsc->lsc_suppress_distributing = TRUE; 795168561Sthompsa /* XXX should consider collector max delay */ 796168561Sthompsa callout_reset(&lsc->lsc_transit_callout, 797168561Sthompsa LACP_TRANSIT_DELAY * hz / 1000, lacp_transit_expire, lsc); 798168561Sthompsa} 799168561Sthompsa 800168561Sthompsastatic int 801168561Sthompsalacp_compare_peerinfo(const struct lacp_peerinfo *a, 802168561Sthompsa const struct lacp_peerinfo *b) 803168561Sthompsa{ 804168561Sthompsa return (memcmp(a, b, offsetof(struct lacp_peerinfo, lip_state))); 805168561Sthompsa} 806168561Sthompsa 807168561Sthompsastatic int 808168561Sthompsalacp_compare_systemid(const struct lacp_systemid *a, 809168561Sthompsa const struct lacp_systemid *b) 810168561Sthompsa{ 811168561Sthompsa return (memcmp(a, b, sizeof(*a))); 812168561Sthompsa} 813168561Sthompsa 814168561Sthompsa#if 0 /* unused */ 815168561Sthompsastatic int 816168561Sthompsalacp_compare_portid(const struct lacp_portid *a, 817168561Sthompsa const struct lacp_portid *b) 818168561Sthompsa{ 819168561Sthompsa return (memcmp(a, b, sizeof(*a))); 820168561Sthompsa} 821168561Sthompsa#endif 822168561Sthompsa 823168561Sthompsastatic uint64_t 824168561Sthompsalacp_aggregator_bandwidth(struct lacp_aggregator *la) 825168561Sthompsa{ 826168561Sthompsa struct lacp_port *lp; 827168561Sthompsa uint64_t speed; 828168561Sthompsa 829168561Sthompsa lp = TAILQ_FIRST(&la->la_ports); 830168561Sthompsa if (lp == NULL) { 831168561Sthompsa return (0); 832168561Sthompsa } 833168561Sthompsa 834168561Sthompsa speed = ifmedia_baudrate(lp->lp_media); 835168561Sthompsa speed *= la->la_nports; 836168561Sthompsa if (speed == 0) { 837168561Sthompsa LACP_DPRINTF((lp, "speed 0? media=0x%x nports=%d\n", 838168561Sthompsa lp->lp_media, la->la_nports)); 839168561Sthompsa } 840168561Sthompsa 841168561Sthompsa return (speed); 842168561Sthompsa} 843168561Sthompsa 844168561Sthompsa/* 845168561Sthompsa * lacp_select_active_aggregator: select an aggregator to be used to transmit 846168793Sthompsa * packets from lagg(4) interface. 847168561Sthompsa */ 848168561Sthompsa 849168561Sthompsastatic void 850168561Sthompsalacp_select_active_aggregator(struct lacp_softc *lsc) 851168561Sthompsa{ 852168561Sthompsa struct lacp_aggregator *la; 853168561Sthompsa struct lacp_aggregator *best_la = NULL; 854168561Sthompsa uint64_t best_speed = 0; 855168561Sthompsa#if defined(LACP_DEBUG) 856168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 857168561Sthompsa#endif /* defined(LACP_DEBUG) */ 858168561Sthompsa 859168561Sthompsa LACP_DPRINTF((NULL, "%s:\n", __func__)); 860168561Sthompsa 861168561Sthompsa TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 862168561Sthompsa uint64_t speed; 863168561Sthompsa 864168561Sthompsa if (la->la_nports == 0) { 865168561Sthompsa continue; 866168561Sthompsa } 867168561Sthompsa 868168561Sthompsa speed = lacp_aggregator_bandwidth(la); 869168561Sthompsa LACP_DPRINTF((NULL, "%s, speed=%jd, nports=%d\n", 870168561Sthompsa lacp_format_lagid_aggregator(la, buf, sizeof(buf)), 871168561Sthompsa speed, la->la_nports)); 872168561Sthompsa if (speed > best_speed || 873168561Sthompsa (speed == best_speed && 874168561Sthompsa la == lsc->lsc_active_aggregator)) { 875168561Sthompsa best_la = la; 876168561Sthompsa best_speed = speed; 877168561Sthompsa } 878168561Sthompsa } 879168561Sthompsa 880168561Sthompsa KASSERT(best_la == NULL || best_la->la_nports > 0, 881168561Sthompsa ("invalid aggregator refcnt")); 882168561Sthompsa KASSERT(best_la == NULL || !TAILQ_EMPTY(&best_la->la_ports), 883168561Sthompsa ("invalid aggregator list")); 884168561Sthompsa 885168561Sthompsa#if defined(LACP_DEBUG) 886168561Sthompsa if (lsc->lsc_active_aggregator != best_la) { 887168561Sthompsa LACP_DPRINTF((NULL, "active aggregator changed\n")); 888168561Sthompsa LACP_DPRINTF((NULL, "old %s\n", 889168561Sthompsa lacp_format_lagid_aggregator(lsc->lsc_active_aggregator, 890168561Sthompsa buf, sizeof(buf)))); 891168561Sthompsa } else { 892168561Sthompsa LACP_DPRINTF((NULL, "active aggregator not changed\n")); 893168561Sthompsa } 894168561Sthompsa LACP_DPRINTF((NULL, "new %s\n", 895168561Sthompsa lacp_format_lagid_aggregator(best_la, buf, sizeof(buf)))); 896168561Sthompsa#endif /* defined(LACP_DEBUG) */ 897168561Sthompsa 898168561Sthompsa if (lsc->lsc_active_aggregator != best_la) { 899168561Sthompsa lsc->lsc_active_aggregator = best_la; 900168561Sthompsa if (best_la) { 901168561Sthompsa lacp_suppress_distributing(lsc, best_la); 902168561Sthompsa } 903168561Sthompsa } 904168561Sthompsa} 905168561Sthompsa 906168561Sthompsastatic uint16_t 907168561Sthompsalacp_compose_key(struct lacp_port *lp) 908168561Sthompsa{ 909168793Sthompsa struct lagg_port *lgp = lp->lp_lagg; 910168793Sthompsa struct lagg_softc *lgs = lgp->lp_lagg; 911168561Sthompsa u_int media = lp->lp_media; 912168561Sthompsa uint16_t key; 913168561Sthompsa 914168561Sthompsa if ((lp->lp_state & LACP_STATE_AGGREGATION) == 0) { 915168561Sthompsa 916168561Sthompsa /* 917168561Sthompsa * non-aggregatable links should have unique keys. 918168561Sthompsa * 919168561Sthompsa * XXX this isn't really unique as if_index is 16 bit. 920168561Sthompsa */ 921168561Sthompsa 922168561Sthompsa /* bit 0..14: (some bits of) if_index of this port */ 923168561Sthompsa key = lp->lp_ifp->if_index; 924168561Sthompsa /* bit 15: 1 */ 925168561Sthompsa key |= 0x8000; 926168561Sthompsa } else { 927168561Sthompsa u_int subtype = IFM_SUBTYPE(media); 928168561Sthompsa 929169227Sthompsa KASSERT(IFM_TYPE(media) == IFM_ETHER, ("invalid media type")); 930169227Sthompsa KASSERT((media & IFM_FDX) != 0, ("aggregating HDX interface")); 931168561Sthompsa 932168561Sthompsa /* bit 0..4: IFM_SUBTYPE */ 933168561Sthompsa key = subtype; 934168793Sthompsa /* bit 5..14: (some bits of) if_index of lagg device */ 935168793Sthompsa key |= 0x7fe0 & ((lgs->sc_ifp->if_index) << 5); 936168561Sthompsa /* bit 15: 0 */ 937168561Sthompsa } 938168561Sthompsa return (htons(key)); 939168561Sthompsa} 940168561Sthompsa 941168561Sthompsastatic void 942168561Sthompsalacp_aggregator_addref(struct lacp_softc *lsc, struct lacp_aggregator *la) 943168561Sthompsa{ 944168561Sthompsa#if defined(LACP_DEBUG) 945168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 946168561Sthompsa#endif 947168561Sthompsa 948168561Sthompsa LACP_DPRINTF((NULL, "%s: lagid=%s, refcnt %d -> %d\n", 949168561Sthompsa __func__, 950168561Sthompsa lacp_format_lagid(&la->la_actor, &la->la_partner, 951168561Sthompsa buf, sizeof(buf)), 952168561Sthompsa la->la_refcnt, la->la_refcnt + 1)); 953168561Sthompsa 954168561Sthompsa KASSERT(la->la_refcnt > 0, ("refcount <= 0")); 955168561Sthompsa la->la_refcnt++; 956168561Sthompsa KASSERT(la->la_refcnt > la->la_nports, ("invalid refcount")); 957168561Sthompsa} 958168561Sthompsa 959168561Sthompsastatic void 960168561Sthompsalacp_aggregator_delref(struct lacp_softc *lsc, struct lacp_aggregator *la) 961168561Sthompsa{ 962168561Sthompsa#if defined(LACP_DEBUG) 963168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 964168561Sthompsa#endif 965168561Sthompsa 966168561Sthompsa LACP_DPRINTF((NULL, "%s: lagid=%s, refcnt %d -> %d\n", 967168561Sthompsa __func__, 968168561Sthompsa lacp_format_lagid(&la->la_actor, &la->la_partner, 969168561Sthompsa buf, sizeof(buf)), 970168561Sthompsa la->la_refcnt, la->la_refcnt - 1)); 971168561Sthompsa 972168561Sthompsa KASSERT(la->la_refcnt > la->la_nports, ("invalid refcnt")); 973168561Sthompsa la->la_refcnt--; 974168561Sthompsa if (la->la_refcnt > 0) { 975168561Sthompsa return; 976168561Sthompsa } 977168561Sthompsa 978168561Sthompsa KASSERT(la->la_refcnt == 0, ("refcount not zero")); 979168561Sthompsa KASSERT(lsc->lsc_active_aggregator != la, ("aggregator active")); 980168561Sthompsa 981168561Sthompsa TAILQ_REMOVE(&lsc->lsc_aggregators, la, la_q); 982168561Sthompsa 983168561Sthompsa free(la, M_DEVBUF); 984168561Sthompsa} 985168561Sthompsa 986168561Sthompsa/* 987168561Sthompsa * lacp_aggregator_get: allocate an aggregator. 988168561Sthompsa */ 989168561Sthompsa 990168561Sthompsastatic struct lacp_aggregator * 991168561Sthompsalacp_aggregator_get(struct lacp_softc *lsc, struct lacp_port *lp) 992168561Sthompsa{ 993168561Sthompsa struct lacp_aggregator *la; 994168561Sthompsa 995168561Sthompsa la = malloc(sizeof(*la), M_DEVBUF, M_NOWAIT); 996168561Sthompsa if (la) { 997168561Sthompsa la->la_refcnt = 1; 998168561Sthompsa la->la_nports = 0; 999168561Sthompsa TAILQ_INIT(&la->la_ports); 1000168561Sthompsa la->la_pending = 0; 1001168561Sthompsa TAILQ_INSERT_TAIL(&lsc->lsc_aggregators, la, la_q); 1002168561Sthompsa } 1003168561Sthompsa 1004168561Sthompsa return (la); 1005168561Sthompsa} 1006168561Sthompsa 1007168561Sthompsa/* 1008168561Sthompsa * lacp_fill_aggregator_id: setup a newly allocated aggregator from a port. 1009168561Sthompsa */ 1010168561Sthompsa 1011168561Sthompsastatic void 1012168561Sthompsalacp_fill_aggregator_id(struct lacp_aggregator *la, const struct lacp_port *lp) 1013168561Sthompsa{ 1014168561Sthompsa lacp_fill_aggregator_id_peer(&la->la_partner, &lp->lp_partner); 1015168561Sthompsa lacp_fill_aggregator_id_peer(&la->la_actor, &lp->lp_actor); 1016168561Sthompsa 1017168561Sthompsa la->la_actor.lip_state = lp->lp_state & LACP_STATE_AGGREGATION; 1018168561Sthompsa} 1019168561Sthompsa 1020168561Sthompsastatic void 1021168561Sthompsalacp_fill_aggregator_id_peer(struct lacp_peerinfo *lpi_aggr, 1022168561Sthompsa const struct lacp_peerinfo *lpi_port) 1023168561Sthompsa{ 1024168561Sthompsa memset(lpi_aggr, 0, sizeof(*lpi_aggr)); 1025168561Sthompsa lpi_aggr->lip_systemid = lpi_port->lip_systemid; 1026168561Sthompsa lpi_aggr->lip_key = lpi_port->lip_key; 1027168561Sthompsa} 1028168561Sthompsa 1029168561Sthompsa/* 1030168561Sthompsa * lacp_aggregator_is_compatible: check if a port can join to an aggregator. 1031168561Sthompsa */ 1032168561Sthompsa 1033168561Sthompsastatic int 1034168561Sthompsalacp_aggregator_is_compatible(const struct lacp_aggregator *la, 1035168561Sthompsa const struct lacp_port *lp) 1036168561Sthompsa{ 1037168561Sthompsa if (!(lp->lp_state & LACP_STATE_AGGREGATION) || 1038168561Sthompsa !(lp->lp_partner.lip_state & LACP_STATE_AGGREGATION)) { 1039168561Sthompsa return (0); 1040168561Sthompsa } 1041168561Sthompsa 1042168561Sthompsa if (!(la->la_actor.lip_state & LACP_STATE_AGGREGATION)) { 1043168561Sthompsa return (0); 1044168561Sthompsa } 1045168561Sthompsa 1046168561Sthompsa if (!lacp_peerinfo_is_compatible(&la->la_partner, &lp->lp_partner)) { 1047168561Sthompsa return (0); 1048168561Sthompsa } 1049168561Sthompsa 1050168561Sthompsa if (!lacp_peerinfo_is_compatible(&la->la_actor, &lp->lp_actor)) { 1051168561Sthompsa return (0); 1052168561Sthompsa } 1053168561Sthompsa 1054168561Sthompsa return (1); 1055168561Sthompsa} 1056168561Sthompsa 1057168561Sthompsastatic int 1058168561Sthompsalacp_peerinfo_is_compatible(const struct lacp_peerinfo *a, 1059168561Sthompsa const struct lacp_peerinfo *b) 1060168561Sthompsa{ 1061168561Sthompsa if (memcmp(&a->lip_systemid, &b->lip_systemid, 1062168561Sthompsa sizeof(a->lip_systemid))) { 1063168561Sthompsa return (0); 1064168561Sthompsa } 1065168561Sthompsa 1066168561Sthompsa if (memcmp(&a->lip_key, &b->lip_key, sizeof(a->lip_key))) { 1067168561Sthompsa return (0); 1068168561Sthompsa } 1069168561Sthompsa 1070168561Sthompsa return (1); 1071168561Sthompsa} 1072168561Sthompsa 1073168561Sthompsastatic void 1074168561Sthompsalacp_port_enable(struct lacp_port *lp) 1075168561Sthompsa{ 1076169227Sthompsa struct lagg_port *lgp = lp->lp_lagg; 1077169227Sthompsa 1078168561Sthompsa lp->lp_state |= LACP_STATE_AGGREGATION; 1079169227Sthompsa lgp->lp_flags &= ~LAGG_PORT_DISABLED; 1080168561Sthompsa} 1081168561Sthompsa 1082168561Sthompsastatic void 1083168561Sthompsalacp_port_disable(struct lacp_port *lp) 1084168561Sthompsa{ 1085169227Sthompsa struct lagg_port *lgp = lp->lp_lagg; 1086169227Sthompsa 1087168561Sthompsa lacp_set_mux(lp, LACP_MUX_DETACHED); 1088168561Sthompsa 1089168561Sthompsa lp->lp_state &= ~LACP_STATE_AGGREGATION; 1090168561Sthompsa lp->lp_selected = LACP_UNSELECTED; 1091168561Sthompsa lacp_sm_rx_record_default(lp); 1092168561Sthompsa lp->lp_partner.lip_state &= ~LACP_STATE_AGGREGATION; 1093168561Sthompsa lp->lp_state &= ~LACP_STATE_EXPIRED; 1094169227Sthompsa lgp->lp_flags |= LAGG_PORT_DISABLED; 1095168561Sthompsa} 1096168561Sthompsa 1097168561Sthompsa/* 1098168561Sthompsa * lacp_select: select an aggregator. create one if necessary. 1099168561Sthompsa */ 1100168561Sthompsastatic void 1101168561Sthompsalacp_select(struct lacp_port *lp) 1102168561Sthompsa{ 1103168561Sthompsa struct lacp_softc *lsc = lp->lp_lsc; 1104168561Sthompsa struct lacp_aggregator *la; 1105168561Sthompsa#if defined(LACP_DEBUG) 1106168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 1107168561Sthompsa#endif 1108168561Sthompsa 1109168561Sthompsa if (lp->lp_aggregator) { 1110168561Sthompsa return; 1111168561Sthompsa } 1112168561Sthompsa 1113168561Sthompsa KASSERT(!LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE), 1114168561Sthompsa ("timer_wait_while still active")); 1115168561Sthompsa 1116168561Sthompsa LACP_DPRINTF((lp, "port lagid=%s\n", 1117168561Sthompsa lacp_format_lagid(&lp->lp_actor, &lp->lp_partner, 1118168561Sthompsa buf, sizeof(buf)))); 1119168561Sthompsa 1120168561Sthompsa TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 1121168561Sthompsa if (lacp_aggregator_is_compatible(la, lp)) { 1122168561Sthompsa break; 1123168561Sthompsa } 1124168561Sthompsa } 1125168561Sthompsa 1126168561Sthompsa if (la == NULL) { 1127168561Sthompsa la = lacp_aggregator_get(lsc, lp); 1128168561Sthompsa if (la == NULL) { 1129168561Sthompsa LACP_DPRINTF((lp, "aggregator creation failed\n")); 1130168561Sthompsa 1131168561Sthompsa /* 1132168561Sthompsa * will retry on the next tick. 1133168561Sthompsa */ 1134168561Sthompsa 1135168561Sthompsa return; 1136168561Sthompsa } 1137168561Sthompsa lacp_fill_aggregator_id(la, lp); 1138168561Sthompsa LACP_DPRINTF((lp, "aggregator created\n")); 1139168561Sthompsa } else { 1140168561Sthompsa LACP_DPRINTF((lp, "compatible aggregator found\n")); 1141168561Sthompsa lacp_aggregator_addref(lsc, la); 1142168561Sthompsa } 1143168561Sthompsa 1144168561Sthompsa LACP_DPRINTF((lp, "aggregator lagid=%s\n", 1145168561Sthompsa lacp_format_lagid(&la->la_actor, &la->la_partner, 1146168561Sthompsa buf, sizeof(buf)))); 1147168561Sthompsa 1148168561Sthompsa lp->lp_aggregator = la; 1149168561Sthompsa lp->lp_selected = LACP_SELECTED; 1150168561Sthompsa} 1151168561Sthompsa 1152168561Sthompsa/* 1153168561Sthompsa * lacp_unselect: finish unselect/detach process. 1154168561Sthompsa */ 1155168561Sthompsa 1156168561Sthompsastatic void 1157168561Sthompsalacp_unselect(struct lacp_port *lp) 1158168561Sthompsa{ 1159168561Sthompsa struct lacp_softc *lsc = lp->lp_lsc; 1160168561Sthompsa struct lacp_aggregator *la = lp->lp_aggregator; 1161168561Sthompsa 1162168561Sthompsa KASSERT(!LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE), 1163168561Sthompsa ("timer_wait_while still active")); 1164168561Sthompsa 1165168561Sthompsa if (la == NULL) { 1166168561Sthompsa return; 1167168561Sthompsa } 1168168561Sthompsa 1169168561Sthompsa lp->lp_aggregator = NULL; 1170168561Sthompsa lacp_aggregator_delref(lsc, la); 1171168561Sthompsa} 1172168561Sthompsa 1173168561Sthompsa/* mux machine */ 1174168561Sthompsa 1175168561Sthompsastatic void 1176168561Sthompsalacp_sm_mux(struct lacp_port *lp) 1177168561Sthompsa{ 1178168561Sthompsa enum lacp_mux_state new_state; 1179168561Sthompsa boolean_t p_sync = 1180168561Sthompsa (lp->lp_partner.lip_state & LACP_STATE_SYNC) != 0; 1181168561Sthompsa boolean_t p_collecting = 1182168561Sthompsa (lp->lp_partner.lip_state & LACP_STATE_COLLECTING) != 0; 1183168561Sthompsa enum lacp_selected selected = lp->lp_selected; 1184168561Sthompsa struct lacp_aggregator *la; 1185168561Sthompsa 1186168561Sthompsa /* LACP_DPRINTF((lp, "%s: state %d\n", __func__, lp->lp_mux_state)); */ 1187168561Sthompsa 1188168561Sthompsare_eval: 1189168561Sthompsa la = lp->lp_aggregator; 1190168561Sthompsa KASSERT(lp->lp_mux_state == LACP_MUX_DETACHED || la != NULL, 1191168561Sthompsa ("MUX not detached")); 1192168561Sthompsa new_state = lp->lp_mux_state; 1193168561Sthompsa switch (lp->lp_mux_state) { 1194168561Sthompsa case LACP_MUX_DETACHED: 1195168561Sthompsa if (selected != LACP_UNSELECTED) { 1196168561Sthompsa new_state = LACP_MUX_WAITING; 1197168561Sthompsa } 1198168561Sthompsa break; 1199168561Sthompsa case LACP_MUX_WAITING: 1200168561Sthompsa KASSERT(la->la_pending > 0 || 1201168561Sthompsa !LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE), 1202168561Sthompsa ("timer_wait_while still active")); 1203168561Sthompsa if (selected == LACP_SELECTED && la->la_pending == 0) { 1204168561Sthompsa new_state = LACP_MUX_ATTACHED; 1205168561Sthompsa } else if (selected == LACP_UNSELECTED) { 1206168561Sthompsa new_state = LACP_MUX_DETACHED; 1207168561Sthompsa } 1208168561Sthompsa break; 1209168561Sthompsa case LACP_MUX_ATTACHED: 1210168561Sthompsa if (selected == LACP_SELECTED && p_sync) { 1211168561Sthompsa new_state = LACP_MUX_COLLECTING; 1212168561Sthompsa } else if (selected != LACP_SELECTED) { 1213168561Sthompsa new_state = LACP_MUX_DETACHED; 1214168561Sthompsa } 1215168561Sthompsa break; 1216168561Sthompsa case LACP_MUX_COLLECTING: 1217168561Sthompsa if (selected == LACP_SELECTED && p_sync && p_collecting) { 1218168561Sthompsa new_state = LACP_MUX_DISTRIBUTING; 1219168561Sthompsa } else if (selected != LACP_SELECTED || !p_sync) { 1220168561Sthompsa new_state = LACP_MUX_ATTACHED; 1221168561Sthompsa } 1222168561Sthompsa break; 1223168561Sthompsa case LACP_MUX_DISTRIBUTING: 1224168561Sthompsa if (selected != LACP_SELECTED || !p_sync || !p_collecting) { 1225168561Sthompsa new_state = LACP_MUX_COLLECTING; 1226168561Sthompsa } 1227168561Sthompsa break; 1228168561Sthompsa default: 1229168561Sthompsa panic("%s: unknown state", __func__); 1230168561Sthompsa } 1231168561Sthompsa 1232168561Sthompsa if (lp->lp_mux_state == new_state) { 1233168561Sthompsa return; 1234168561Sthompsa } 1235168561Sthompsa 1236168561Sthompsa lacp_set_mux(lp, new_state); 1237168561Sthompsa goto re_eval; 1238168561Sthompsa} 1239168561Sthompsa 1240168561Sthompsastatic void 1241168561Sthompsalacp_set_mux(struct lacp_port *lp, enum lacp_mux_state new_state) 1242168561Sthompsa{ 1243168561Sthompsa struct lacp_aggregator *la = lp->lp_aggregator; 1244168561Sthompsa 1245168561Sthompsa if (lp->lp_mux_state == new_state) { 1246168561Sthompsa return; 1247168561Sthompsa } 1248168561Sthompsa 1249168561Sthompsa switch (new_state) { 1250168561Sthompsa case LACP_MUX_DETACHED: 1251168561Sthompsa lp->lp_state &= ~LACP_STATE_SYNC; 1252168561Sthompsa lacp_disable_distributing(lp); 1253168561Sthompsa lacp_disable_collecting(lp); 1254168561Sthompsa lacp_sm_assert_ntt(lp); 1255168561Sthompsa /* cancel timer */ 1256168561Sthompsa if (LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE)) { 1257168561Sthompsa KASSERT(la->la_pending > 0, 1258168561Sthompsa ("timer_wait_while not active")); 1259168561Sthompsa la->la_pending--; 1260168561Sthompsa } 1261168561Sthompsa LACP_TIMER_DISARM(lp, LACP_TIMER_WAIT_WHILE); 1262168561Sthompsa lacp_unselect(lp); 1263168561Sthompsa break; 1264168561Sthompsa case LACP_MUX_WAITING: 1265168561Sthompsa LACP_TIMER_ARM(lp, LACP_TIMER_WAIT_WHILE, 1266168561Sthompsa LACP_AGGREGATE_WAIT_TIME); 1267168561Sthompsa la->la_pending++; 1268168561Sthompsa break; 1269168561Sthompsa case LACP_MUX_ATTACHED: 1270168561Sthompsa lp->lp_state |= LACP_STATE_SYNC; 1271168561Sthompsa lacp_disable_collecting(lp); 1272168561Sthompsa lacp_sm_assert_ntt(lp); 1273168561Sthompsa break; 1274168561Sthompsa case LACP_MUX_COLLECTING: 1275168561Sthompsa lacp_enable_collecting(lp); 1276168561Sthompsa lacp_disable_distributing(lp); 1277168561Sthompsa lacp_sm_assert_ntt(lp); 1278168561Sthompsa break; 1279168561Sthompsa case LACP_MUX_DISTRIBUTING: 1280168561Sthompsa lacp_enable_distributing(lp); 1281168561Sthompsa break; 1282168561Sthompsa default: 1283168561Sthompsa panic("%s: unknown state", __func__); 1284168561Sthompsa } 1285168561Sthompsa 1286168561Sthompsa LACP_DPRINTF((lp, "mux_state %d -> %d\n", lp->lp_mux_state, new_state)); 1287168561Sthompsa 1288168561Sthompsa lp->lp_mux_state = new_state; 1289168561Sthompsa} 1290168561Sthompsa 1291168561Sthompsastatic void 1292168561Sthompsalacp_sm_mux_timer(struct lacp_port *lp) 1293168561Sthompsa{ 1294168561Sthompsa struct lacp_aggregator *la = lp->lp_aggregator; 1295168561Sthompsa#if defined(LACP_DEBUG) 1296168561Sthompsa char buf[LACP_LAGIDSTR_MAX+1]; 1297168561Sthompsa#endif 1298168561Sthompsa 1299168561Sthompsa KASSERT(la->la_pending > 0, ("no pending event")); 1300168561Sthompsa 1301168561Sthompsa LACP_DPRINTF((lp, "%s: aggregator %s, pending %d -> %d\n", __func__, 1302168561Sthompsa lacp_format_lagid(&la->la_actor, &la->la_partner, 1303168561Sthompsa buf, sizeof(buf)), 1304168561Sthompsa la->la_pending, la->la_pending - 1)); 1305168561Sthompsa 1306168561Sthompsa la->la_pending--; 1307168561Sthompsa} 1308168561Sthompsa 1309168561Sthompsa/* periodic transmit machine */ 1310168561Sthompsa 1311168561Sthompsastatic void 1312168561Sthompsalacp_sm_ptx_update_timeout(struct lacp_port *lp, uint8_t oldpstate) 1313168561Sthompsa{ 1314168561Sthompsa if (LACP_STATE_EQ(oldpstate, lp->lp_partner.lip_state, 1315168561Sthompsa LACP_STATE_TIMEOUT)) { 1316168561Sthompsa return; 1317168561Sthompsa } 1318168561Sthompsa 1319168561Sthompsa LACP_DPRINTF((lp, "partner timeout changed\n")); 1320168561Sthompsa 1321168561Sthompsa /* 1322168561Sthompsa * FAST_PERIODIC -> SLOW_PERIODIC 1323168561Sthompsa * or 1324168561Sthompsa * SLOW_PERIODIC (-> PERIODIC_TX) -> FAST_PERIODIC 1325168561Sthompsa * 1326168561Sthompsa * let lacp_sm_ptx_tx_schedule to update timeout. 1327168561Sthompsa */ 1328168561Sthompsa 1329168561Sthompsa LACP_TIMER_DISARM(lp, LACP_TIMER_PERIODIC); 1330168561Sthompsa 1331168561Sthompsa /* 1332168561Sthompsa * if timeout has been shortened, assert NTT. 1333168561Sthompsa */ 1334168561Sthompsa 1335168561Sthompsa if ((lp->lp_partner.lip_state & LACP_STATE_TIMEOUT)) { 1336168561Sthompsa lacp_sm_assert_ntt(lp); 1337168561Sthompsa } 1338168561Sthompsa} 1339168561Sthompsa 1340168561Sthompsastatic void 1341168561Sthompsalacp_sm_ptx_tx_schedule(struct lacp_port *lp) 1342168561Sthompsa{ 1343168561Sthompsa int timeout; 1344168561Sthompsa 1345168561Sthompsa if (!(lp->lp_state & LACP_STATE_ACTIVITY) && 1346168561Sthompsa !(lp->lp_partner.lip_state & LACP_STATE_ACTIVITY)) { 1347168561Sthompsa 1348168561Sthompsa /* 1349168561Sthompsa * NO_PERIODIC 1350168561Sthompsa */ 1351168561Sthompsa 1352168561Sthompsa LACP_TIMER_DISARM(lp, LACP_TIMER_PERIODIC); 1353168561Sthompsa return; 1354168561Sthompsa } 1355168561Sthompsa 1356168561Sthompsa if (LACP_TIMER_ISARMED(lp, LACP_TIMER_PERIODIC)) { 1357168561Sthompsa return; 1358168561Sthompsa } 1359168561Sthompsa 1360168561Sthompsa timeout = (lp->lp_partner.lip_state & LACP_STATE_TIMEOUT) ? 1361168561Sthompsa LACP_FAST_PERIODIC_TIME : LACP_SLOW_PERIODIC_TIME; 1362168561Sthompsa 1363168561Sthompsa LACP_TIMER_ARM(lp, LACP_TIMER_PERIODIC, timeout); 1364168561Sthompsa} 1365168561Sthompsa 1366168561Sthompsastatic void 1367168561Sthompsalacp_sm_ptx_timer(struct lacp_port *lp) 1368168561Sthompsa{ 1369168561Sthompsa lacp_sm_assert_ntt(lp); 1370168561Sthompsa} 1371168561Sthompsa 1372168561Sthompsastatic void 1373168561Sthompsalacp_sm_rx(struct lacp_port *lp, const struct lacpdu *du) 1374168561Sthompsa{ 1375168561Sthompsa int timeout; 1376168561Sthompsa 1377168561Sthompsa /* 1378168561Sthompsa * check LACP_DISABLED first 1379168561Sthompsa */ 1380168561Sthompsa 1381168561Sthompsa if (!(lp->lp_state & LACP_STATE_AGGREGATION)) { 1382168561Sthompsa return; 1383168561Sthompsa } 1384168561Sthompsa 1385168561Sthompsa /* 1386168561Sthompsa * check loopback condition. 1387168561Sthompsa */ 1388168561Sthompsa 1389168561Sthompsa if (!lacp_compare_systemid(&du->ldu_actor.lip_systemid, 1390168561Sthompsa &lp->lp_actor.lip_systemid)) { 1391168561Sthompsa return; 1392168561Sthompsa } 1393168561Sthompsa 1394168561Sthompsa /* 1395168561Sthompsa * EXPIRED, DEFAULTED, CURRENT -> CURRENT 1396168561Sthompsa */ 1397168561Sthompsa 1398168561Sthompsa lacp_sm_rx_update_selected(lp, du); 1399168561Sthompsa lacp_sm_rx_update_ntt(lp, du); 1400168561Sthompsa lacp_sm_rx_record_pdu(lp, du); 1401168561Sthompsa 1402168561Sthompsa timeout = (lp->lp_state & LACP_STATE_TIMEOUT) ? 1403168561Sthompsa LACP_SHORT_TIMEOUT_TIME : LACP_LONG_TIMEOUT_TIME; 1404168561Sthompsa LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, timeout); 1405168561Sthompsa 1406168561Sthompsa lp->lp_state &= ~LACP_STATE_EXPIRED; 1407168561Sthompsa 1408168561Sthompsa /* 1409168561Sthompsa * kick transmit machine without waiting the next tick. 1410168561Sthompsa */ 1411168561Sthompsa 1412168561Sthompsa lacp_sm_tx(lp); 1413168561Sthompsa} 1414168561Sthompsa 1415168561Sthompsastatic void 1416168561Sthompsalacp_sm_rx_set_expired(struct lacp_port *lp) 1417168561Sthompsa{ 1418168561Sthompsa lp->lp_partner.lip_state &= ~LACP_STATE_SYNC; 1419168561Sthompsa lp->lp_partner.lip_state |= LACP_STATE_TIMEOUT; 1420168561Sthompsa LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, LACP_SHORT_TIMEOUT_TIME); 1421168561Sthompsa lp->lp_state |= LACP_STATE_EXPIRED; 1422168561Sthompsa} 1423168561Sthompsa 1424168561Sthompsastatic void 1425168561Sthompsalacp_sm_rx_timer(struct lacp_port *lp) 1426168561Sthompsa{ 1427168561Sthompsa if ((lp->lp_state & LACP_STATE_EXPIRED) == 0) { 1428168561Sthompsa /* CURRENT -> EXPIRED */ 1429168561Sthompsa LACP_DPRINTF((lp, "%s: CURRENT -> EXPIRED\n", __func__)); 1430168561Sthompsa lacp_sm_rx_set_expired(lp); 1431168561Sthompsa } else { 1432168561Sthompsa /* EXPIRED -> DEFAULTED */ 1433168561Sthompsa LACP_DPRINTF((lp, "%s: EXPIRED -> DEFAULTED\n", __func__)); 1434168561Sthompsa lacp_sm_rx_update_default_selected(lp); 1435168561Sthompsa lacp_sm_rx_record_default(lp); 1436168561Sthompsa lp->lp_state &= ~LACP_STATE_EXPIRED; 1437168561Sthompsa } 1438168561Sthompsa} 1439168561Sthompsa 1440168561Sthompsastatic void 1441168561Sthompsalacp_sm_rx_record_pdu(struct lacp_port *lp, const struct lacpdu *du) 1442168561Sthompsa{ 1443168561Sthompsa boolean_t active; 1444168561Sthompsa uint8_t oldpstate; 1445168561Sthompsa#if defined(LACP_DEBUG) 1446168561Sthompsa char buf[LACP_STATESTR_MAX+1]; 1447168561Sthompsa#endif 1448168561Sthompsa 1449168561Sthompsa /* LACP_DPRINTF((lp, "%s\n", __func__)); */ 1450168561Sthompsa 1451168561Sthompsa oldpstate = lp->lp_partner.lip_state; 1452168561Sthompsa 1453168561Sthompsa active = (du->ldu_actor.lip_state & LACP_STATE_ACTIVITY) 1454168561Sthompsa || ((lp->lp_state & LACP_STATE_ACTIVITY) && 1455168561Sthompsa (du->ldu_partner.lip_state & LACP_STATE_ACTIVITY)); 1456168561Sthompsa 1457168561Sthompsa lp->lp_partner = du->ldu_actor; 1458168561Sthompsa if (active && 1459168561Sthompsa ((LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state, 1460168561Sthompsa LACP_STATE_AGGREGATION) && 1461168561Sthompsa !lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner)) 1462168561Sthompsa || (du->ldu_partner.lip_state & LACP_STATE_AGGREGATION) == 0)) { 1463168561Sthompsa /* XXX nothing? */ 1464168561Sthompsa } else { 1465168561Sthompsa lp->lp_partner.lip_state &= ~LACP_STATE_SYNC; 1466168561Sthompsa } 1467168561Sthompsa 1468168561Sthompsa lp->lp_state &= ~LACP_STATE_DEFAULTED; 1469168561Sthompsa 1470168561Sthompsa if (oldpstate != lp->lp_partner.lip_state) { 1471168561Sthompsa LACP_DPRINTF((lp, "old pstate %s\n", 1472168561Sthompsa lacp_format_state(oldpstate, buf, sizeof(buf)))); 1473168561Sthompsa LACP_DPRINTF((lp, "new pstate %s\n", 1474168561Sthompsa lacp_format_state(lp->lp_partner.lip_state, buf, 1475168561Sthompsa sizeof(buf)))); 1476168561Sthompsa } 1477168561Sthompsa 1478168561Sthompsa lacp_sm_ptx_update_timeout(lp, oldpstate); 1479168561Sthompsa} 1480168561Sthompsa 1481168561Sthompsastatic void 1482168561Sthompsalacp_sm_rx_update_ntt(struct lacp_port *lp, const struct lacpdu *du) 1483168561Sthompsa{ 1484168561Sthompsa /* LACP_DPRINTF((lp, "%s\n", __func__)); */ 1485168561Sthompsa 1486168561Sthompsa if (lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner) || 1487168561Sthompsa !LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state, 1488168561Sthompsa LACP_STATE_ACTIVITY | LACP_STATE_SYNC | LACP_STATE_AGGREGATION)) { 1489168561Sthompsa LACP_DPRINTF((lp, "%s: assert ntt\n", __func__)); 1490168561Sthompsa lacp_sm_assert_ntt(lp); 1491168561Sthompsa } 1492168561Sthompsa} 1493168561Sthompsa 1494168561Sthompsastatic void 1495168561Sthompsalacp_sm_rx_record_default(struct lacp_port *lp) 1496168561Sthompsa{ 1497168561Sthompsa uint8_t oldpstate; 1498168561Sthompsa 1499168561Sthompsa /* LACP_DPRINTF((lp, "%s\n", __func__)); */ 1500168561Sthompsa 1501168561Sthompsa oldpstate = lp->lp_partner.lip_state; 1502168561Sthompsa lp->lp_partner = lacp_partner_admin; 1503168561Sthompsa lp->lp_state |= LACP_STATE_DEFAULTED; 1504168561Sthompsa lacp_sm_ptx_update_timeout(lp, oldpstate); 1505168561Sthompsa} 1506168561Sthompsa 1507168561Sthompsastatic void 1508168561Sthompsalacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *lp, 1509168561Sthompsa const struct lacp_peerinfo *info) 1510168561Sthompsa{ 1511168561Sthompsa /* LACP_DPRINTF((lp, "%s\n", __func__)); */ 1512168561Sthompsa 1513168561Sthompsa if (lacp_compare_peerinfo(&lp->lp_partner, info) || 1514168561Sthompsa !LACP_STATE_EQ(lp->lp_partner.lip_state, info->lip_state, 1515168561Sthompsa LACP_STATE_AGGREGATION)) { 1516168561Sthompsa lp->lp_selected = LACP_UNSELECTED; 1517168561Sthompsa /* mux machine will clean up lp->lp_aggregator */ 1518168561Sthompsa } 1519168561Sthompsa} 1520168561Sthompsa 1521168561Sthompsastatic void 1522168561Sthompsalacp_sm_rx_update_selected(struct lacp_port *lp, const struct lacpdu *du) 1523168561Sthompsa{ 1524168561Sthompsa /* LACP_DPRINTF((lp, "%s\n", __func__)); */ 1525168561Sthompsa 1526168561Sthompsa lacp_sm_rx_update_selected_from_peerinfo(lp, &du->ldu_actor); 1527168561Sthompsa} 1528168561Sthompsa 1529168561Sthompsastatic void 1530168561Sthompsalacp_sm_rx_update_default_selected(struct lacp_port *lp) 1531168561Sthompsa{ 1532168561Sthompsa /* LACP_DPRINTF((lp, "%s\n", __func__)); */ 1533168561Sthompsa 1534168561Sthompsa lacp_sm_rx_update_selected_from_peerinfo(lp, &lacp_partner_admin); 1535168561Sthompsa} 1536168561Sthompsa 1537168561Sthompsa/* transmit machine */ 1538168561Sthompsa 1539168561Sthompsastatic void 1540168561Sthompsalacp_sm_tx(struct lacp_port *lp) 1541168561Sthompsa{ 1542168561Sthompsa int error; 1543168561Sthompsa 1544168561Sthompsa if (!(lp->lp_state & LACP_STATE_AGGREGATION) 1545168561Sthompsa#if 1 1546168561Sthompsa || (!(lp->lp_state & LACP_STATE_ACTIVITY) 1547168561Sthompsa && !(lp->lp_partner.lip_state & LACP_STATE_ACTIVITY)) 1548168561Sthompsa#endif 1549168561Sthompsa ) { 1550168561Sthompsa lp->lp_flags &= ~LACP_PORT_NTT; 1551168561Sthompsa } 1552168561Sthompsa 1553168561Sthompsa if (!(lp->lp_flags & LACP_PORT_NTT)) { 1554168561Sthompsa return; 1555168561Sthompsa } 1556168561Sthompsa 1557168561Sthompsa /* Rate limit to 3 PDUs per LACP_FAST_PERIODIC_TIME */ 1558168561Sthompsa if (ppsratecheck(&lp->lp_last_lacpdu, &lp->lp_lacpdu_sent, 1559168561Sthompsa (3 / LACP_FAST_PERIODIC_TIME)) == 0) { 1560168561Sthompsa LACP_DPRINTF((lp, "rate limited pdu\n")); 1561168561Sthompsa return; 1562168561Sthompsa } 1563168561Sthompsa 1564168561Sthompsa error = lacp_xmit_lacpdu(lp); 1565168561Sthompsa 1566168561Sthompsa if (error == 0) { 1567168561Sthompsa lp->lp_flags &= ~LACP_PORT_NTT; 1568168561Sthompsa } else { 1569168561Sthompsa LACP_DPRINTF((lp, "lacpdu transmit failure, error %d\n", 1570168561Sthompsa error)); 1571168561Sthompsa } 1572168561Sthompsa} 1573168561Sthompsa 1574168561Sthompsastatic void 1575168561Sthompsalacp_sm_assert_ntt(struct lacp_port *lp) 1576168561Sthompsa{ 1577168561Sthompsa 1578168561Sthompsa lp->lp_flags |= LACP_PORT_NTT; 1579168561Sthompsa} 1580168561Sthompsa 1581168561Sthompsastatic void 1582168561Sthompsalacp_run_timers(struct lacp_port *lp) 1583168561Sthompsa{ 1584168561Sthompsa int i; 1585168561Sthompsa 1586168561Sthompsa for (i = 0; i < LACP_NTIMER; i++) { 1587168561Sthompsa KASSERT(lp->lp_timer[i] >= 0, 1588168561Sthompsa ("invalid timer value %d", lp->lp_timer[i])); 1589168561Sthompsa if (lp->lp_timer[i] == 0) { 1590168561Sthompsa continue; 1591168561Sthompsa } else if (--lp->lp_timer[i] <= 0) { 1592168561Sthompsa if (lacp_timer_funcs[i]) { 1593168561Sthompsa (*lacp_timer_funcs[i])(lp); 1594168561Sthompsa } 1595168561Sthompsa } 1596168561Sthompsa } 1597168561Sthompsa} 1598168561Sthompsa 1599168561Sthompsaint 1600168793Sthompsalacp_marker_input(struct lagg_port *lgp, struct mbuf *m) 1601168561Sthompsa{ 1602168793Sthompsa struct lacp_port *lp = LACP_PORT(lgp); 1603168561Sthompsa struct markerdu *mdu; 1604168561Sthompsa int error = 0; 1605168561Sthompsa 1606169569Sthompsa LAGG_RLOCK_ASSERT(lgp->lp_lagg); 1607168561Sthompsa 1608168561Sthompsa if (__predict_false(lp->lp_flags & LACP_PORT_DETACHING)) { 1609168561Sthompsa goto bad; 1610168561Sthompsa } 1611168561Sthompsa 1612168561Sthompsa if (m->m_pkthdr.len != sizeof(*mdu)) { 1613168561Sthompsa goto bad; 1614168561Sthompsa } 1615168561Sthompsa 1616168561Sthompsa if ((m->m_flags & M_MCAST) == 0) { 1617168561Sthompsa goto bad; 1618168561Sthompsa } 1619168561Sthompsa 1620168561Sthompsa if (m->m_len < sizeof(*mdu)) { 1621168561Sthompsa m = m_pullup(m, sizeof(*mdu)); 1622168561Sthompsa if (m == NULL) { 1623168561Sthompsa return (ENOMEM); 1624168561Sthompsa } 1625168561Sthompsa } 1626168561Sthompsa 1627168561Sthompsa mdu = mtod(m, struct markerdu *); 1628168561Sthompsa 1629168561Sthompsa if (memcmp(&mdu->mdu_eh.ether_dhost, 1630168561Sthompsa ðermulticastaddr_slowprotocols, ETHER_ADDR_LEN)) { 1631168561Sthompsa goto bad; 1632168561Sthompsa } 1633168561Sthompsa 1634168561Sthompsa /* XXX 1635168561Sthompsa KASSERT(mdu->mdu_sph.sph_subtype == SLOWPROTOCOLS_SUBTYPE_MARKER, 1636168561Sthompsa ("a very bad kassert!")); 1637168561Sthompsa */ 1638168561Sthompsa 1639168561Sthompsa if (mdu->mdu_sph.sph_version != 1) { 1640168561Sthompsa goto bad; 1641168561Sthompsa } 1642168561Sthompsa 1643168561Sthompsa switch (mdu->mdu_tlv.tlv_type) { 1644168561Sthompsa case MARKER_TYPE_INFO: 1645168561Sthompsa if (tlv_check(mdu, sizeof(*mdu), &mdu->mdu_tlv, 1646168561Sthompsa marker_info_tlv_template, TRUE)) { 1647168561Sthompsa goto bad; 1648168561Sthompsa } 1649168561Sthompsa mdu->mdu_tlv.tlv_type = MARKER_TYPE_RESPONSE; 1650168561Sthompsa memcpy(&mdu->mdu_eh.ether_dhost, 1651168561Sthompsa ðermulticastaddr_slowprotocols, ETHER_ADDR_LEN); 1652168561Sthompsa memcpy(&mdu->mdu_eh.ether_shost, 1653168793Sthompsa lgp->lp_lladdr, ETHER_ADDR_LEN); 1654168793Sthompsa error = lagg_enqueue(lp->lp_ifp, m); 1655168561Sthompsa break; 1656168561Sthompsa 1657168561Sthompsa case MARKER_TYPE_RESPONSE: 1658168561Sthompsa if (tlv_check(mdu, sizeof(*mdu), &mdu->mdu_tlv, 1659168561Sthompsa marker_response_tlv_template, TRUE)) { 1660168561Sthompsa goto bad; 1661168561Sthompsa } 1662168561Sthompsa /* 1663168561Sthompsa * we are not interested in responses as 1664168561Sthompsa * we don't have a marker sender. 1665168561Sthompsa */ 1666168561Sthompsa /* FALLTHROUGH */ 1667168561Sthompsa default: 1668168561Sthompsa goto bad; 1669168561Sthompsa } 1670168561Sthompsa 1671168561Sthompsa return (error); 1672168561Sthompsa 1673168561Sthompsabad: 1674168561Sthompsa m_freem(m); 1675168561Sthompsa return (EINVAL); 1676168561Sthompsa} 1677168561Sthompsa 1678168561Sthompsastatic int 1679168561Sthompsatlv_check(const void *p, size_t size, const struct tlvhdr *tlv, 1680168561Sthompsa const struct tlv_template *tmpl, boolean_t check_type) 1681168561Sthompsa{ 1682168561Sthompsa while (/* CONSTCOND */ 1) { 1683168561Sthompsa if ((const char *)tlv - (const char *)p + sizeof(*tlv) > size) { 1684168561Sthompsa return (EINVAL); 1685168561Sthompsa } 1686168561Sthompsa if ((check_type && tlv->tlv_type != tmpl->tmpl_type) || 1687168561Sthompsa tlv->tlv_length != tmpl->tmpl_length) { 1688168561Sthompsa return (EINVAL); 1689168561Sthompsa } 1690168561Sthompsa if (tmpl->tmpl_type == 0) { 1691168561Sthompsa break; 1692168561Sthompsa } 1693168561Sthompsa tlv = (const struct tlvhdr *) 1694168561Sthompsa ((const char *)tlv + tlv->tlv_length); 1695168561Sthompsa tmpl++; 1696168561Sthompsa } 1697168561Sthompsa 1698168561Sthompsa return (0); 1699168561Sthompsa} 1700168561Sthompsa 1701168561Sthompsa#if defined(LACP_DEBUG) 1702168561Sthompsaconst char * 1703168561Sthompsalacp_format_mac(const uint8_t *mac, char *buf, size_t buflen) 1704168561Sthompsa{ 1705168561Sthompsa snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X", 1706168561Sthompsa (int)mac[0], 1707168561Sthompsa (int)mac[1], 1708168561Sthompsa (int)mac[2], 1709168561Sthompsa (int)mac[3], 1710168561Sthompsa (int)mac[4], 1711168561Sthompsa (int)mac[5]); 1712168561Sthompsa 1713168561Sthompsa return (buf); 1714168561Sthompsa} 1715168561Sthompsa 1716168561Sthompsaconst char * 1717168561Sthompsalacp_format_systemid(const struct lacp_systemid *sysid, 1718168561Sthompsa char *buf, size_t buflen) 1719168561Sthompsa{ 1720168561Sthompsa char macbuf[LACP_MACSTR_MAX+1]; 1721168561Sthompsa 1722168561Sthompsa snprintf(buf, buflen, "%04X,%s", 1723168561Sthompsa ntohs(sysid->lsi_prio), 1724168561Sthompsa lacp_format_mac(sysid->lsi_mac, macbuf, sizeof(macbuf))); 1725168561Sthompsa 1726168561Sthompsa return (buf); 1727168561Sthompsa} 1728168561Sthompsa 1729168561Sthompsaconst char * 1730168561Sthompsalacp_format_portid(const struct lacp_portid *portid, char *buf, size_t buflen) 1731168561Sthompsa{ 1732168561Sthompsa snprintf(buf, buflen, "%04X,%04X", 1733168561Sthompsa ntohs(portid->lpi_prio), 1734168561Sthompsa ntohs(portid->lpi_portno)); 1735168561Sthompsa 1736168561Sthompsa return (buf); 1737168561Sthompsa} 1738168561Sthompsa 1739168561Sthompsaconst char * 1740168561Sthompsalacp_format_partner(const struct lacp_peerinfo *peer, char *buf, size_t buflen) 1741168561Sthompsa{ 1742168561Sthompsa char sysid[LACP_SYSTEMIDSTR_MAX+1]; 1743168561Sthompsa char portid[LACP_PORTIDSTR_MAX+1]; 1744168561Sthompsa 1745168561Sthompsa snprintf(buf, buflen, "(%s,%04X,%s)", 1746168561Sthompsa lacp_format_systemid(&peer->lip_systemid, sysid, sizeof(sysid)), 1747168561Sthompsa ntohs(peer->lip_key), 1748168561Sthompsa lacp_format_portid(&peer->lip_portid, portid, sizeof(portid))); 1749168561Sthompsa 1750168561Sthompsa return (buf); 1751168561Sthompsa} 1752168561Sthompsa 1753168561Sthompsaconst char * 1754168561Sthompsalacp_format_lagid(const struct lacp_peerinfo *a, 1755168561Sthompsa const struct lacp_peerinfo *b, char *buf, size_t buflen) 1756168561Sthompsa{ 1757168561Sthompsa char astr[LACP_PARTNERSTR_MAX+1]; 1758168561Sthompsa char bstr[LACP_PARTNERSTR_MAX+1]; 1759168561Sthompsa 1760168561Sthompsa#if 0 1761168561Sthompsa /* 1762168561Sthompsa * there's a convention to display small numbered peer 1763168561Sthompsa * in the left. 1764168561Sthompsa */ 1765168561Sthompsa 1766168561Sthompsa if (lacp_compare_peerinfo(a, b) > 0) { 1767168561Sthompsa const struct lacp_peerinfo *t; 1768168561Sthompsa 1769168561Sthompsa t = a; 1770168561Sthompsa a = b; 1771168561Sthompsa b = t; 1772168561Sthompsa } 1773168561Sthompsa#endif 1774168561Sthompsa 1775168561Sthompsa snprintf(buf, buflen, "[%s,%s]", 1776168561Sthompsa lacp_format_partner(a, astr, sizeof(astr)), 1777168561Sthompsa lacp_format_partner(b, bstr, sizeof(bstr))); 1778168561Sthompsa 1779168561Sthompsa return (buf); 1780168561Sthompsa} 1781168561Sthompsa 1782168561Sthompsaconst char * 1783168561Sthompsalacp_format_lagid_aggregator(const struct lacp_aggregator *la, 1784168561Sthompsa char *buf, size_t buflen) 1785168561Sthompsa{ 1786168561Sthompsa if (la == NULL) { 1787168561Sthompsa return ("(none)"); 1788168561Sthompsa } 1789168561Sthompsa 1790168561Sthompsa return (lacp_format_lagid(&la->la_actor, &la->la_partner, buf, buflen)); 1791168561Sthompsa} 1792168561Sthompsa 1793168561Sthompsaconst char * 1794168561Sthompsalacp_format_state(uint8_t state, char *buf, size_t buflen) 1795168561Sthompsa{ 1796168561Sthompsa snprintf(buf, buflen, "%b", state, LACP_STATE_BITS); 1797168561Sthompsa return (buf); 1798168561Sthompsa} 1799168561Sthompsa 1800168561Sthompsastatic void 1801168561Sthompsalacp_dump_lacpdu(const struct lacpdu *du) 1802168561Sthompsa{ 1803168561Sthompsa char buf[LACP_PARTNERSTR_MAX+1]; 1804168561Sthompsa char buf2[LACP_STATESTR_MAX+1]; 1805168561Sthompsa 1806168561Sthompsa printf("actor=%s\n", 1807168561Sthompsa lacp_format_partner(&du->ldu_actor, buf, sizeof(buf))); 1808168561Sthompsa printf("actor.state=%s\n", 1809168561Sthompsa lacp_format_state(du->ldu_actor.lip_state, buf2, sizeof(buf2))); 1810168561Sthompsa printf("partner=%s\n", 1811168561Sthompsa lacp_format_partner(&du->ldu_partner, buf, sizeof(buf))); 1812168561Sthompsa printf("partner.state=%s\n", 1813168561Sthompsa lacp_format_state(du->ldu_partner.lip_state, buf2, sizeof(buf2))); 1814168561Sthompsa 1815168561Sthompsa printf("maxdelay=%d\n", ntohs(du->ldu_collector.lci_maxdelay)); 1816168561Sthompsa} 1817168561Sthompsa 1818168561Sthompsastatic void 1819168561Sthompsalacp_dprintf(const struct lacp_port *lp, const char *fmt, ...) 1820168561Sthompsa{ 1821168561Sthompsa va_list va; 1822168561Sthompsa 1823168561Sthompsa if (lp) { 1824168561Sthompsa printf("%s: ", lp->lp_ifp->if_xname); 1825168561Sthompsa } 1826168561Sthompsa 1827168561Sthompsa va_start(va, fmt); 1828168561Sthompsa vprintf(fmt, va); 1829168561Sthompsa va_end(va); 1830168561Sthompsa} 1831168561Sthompsa#endif 1832