1 1.43 yamaguch /* $NetBSD: if_lagg_lacp.c,v 1.43 2024/04/05 06:31:37 yamaguchi Exp $ */ 2 1.1 yamaguch 3 1.1 yamaguch /*- 4 1.1 yamaguch * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5 1.1 yamaguch * 6 1.1 yamaguch * Copyright (c)2005 YAMAMOTO Takashi, 7 1.1 yamaguch * Copyright (c)2008 Andrew Thompson <thompsa (at) FreeBSD.org> 8 1.1 yamaguch * Copyright (c)2021 Internet Initiative Japan, Inc. 9 1.1 yamaguch * All rights reserved. 10 1.1 yamaguch * 11 1.1 yamaguch * Redistribution and use in source and binary forms, with or without 12 1.1 yamaguch * modification, are permitted provided that the following conditions 13 1.1 yamaguch * are met: 14 1.1 yamaguch * 1. Redistributions of source code must retain the above copyright 15 1.1 yamaguch * notice, this list of conditions and the following disclaimer. 16 1.1 yamaguch * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 yamaguch * notice, this list of conditions and the following disclaimer in the 18 1.1 yamaguch * documentation and/or other materials provided with the distribution. 19 1.1 yamaguch * 20 1.1 yamaguch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 1.1 yamaguch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 yamaguch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 yamaguch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 1.1 yamaguch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 yamaguch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 yamaguch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 yamaguch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 yamaguch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 yamaguch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 yamaguch * SUCH DAMAGE. 31 1.1 yamaguch */ 32 1.1 yamaguch 33 1.1 yamaguch #include <sys/cdefs.h> 34 1.43 yamaguch __KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp.c,v 1.43 2024/04/05 06:31:37 yamaguchi Exp $"); 35 1.1 yamaguch 36 1.1 yamaguch #ifdef _KERNEL_OPT 37 1.1 yamaguch #include "opt_lagg.h" 38 1.1 yamaguch #endif 39 1.1 yamaguch 40 1.1 yamaguch #include <sys/param.h> 41 1.1 yamaguch #include <sys/types.h> 42 1.1 yamaguch 43 1.1 yamaguch #include <sys/evcnt.h> 44 1.1 yamaguch #include <sys/kmem.h> 45 1.18 yamaguch #include <sys/pcq.h> 46 1.1 yamaguch #include <sys/pslist.h> 47 1.1 yamaguch #include <sys/sysctl.h> 48 1.1 yamaguch #include <sys/syslog.h> 49 1.1 yamaguch #include <sys/workqueue.h> 50 1.1 yamaguch 51 1.1 yamaguch #include <net/if.h> 52 1.1 yamaguch #include <net/if_dl.h> 53 1.1 yamaguch #include <net/if_ether.h> 54 1.1 yamaguch #include <net/if_media.h> 55 1.1 yamaguch 56 1.9 yamaguch #include <net/ether_slowprotocols.h> 57 1.9 yamaguch 58 1.1 yamaguch #include <net/lagg/if_lagg.h> 59 1.1 yamaguch #include <net/lagg/if_laggproto.h> 60 1.1 yamaguch #include <net/lagg/if_lagg_lacp.h> 61 1.1 yamaguch 62 1.1 yamaguch #define LACP_SYSTEMIDSTR_LEN 32 63 1.1 yamaguch 64 1.1 yamaguch enum { 65 1.1 yamaguch LACP_TIMER_CURRENT_WHILE = 0, 66 1.1 yamaguch LACP_TIMER_PERIODIC, 67 1.1 yamaguch LACP_TIMER_WAIT_WHILE, 68 1.1 yamaguch LACP_NTIMER 69 1.1 yamaguch }; 70 1.1 yamaguch 71 1.1 yamaguch enum { 72 1.1 yamaguch LACP_PTIMER_DISTRIBUTING = 0, 73 1.1 yamaguch LACP_NPTIMER 74 1.1 yamaguch }; 75 1.1 yamaguch 76 1.1 yamaguch enum lacp_selected { 77 1.1 yamaguch LACP_UNSELECTED, 78 1.30 yamaguch LACP_READY, 79 1.1 yamaguch LACP_STANDBY, 80 1.1 yamaguch LACP_SELECTED, 81 1.1 yamaguch }; 82 1.1 yamaguch 83 1.1 yamaguch enum lacp_mux_state { 84 1.1 yamaguch LACP_MUX_DETACHED, 85 1.1 yamaguch LACP_MUX_WAITING, 86 1.7 yamaguch LACP_MUX_STANDBY, 87 1.1 yamaguch LACP_MUX_ATTACHED, 88 1.1 yamaguch LACP_MUX_COLLECTING, 89 1.1 yamaguch LACP_MUX_DISTRIBUTING, 90 1.1 yamaguch LACP_MUX_INIT, 91 1.1 yamaguch }; 92 1.1 yamaguch 93 1.1 yamaguch struct lacp_aggregator_systemid { 94 1.1 yamaguch uint16_t sid_prio; 95 1.1 yamaguch uint16_t sid_key; 96 1.1 yamaguch uint8_t sid_mac[LACP_MAC_LEN]; 97 1.1 yamaguch }; 98 1.1 yamaguch 99 1.1 yamaguch struct lacp_aggregator { 100 1.1 yamaguch TAILQ_ENTRY(lacp_aggregator) 101 1.1 yamaguch la_q; 102 1.1 yamaguch LIST_HEAD(, lacp_port) 103 1.1 yamaguch la_ports; 104 1.1 yamaguch ssize_t la_attached_port; 105 1.1 yamaguch 106 1.1 yamaguch struct lacp_aggregator_systemid 107 1.1 yamaguch la_sid; 108 1.1 yamaguch }; 109 1.1 yamaguch 110 1.1 yamaguch struct lacp_portinfo { 111 1.1 yamaguch uint8_t lpi_state; 112 1.1 yamaguch uint16_t lpi_portno; 113 1.1 yamaguch #define LACP_PORTNO_NONE 0 114 1.1 yamaguch uint16_t lpi_portprio; 115 1.1 yamaguch }; 116 1.1 yamaguch 117 1.1 yamaguch struct lacp_port { 118 1.1 yamaguch struct lagg_port *lp_laggport; 119 1.6 yamaguch bool lp_added_multi; 120 1.1 yamaguch int lp_timer[LACP_NTIMER]; 121 1.1 yamaguch uint32_t lp_marker_xid; 122 1.1 yamaguch enum lacp_selected lp_selected; 123 1.1 yamaguch enum lacp_mux_state lp_mux_state; 124 1.1 yamaguch 125 1.1 yamaguch struct lacp_portinfo lp_actor; 126 1.1 yamaguch struct lacp_portinfo lp_partner; 127 1.1 yamaguch struct lacp_aggregator *lp_aggregator; 128 1.1 yamaguch struct lacp_aggregator_systemid 129 1.1 yamaguch lp_aggregator_sidbuf; 130 1.28 yamaguch uint64_t lp_linkspeed; 131 1.1 yamaguch int lp_pending; 132 1.1 yamaguch LIST_ENTRY(lacp_port) lp_entry_la; 133 1.1 yamaguch struct timeval lp_last_lacpdu; 134 1.1 yamaguch int lp_lacpdu_sent; 135 1.1 yamaguch bool lp_collector; 136 1.1 yamaguch 137 1.1 yamaguch unsigned int lp_flags; 138 1.1 yamaguch #define LACP_PORT_NTT __BIT(0) 139 1.1 yamaguch #define LACP_PORT_MARK __BIT(1) 140 1.1 yamaguch 141 1.1 yamaguch struct lagg_work lp_work_smtx; 142 1.1 yamaguch struct lagg_work lp_work_marker; 143 1.1 yamaguch }; 144 1.1 yamaguch 145 1.1 yamaguch struct lacp_portmap { 146 1.1 yamaguch size_t pm_count; 147 1.1 yamaguch struct lagg_port *pm_ports[LACP_MAX_PORTS]; 148 1.1 yamaguch }; 149 1.1 yamaguch 150 1.1 yamaguch struct lacp_softc { 151 1.1 yamaguch struct lagg_softc *lsc_softc; 152 1.1 yamaguch kmutex_t lsc_lock; 153 1.1 yamaguch pserialize_t lsc_psz; 154 1.1 yamaguch bool lsc_running; 155 1.1 yamaguch bool lsc_suppress_distributing; 156 1.1 yamaguch int lsc_timer[LACP_NPTIMER]; 157 1.1 yamaguch uint8_t lsc_system_mac[LACP_MAC_LEN]; 158 1.1 yamaguch uint16_t lsc_system_prio; 159 1.1 yamaguch uint16_t lsc_key; 160 1.1 yamaguch size_t lsc_max_ports; 161 1.1 yamaguch size_t lsc_activemap; 162 1.1 yamaguch struct lacp_portmap lsc_portmaps[2]; /* active & idle */ 163 1.1 yamaguch struct lacp_aggregator *lsc_aggregator; 164 1.1 yamaguch TAILQ_HEAD(, lacp_aggregator) 165 1.1 yamaguch lsc_aggregators; 166 1.1 yamaguch struct workqueue *lsc_workq; 167 1.1 yamaguch struct lagg_work lsc_work_tick; 168 1.18 yamaguch struct lagg_work lsc_work_rcvdu; 169 1.28 yamaguch struct lagg_work lsc_work_linkspeed; 170 1.1 yamaguch callout_t lsc_tick; 171 1.18 yamaguch pcq_t *lsc_du_q; 172 1.1 yamaguch 173 1.1 yamaguch char lsc_evgroup[32]; 174 1.1 yamaguch struct evcnt lsc_mgethdr_failed; 175 1.1 yamaguch struct evcnt lsc_mpullup_failed; 176 1.1 yamaguch struct evcnt lsc_badlacpdu; 177 1.1 yamaguch struct evcnt lsc_badmarkerdu; 178 1.18 yamaguch struct evcnt lsc_norcvif; 179 1.18 yamaguch struct evcnt lsc_nolaggport; 180 1.18 yamaguch struct evcnt lsc_duq_nospc; 181 1.1 yamaguch 182 1.1 yamaguch bool lsc_optimistic; 183 1.1 yamaguch bool lsc_stop_lacpdu; 184 1.1 yamaguch bool lsc_dump_du; 185 1.1 yamaguch bool lsc_multi_linkspeed; 186 1.1 yamaguch }; 187 1.1 yamaguch 188 1.1 yamaguch /* 189 1.1 yamaguch * Locking notes: 190 1.1 yamaguch * - Items in struct lacp_softc are protected by 191 1.1 yamaguch * lsc_lock (an adaptive mutex) 192 1.1 yamaguch * - lsc_activemap is protected by pserialize (lsc_psz) 193 1.1 yamaguch * - Items of struct lagg_port in lsc_portmaps are protected by 194 1.1 yamaguch * protected by both pserialize (lsc_psz) and psref (lp_psref) 195 1.1 yamaguch * - Updates for lsc_activemap and lsc_portmaps is serialized by 196 1.1 yamaguch * sc_lock in struct lagg_softc 197 1.1 yamaguch * - Other locking notes are described in if_laggproto.h 198 1.1 yamaguch */ 199 1.1 yamaguch 200 1.1 yamaguch static void lacp_dprintf(const struct lacp_softc *, 201 1.1 yamaguch const struct lacp_port *, const char *, ...) 202 1.1 yamaguch __attribute__((__format__(__printf__, 3, 4))); 203 1.1 yamaguch 204 1.1 yamaguch #ifdef LACP_DEBUG 205 1.1 yamaguch #define LACP_DPRINTF(a) do { lacp_dprintf a; } while (/*CONSTCOND*/ 0) 206 1.1 yamaguch #define LACP_PEERINFO_IDSTR(_pi, _b, _bs) \ 207 1.1 yamaguch lacp_peerinfo_idstr(_pi, _b, _bs) 208 1.1 yamaguch #define LACP_STATE_STR(_s, _b, _bs) lacp_state_str(_s, _b, _bs) 209 1.1 yamaguch #define LACP_AGGREGATOR_STR(_a, _b, _bs) \ 210 1.1 yamaguch lacp_aggregator_str(_a, _b, _bs) 211 1.1 yamaguch #define __LACPDEBUGUSED 212 1.1 yamaguch #else 213 1.1 yamaguch #define LACP_DPRINTF(a) __nothing 214 1.1 yamaguch #define LACP_PEERINFO_IDSTR(_pi, _b, _bs) __nothing 215 1.1 yamaguch #define LACP_STATE_STR(_s, _b, _bs) __nothing 216 1.1 yamaguch #define LACP_AGGREGATOR_STR(_a, _b, _bs) __nothing 217 1.1 yamaguch #define __LACPDEBUGUSED __unused 218 1.1 yamaguch #endif 219 1.1 yamaguch 220 1.1 yamaguch #define LACP_LOCK(_sc) mutex_enter(&(_sc)->lsc_lock) 221 1.1 yamaguch #define LACP_UNLOCK(_sc) mutex_exit(&(_sc)->lsc_lock) 222 1.1 yamaguch #define LACP_LOCKED(_sc) mutex_owned(&(_sc)->lsc_lock) 223 1.1 yamaguch #define LACP_TIMER_ARM(_lacpp, _timer, _val) \ 224 1.1 yamaguch (_lacpp)->lp_timer[(_timer)] = (_val) 225 1.1 yamaguch #define LACP_TIMER_DISARM(_lacpp, _timer) \ 226 1.1 yamaguch LACP_TIMER_ARM((_lacpp), (_timer), 0) 227 1.1 yamaguch #define LACP_TIMER_ISARMED(_lacpp, _timer) \ 228 1.1 yamaguch ((_lacpp)->lp_timer[(_timer)] > 0) 229 1.1 yamaguch #define LACP_PTIMER_ARM(_sc, _timer, _val) \ 230 1.1 yamaguch (_sc)->lsc_timer[(_timer)] = (_val) 231 1.1 yamaguch #define LACP_PTIMER_DISARM(_sc, _timer) \ 232 1.1 yamaguch LACP_PTIMER_ARM((_sc), (_timer), 0) 233 1.1 yamaguch #define LACP_PTIMER_ISARMED(_sc, _timer) \ 234 1.1 yamaguch ((_sc)->lsc_timer[(_timer)] > 0) 235 1.1 yamaguch #define LACP_STATE_EQ(_s1, _s2, _mask) (!ISSET((_s1) ^ (_s2), (_mask))) 236 1.1 yamaguch #define LACP_PORT_XNAME(_lacpp) (_lacpp != NULL) ? \ 237 1.1 yamaguch (_lacpp)->lp_laggport->lp_ifp->if_xname : "(unknown)" 238 1.1 yamaguch #define LACP_ISDUMPING(_sc) (_sc)->lsc_dump_du 239 1.1 yamaguch #define LACP_PORTMAP_ACTIVE(_sc) \ 240 1.1 yamaguch atomic_load_consume(&(_sc)->lsc_activemap) 241 1.1 yamaguch #define LACP_PORTMAP_NEXT(_sc) \ 242 1.1 yamaguch (((LACP_PORTMAP_ACTIVE((_sc))) ^ 0x01) &0x01) 243 1.1 yamaguch #define LACP_SYS_PRI(_la) ntohs((_la)->la_sid.sid_prio) 244 1.1 yamaguch #define LACP_TLV_PARSE(_du, _st, _name, _tlvlist) \ 245 1.1 yamaguch tlv_parse(&(_du)->_name, \ 246 1.1 yamaguch sizeof(_st) - offsetof(_st, _name), \ 247 1.1 yamaguch (_tlvlist)) 248 1.1 yamaguch 249 1.1 yamaguch static void lacp_tick(void *); 250 1.1 yamaguch static void lacp_tick_work(struct lagg_work *, void *); 251 1.12 yamaguch static void lacp_linkstate(struct lagg_proto_softc *, struct lagg_port *); 252 1.1 yamaguch static void lacp_port_disable(struct lacp_softc *, struct lacp_port *); 253 1.1 yamaguch static void lacp_port_enable(struct lacp_softc *, struct lacp_port *); 254 1.1 yamaguch static void lacp_peerinfo_actor(struct lacp_softc *, struct lacp_port *, 255 1.1 yamaguch struct lacpdu_peerinfo *); 256 1.1 yamaguch static void lacp_peerinfo_partner(struct lacp_port *, 257 1.1 yamaguch struct lacpdu_peerinfo *); 258 1.1 yamaguch static struct lagg_port * 259 1.1 yamaguch lacp_select_tx_port(struct lacp_softc *, struct mbuf *, 260 1.1 yamaguch struct psref *); 261 1.1 yamaguch static void lacp_suppress_distributing(struct lacp_softc *); 262 1.1 yamaguch static void lacp_distributing_timer(struct lacp_softc *); 263 1.1 yamaguch 264 1.1 yamaguch static void lacp_select(struct lacp_softc *, struct lacp_port *); 265 1.1 yamaguch static void lacp_unselect(struct lacp_softc *, struct lacp_port *); 266 1.1 yamaguch static void lacp_selected_update(struct lacp_softc *, 267 1.1 yamaguch struct lacp_aggregator *); 268 1.1 yamaguch static void lacp_sm_port_init(struct lacp_softc *, 269 1.1 yamaguch struct lacp_port *, struct lagg_port *); 270 1.1 yamaguch static int lacp_set_mux(struct lacp_softc *, 271 1.1 yamaguch struct lacp_port *, enum lacp_mux_state); 272 1.1 yamaguch static void lacp_sm_mux(struct lacp_softc *, struct lacp_port *); 273 1.1 yamaguch static void lacp_sm_mux_timer(struct lacp_softc *, struct lacp_port *); 274 1.1 yamaguch static void lacp_sm_rx(struct lacp_softc *, struct lacp_port *, 275 1.1 yamaguch struct lacpdu_peerinfo *, struct lacpdu_peerinfo *); 276 1.1 yamaguch static void lacp_sm_rx_set_expired(struct lacp_port *); 277 1.1 yamaguch static void lacp_sm_rx_timer(struct lacp_softc *, struct lacp_port *); 278 1.1 yamaguch static void lacp_sm_rx_record_default(struct lacp_softc *, 279 1.1 yamaguch struct lacp_port *); 280 1.1 yamaguch 281 1.1 yamaguch static void lacp_sm_tx(struct lacp_softc *, struct lacp_port *); 282 1.1 yamaguch static void lacp_sm_tx_work(struct lagg_work *, void *); 283 1.1 yamaguch static void lacp_sm_ptx_timer(struct lacp_softc *, struct lacp_port *); 284 1.1 yamaguch static void lacp_sm_ptx_schedule(struct lacp_port *); 285 1.1 yamaguch static void lacp_sm_ptx_update_timeout(struct lacp_port *, uint8_t); 286 1.1 yamaguch 287 1.18 yamaguch static void lacp_rcvdu_work(struct lagg_work *, void *); 288 1.1 yamaguch static void lacp_marker_work(struct lagg_work *, void *); 289 1.28 yamaguch static void lacp_linkspeed_work(struct lagg_work *, void *); 290 1.1 yamaguch static void lacp_dump_lacpdutlv(const struct lacpdu_peerinfo *, 291 1.1 yamaguch const struct lacpdu_peerinfo *, 292 1.1 yamaguch const struct lacpdu_collectorinfo *); 293 1.1 yamaguch static void lacp_dump_markertlv(const struct markerdu_info *, 294 1.1 yamaguch const struct markerdu_info *); 295 1.1 yamaguch 296 1.1 yamaguch typedef void (*lacp_timer_func_t)(struct lacp_softc *, struct lacp_port *); 297 1.1 yamaguch static const lacp_timer_func_t lacp_timer_funcs[] = { 298 1.1 yamaguch [LACP_TIMER_CURRENT_WHILE] = lacp_sm_rx_timer, 299 1.1 yamaguch [LACP_TIMER_PERIODIC] = lacp_sm_ptx_timer, 300 1.1 yamaguch [LACP_TIMER_WAIT_WHILE] = lacp_sm_mux_timer, 301 1.1 yamaguch }; 302 1.1 yamaguch typedef void (*lacp_prototimer_func_t)(struct lacp_softc *); 303 1.1 yamaguch static const lacp_prototimer_func_t lacp_ptimer_funcs[] = { 304 1.1 yamaguch [LACP_PTIMER_DISTRIBUTING] = lacp_distributing_timer, 305 1.1 yamaguch }; 306 1.1 yamaguch 307 1.1 yamaguch static void 308 1.1 yamaguch lacp_dprintf(const struct lacp_softc *lsc, const struct lacp_port *lacpp, 309 1.1 yamaguch const char *fmt, ...) 310 1.1 yamaguch { 311 1.1 yamaguch struct lagg_softc *sc; 312 1.1 yamaguch va_list va; 313 1.1 yamaguch 314 1.1 yamaguch if (lsc != NULL && lsc->lsc_softc != NULL) { 315 1.1 yamaguch sc = lsc->lsc_softc; 316 1.1 yamaguch printf("%s", sc->sc_if.if_xname); 317 1.1 yamaguch } else { 318 1.1 yamaguch printf("lacp"); 319 1.1 yamaguch } 320 1.1 yamaguch 321 1.1 yamaguch if (lacpp != NULL) 322 1.1 yamaguch printf("(%s)", LACP_PORT_XNAME(lacpp)); 323 1.1 yamaguch 324 1.1 yamaguch printf(": "); 325 1.1 yamaguch 326 1.1 yamaguch va_start(va, fmt); 327 1.1 yamaguch vprintf(fmt, va); 328 1.1 yamaguch va_end(va); 329 1.1 yamaguch } 330 1.1 yamaguch 331 1.1 yamaguch static inline void 332 1.1 yamaguch lacp_evcnt_attach(struct lacp_softc *lsc, 333 1.1 yamaguch struct evcnt *ev, const char *name) 334 1.1 yamaguch { 335 1.1 yamaguch 336 1.1 yamaguch evcnt_attach_dynamic(ev, EVCNT_TYPE_MISC, NULL, 337 1.1 yamaguch lsc->lsc_evgroup, name); 338 1.1 yamaguch } 339 1.1 yamaguch 340 1.1 yamaguch static inline bool 341 1.1 yamaguch lacp_iscollecting(struct lacp_port *lacpp) 342 1.1 yamaguch { 343 1.1 yamaguch 344 1.1 yamaguch return atomic_load_relaxed(&lacpp->lp_collector); 345 1.1 yamaguch } 346 1.1 yamaguch 347 1.1 yamaguch static inline bool 348 1.1 yamaguch lacp_isdistributing(struct lacp_port *lacpp) 349 1.1 yamaguch { 350 1.1 yamaguch 351 1.1 yamaguch return ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_DISTRIBUTING); 352 1.1 yamaguch } 353 1.1 yamaguch 354 1.1 yamaguch static inline bool 355 1.1 yamaguch lacp_isactive(struct lacp_softc *lsc, struct lacp_port *lacpp) 356 1.1 yamaguch { 357 1.1 yamaguch 358 1.1 yamaguch if (lacpp->lp_selected != LACP_SELECTED) 359 1.1 yamaguch return false; 360 1.1 yamaguch 361 1.1 yamaguch if (lacpp->lp_aggregator == NULL) 362 1.1 yamaguch return false; 363 1.1 yamaguch 364 1.1 yamaguch if (lacpp->lp_aggregator != lsc->lsc_aggregator) 365 1.1 yamaguch return false; 366 1.1 yamaguch 367 1.1 yamaguch return true; 368 1.1 yamaguch } 369 1.1 yamaguch 370 1.1 yamaguch static inline void 371 1.1 yamaguch lacp_mcastaddr(struct ifreq *ifr, const char *if_xname) 372 1.1 yamaguch { 373 1.1 yamaguch static const uint8_t addr[ETHER_ADDR_LEN] = 374 1.1 yamaguch { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }; 375 1.1 yamaguch 376 1.1 yamaguch memset(ifr, 0, sizeof(*ifr)); 377 1.1 yamaguch 378 1.1 yamaguch strlcpy(ifr->ifr_name, if_xname, 379 1.1 yamaguch sizeof(ifr->ifr_name)); 380 1.1 yamaguch ifr->ifr_addr.sa_len = sizeof(ifr->ifr_addr); 381 1.1 yamaguch ifr->ifr_addr.sa_family = AF_UNSPEC; 382 1.1 yamaguch 383 1.34 yamaguch CTASSERT(sizeof(ifr->ifr_addr) >= sizeof(addr)); 384 1.1 yamaguch memcpy(&ifr->ifr_addr.sa_data, addr, sizeof(addr)); 385 1.1 yamaguch } 386 1.1 yamaguch 387 1.1 yamaguch static inline u_int 388 1.1 yamaguch lacp_portmap_linkstate(struct lacp_portmap *pm) 389 1.1 yamaguch { 390 1.1 yamaguch 391 1.1 yamaguch if (pm->pm_count == 0) 392 1.1 yamaguch return LINK_STATE_DOWN; 393 1.1 yamaguch 394 1.1 yamaguch return LINK_STATE_UP; 395 1.1 yamaguch } 396 1.1 yamaguch 397 1.1 yamaguch static inline struct lacp_port * 398 1.1 yamaguch lacp_port_priority_max(struct lacp_port *a, struct lacp_port *b) 399 1.1 yamaguch { 400 1.1 yamaguch uint16_t pri_a, pri_b; 401 1.1 yamaguch 402 1.1 yamaguch pri_a = ntohs(a->lp_actor.lpi_portprio); 403 1.1 yamaguch pri_b = ntohs(b->lp_actor.lpi_portprio); 404 1.1 yamaguch 405 1.1 yamaguch if (pri_a < pri_b) 406 1.1 yamaguch return a; 407 1.1 yamaguch if (pri_b < pri_a) 408 1.1 yamaguch return b; 409 1.1 yamaguch 410 1.1 yamaguch pri_a = ntohs(a->lp_partner.lpi_portprio); 411 1.1 yamaguch pri_b = ntohs(b->lp_partner.lpi_portprio); 412 1.1 yamaguch 413 1.1 yamaguch if (pri_a < pri_b) 414 1.1 yamaguch return a; 415 1.1 yamaguch if (pri_b < pri_a) 416 1.1 yamaguch return b; 417 1.1 yamaguch 418 1.28 yamaguch if (a->lp_linkspeed > b->lp_linkspeed) 419 1.1 yamaguch return a; 420 1.28 yamaguch if (b->lp_linkspeed > a->lp_linkspeed) 421 1.1 yamaguch return b; 422 1.1 yamaguch 423 1.1 yamaguch return a; 424 1.1 yamaguch } 425 1.1 yamaguch 426 1.1 yamaguch static void 427 1.1 yamaguch tlv_parse(void *vp, size_t len, struct tlv *list) 428 1.1 yamaguch { 429 1.1 yamaguch struct tlvhdr *th; 430 1.1 yamaguch uint8_t *p; 431 1.1 yamaguch size_t l, i; 432 1.1 yamaguch 433 1.1 yamaguch th = (struct tlvhdr *)vp; 434 1.1 yamaguch p = (uint8_t *)vp; 435 1.1 yamaguch 436 1.1 yamaguch for (l = 0; l < len; l += th->tlv_length) { 437 1.1 yamaguch th = (struct tlvhdr *)(p + l); 438 1.1 yamaguch 439 1.1 yamaguch if (th->tlv_type == TLV_TYPE_TERMINATE) 440 1.1 yamaguch break; 441 1.1 yamaguch 442 1.16 yamaguch if (th->tlv_length <= 0) 443 1.16 yamaguch break; 444 1.16 yamaguch 445 1.1 yamaguch for (i = 0; list[i].tlv_t != TLV_TYPE_TERMINATE; i++) { 446 1.1 yamaguch if (th->tlv_type != list[i].tlv_t) 447 1.1 yamaguch continue; 448 1.1 yamaguch 449 1.1 yamaguch if (th->tlv_length - sizeof(*th) != list[i].tlv_l) 450 1.1 yamaguch break; 451 1.1 yamaguch 452 1.1 yamaguch if (list[i].tlv_v == NULL) { 453 1.1 yamaguch list[i].tlv_v = 454 1.1 yamaguch (void *)((uint8_t *)th + sizeof(*th)); 455 1.1 yamaguch } 456 1.1 yamaguch 457 1.1 yamaguch break; 458 1.1 yamaguch } 459 1.1 yamaguch } 460 1.1 yamaguch } 461 1.1 yamaguch 462 1.1 yamaguch int 463 1.1 yamaguch lacp_attach(struct lagg_softc *sc, struct lagg_proto_softc **lscp) 464 1.1 yamaguch { 465 1.1 yamaguch struct lacp_softc *lsc; 466 1.1 yamaguch char xnamebuf[MAXCOMLEN]; 467 1.1 yamaguch int error; 468 1.1 yamaguch 469 1.1 yamaguch KASSERT(LAGG_LOCKED(sc)); 470 1.1 yamaguch 471 1.1 yamaguch lsc = kmem_zalloc(sizeof(*lsc), KM_NOSLEEP); 472 1.1 yamaguch if (lsc == NULL) 473 1.1 yamaguch return ENOMEM; 474 1.1 yamaguch 475 1.18 yamaguch lsc->lsc_du_q = pcq_create(LACP_RCVDU_LIMIT, KM_NOSLEEP); 476 1.18 yamaguch if (lsc->lsc_du_q == NULL) { 477 1.18 yamaguch error = ENOMEM; 478 1.18 yamaguch goto free_lsc; 479 1.18 yamaguch } 480 1.18 yamaguch 481 1.1 yamaguch mutex_init(&lsc->lsc_lock, MUTEX_DEFAULT, IPL_SOFTNET); 482 1.1 yamaguch lsc->lsc_softc = sc; 483 1.1 yamaguch lsc->lsc_key = htons(if_get_index(&sc->sc_if)); 484 1.1 yamaguch lsc->lsc_system_prio = htons(LACP_SYSTEM_PRIO); 485 1.1 yamaguch lsc->lsc_running = false; 486 1.1 yamaguch lsc->lsc_max_ports = LACP_MAX_PORTS; 487 1.1 yamaguch lsc->lsc_multi_linkspeed = true; 488 1.1 yamaguch TAILQ_INIT(&lsc->lsc_aggregators); 489 1.1 yamaguch 490 1.1 yamaguch lagg_work_set(&lsc->lsc_work_tick, lacp_tick_work, lsc); 491 1.18 yamaguch lagg_work_set(&lsc->lsc_work_rcvdu, lacp_rcvdu_work, lsc); 492 1.28 yamaguch lagg_work_set(&lsc->lsc_work_linkspeed, 493 1.28 yamaguch lacp_linkspeed_work, lsc); 494 1.18 yamaguch 495 1.1 yamaguch snprintf(xnamebuf, sizeof(xnamebuf), "%s.lacp", 496 1.1 yamaguch sc->sc_if.if_xname); 497 1.1 yamaguch lsc->lsc_workq = lagg_workq_create(xnamebuf, 498 1.1 yamaguch PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); 499 1.1 yamaguch if (lsc->lsc_workq == NULL) { 500 1.20 yamaguch LAGG_LOG(sc, LOG_ERR, "workqueue create failed\n"); 501 1.1 yamaguch error = ENOMEM; 502 1.1 yamaguch goto destroy_lock; 503 1.1 yamaguch } 504 1.1 yamaguch 505 1.1 yamaguch lsc->lsc_psz = pserialize_create(); 506 1.1 yamaguch 507 1.1 yamaguch callout_init(&lsc->lsc_tick, CALLOUT_MPSAFE); 508 1.1 yamaguch callout_setfunc(&lsc->lsc_tick, lacp_tick, lsc); 509 1.1 yamaguch 510 1.1 yamaguch snprintf(lsc->lsc_evgroup, sizeof(lsc->lsc_evgroup), 511 1.1 yamaguch "%s-lacp", sc->sc_if.if_xname); 512 1.1 yamaguch lacp_evcnt_attach(lsc, &lsc->lsc_mgethdr_failed, "MGETHDR failed"); 513 1.1 yamaguch lacp_evcnt_attach(lsc, &lsc->lsc_mpullup_failed, "m_pullup failed"); 514 1.25 andvar lacp_evcnt_attach(lsc, &lsc->lsc_badlacpdu, "Bad LACPDU received"); 515 1.25 andvar lacp_evcnt_attach(lsc, &lsc->lsc_badmarkerdu, "Bad MarkerDU received"); 516 1.18 yamaguch lacp_evcnt_attach(lsc, &lsc->lsc_norcvif, "No received interface"); 517 1.18 yamaguch lacp_evcnt_attach(lsc, &lsc->lsc_nolaggport, "No lagg context"); 518 1.18 yamaguch lacp_evcnt_attach(lsc, &lsc->lsc_duq_nospc, "No space left on queues"); 519 1.1 yamaguch 520 1.1 yamaguch if_link_state_change(&sc->sc_if, LINK_STATE_DOWN); 521 1.1 yamaguch 522 1.1 yamaguch *lscp = (struct lagg_proto_softc *)lsc; 523 1.1 yamaguch return 0; 524 1.1 yamaguch destroy_lock: 525 1.1 yamaguch mutex_destroy(&lsc->lsc_lock); 526 1.18 yamaguch pcq_destroy(lsc->lsc_du_q); 527 1.18 yamaguch free_lsc: 528 1.15 yamaguch kmem_free(lsc, sizeof(*lsc)); 529 1.1 yamaguch 530 1.1 yamaguch return error; 531 1.1 yamaguch } 532 1.1 yamaguch 533 1.1 yamaguch void 534 1.1 yamaguch lacp_detach(struct lagg_proto_softc *xlsc) 535 1.1 yamaguch { 536 1.1 yamaguch struct lacp_softc *lsc = (struct lacp_softc *)xlsc; 537 1.2 hannken struct lagg_softc *sc __diagused = lsc->lsc_softc; 538 1.1 yamaguch 539 1.1 yamaguch KASSERT(TAILQ_EMPTY(&lsc->lsc_aggregators)); 540 1.1 yamaguch KASSERT(SIMPLEQ_EMPTY(&sc->sc_ports)); 541 1.1 yamaguch 542 1.32 yamaguch LAGG_LOCK(lsc->lsc_softc); 543 1.1 yamaguch lacp_down(xlsc); 544 1.32 yamaguch LAGG_UNLOCK(lsc->lsc_softc); 545 1.1 yamaguch 546 1.18 yamaguch lagg_workq_wait(lsc->lsc_workq, &lsc->lsc_work_rcvdu); 547 1.41 yamaguch lagg_workq_wait(lsc->lsc_workq, &lsc->lsc_work_tick); 548 1.1 yamaguch evcnt_detach(&lsc->lsc_mgethdr_failed); 549 1.1 yamaguch evcnt_detach(&lsc->lsc_mpullup_failed); 550 1.1 yamaguch evcnt_detach(&lsc->lsc_badlacpdu); 551 1.1 yamaguch evcnt_detach(&lsc->lsc_badmarkerdu); 552 1.18 yamaguch evcnt_detach(&lsc->lsc_norcvif); 553 1.18 yamaguch evcnt_detach(&lsc->lsc_nolaggport); 554 1.18 yamaguch evcnt_detach(&lsc->lsc_duq_nospc); 555 1.1 yamaguch lagg_workq_destroy(lsc->lsc_workq); 556 1.1 yamaguch pserialize_destroy(lsc->lsc_psz); 557 1.1 yamaguch mutex_destroy(&lsc->lsc_lock); 558 1.18 yamaguch pcq_destroy(lsc->lsc_du_q); 559 1.1 yamaguch kmem_free(lsc, sizeof(*lsc)); 560 1.1 yamaguch } 561 1.1 yamaguch 562 1.1 yamaguch int 563 1.1 yamaguch lacp_up(struct lagg_proto_softc *xlsc) 564 1.1 yamaguch { 565 1.1 yamaguch struct lagg_softc *sc; 566 1.1 yamaguch struct lagg_port *lp; 567 1.1 yamaguch struct lacp_softc *lsc; 568 1.1 yamaguch 569 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 570 1.1 yamaguch sc = lsc->lsc_softc; 571 1.1 yamaguch 572 1.1 yamaguch KASSERT(LAGG_LOCKED(sc)); 573 1.1 yamaguch 574 1.1 yamaguch LACP_LOCK(lsc); 575 1.4 yamaguch if (memcmp(lsc->lsc_system_mac, LAGG_CLLADDR(sc), 576 1.4 yamaguch sizeof(lsc->lsc_system_mac)) != 0) { 577 1.4 yamaguch memcpy(lsc->lsc_system_mac, LAGG_CLLADDR(sc), 578 1.4 yamaguch sizeof(lsc->lsc_system_mac)); 579 1.4 yamaguch } 580 1.1 yamaguch lsc->lsc_running = true; 581 1.1 yamaguch callout_schedule(&lsc->lsc_tick, hz); 582 1.1 yamaguch LACP_UNLOCK(lsc); 583 1.1 yamaguch 584 1.1 yamaguch LAGG_PORTS_FOREACH(sc, lp) { 585 1.1 yamaguch lacp_linkstate(xlsc, lp); 586 1.1 yamaguch } 587 1.1 yamaguch 588 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "lacp start\n")); 589 1.1 yamaguch 590 1.1 yamaguch return 0; 591 1.1 yamaguch } 592 1.1 yamaguch 593 1.1 yamaguch static void 594 1.1 yamaguch lacp_down_locked(struct lacp_softc *lsc) 595 1.1 yamaguch { 596 1.1 yamaguch struct lagg_softc *sc; 597 1.1 yamaguch struct lagg_port *lp; 598 1.1 yamaguch 599 1.1 yamaguch sc = lsc->lsc_softc; 600 1.1 yamaguch 601 1.1 yamaguch KASSERT(LAGG_LOCKED(sc)); 602 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 603 1.1 yamaguch 604 1.1 yamaguch lsc->lsc_running = false; 605 1.1 yamaguch callout_halt(&lsc->lsc_tick, &lsc->lsc_lock); 606 1.1 yamaguch 607 1.1 yamaguch LAGG_PORTS_FOREACH(sc, lp) { 608 1.1 yamaguch lacp_port_disable(lsc, lp->lp_proto_ctx); 609 1.1 yamaguch } 610 1.1 yamaguch 611 1.4 yamaguch memset(lsc->lsc_system_mac, 0, 612 1.4 yamaguch sizeof(lsc->lsc_system_mac)); 613 1.4 yamaguch 614 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "lacp stopped\n")); 615 1.1 yamaguch } 616 1.1 yamaguch 617 1.1 yamaguch void 618 1.1 yamaguch lacp_down(struct lagg_proto_softc *xlsc) 619 1.1 yamaguch { 620 1.1 yamaguch struct lacp_softc *lsc; 621 1.1 yamaguch 622 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 623 1.1 yamaguch 624 1.1 yamaguch KASSERT(LAGG_LOCKED(lsc->lsc_softc)); 625 1.1 yamaguch 626 1.1 yamaguch LACP_LOCK(lsc); 627 1.1 yamaguch lacp_down_locked(lsc); 628 1.1 yamaguch LACP_UNLOCK(lsc); 629 1.1 yamaguch } 630 1.1 yamaguch 631 1.1 yamaguch int 632 1.1 yamaguch lacp_transmit(struct lagg_proto_softc *xlsc, struct mbuf *m) 633 1.1 yamaguch { 634 1.1 yamaguch struct lacp_softc *lsc; 635 1.1 yamaguch struct lagg_port *lp; 636 1.1 yamaguch struct ifnet *ifp; 637 1.1 yamaguch struct psref psref; 638 1.1 yamaguch 639 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 640 1.1 yamaguch 641 1.1 yamaguch if (__predict_false(lsc->lsc_suppress_distributing)) { 642 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "waiting transit\n")); 643 1.1 yamaguch m_freem(m); 644 1.33 yamaguch return EBUSY; 645 1.1 yamaguch } 646 1.1 yamaguch 647 1.1 yamaguch lp = lacp_select_tx_port(lsc, m, &psref); 648 1.1 yamaguch if (__predict_false(lp == NULL)) { 649 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "no distributing port\n")); 650 1.1 yamaguch ifp = &lsc->lsc_softc->sc_if; 651 1.1 yamaguch if_statinc(ifp, if_oerrors); 652 1.1 yamaguch m_freem(m); 653 1.1 yamaguch return ENOENT; 654 1.1 yamaguch } 655 1.1 yamaguch 656 1.21 yamaguch lagg_output(lsc->lsc_softc, lp, m); 657 1.1 yamaguch lagg_port_putref(lp, &psref); 658 1.1 yamaguch 659 1.1 yamaguch return 0; 660 1.1 yamaguch } 661 1.1 yamaguch 662 1.1 yamaguch int 663 1.1 yamaguch lacp_allocport(struct lagg_proto_softc *xlsc, struct lagg_port *lp) 664 1.1 yamaguch { 665 1.1 yamaguch struct lagg_softc *sc; 666 1.1 yamaguch struct lacp_softc *lsc; 667 1.1 yamaguch struct lacp_port *lacpp; 668 1.1 yamaguch struct ifreq ifr; 669 1.6 yamaguch bool added_multi; 670 1.1 yamaguch int error; 671 1.1 yamaguch 672 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 673 1.1 yamaguch sc = lsc->lsc_softc; 674 1.1 yamaguch 675 1.1 yamaguch KASSERT(LAGG_LOCKED(sc)); 676 1.22 yamaguch KASSERT(IFNET_LOCKED(lp->lp_ifp)); 677 1.1 yamaguch 678 1.36 yamaguch lacpp = kmem_zalloc(sizeof(*lacpp), KM_NOSLEEP); 679 1.36 yamaguch if (lacpp == NULL) 680 1.36 yamaguch return ENOMEM; 681 1.36 yamaguch 682 1.1 yamaguch lacp_mcastaddr(&ifr, lp->lp_ifp->if_xname); 683 1.1 yamaguch error = lp->lp_ioctl(lp->lp_ifp, SIOCADDMULTI, (void *)&ifr); 684 1.1 yamaguch 685 1.6 yamaguch switch (error) { 686 1.6 yamaguch case 0: 687 1.6 yamaguch added_multi = true; 688 1.6 yamaguch break; 689 1.6 yamaguch case EAFNOSUPPORT: 690 1.6 yamaguch added_multi = false; 691 1.6 yamaguch break; 692 1.6 yamaguch default: 693 1.20 yamaguch LAGG_LOG(sc, LOG_ERR, "SIOCADDMULTI failed on %s\n", 694 1.1 yamaguch lp->lp_ifp->if_xname); 695 1.36 yamaguch kmem_free(lacpp, sizeof(*lacpp)); 696 1.1 yamaguch return error; 697 1.1 yamaguch } 698 1.1 yamaguch 699 1.6 yamaguch lacpp->lp_added_multi = added_multi; 700 1.1 yamaguch lagg_work_set(&lacpp->lp_work_smtx, lacp_sm_tx_work, lsc); 701 1.1 yamaguch lagg_work_set(&lacpp->lp_work_marker, lacp_marker_work, lsc); 702 1.1 yamaguch 703 1.1 yamaguch LACP_LOCK(lsc); 704 1.1 yamaguch lacp_sm_port_init(lsc, lacpp, lp); 705 1.1 yamaguch LACP_UNLOCK(lsc); 706 1.1 yamaguch 707 1.1 yamaguch lp->lp_proto_ctx = (void *)lacpp; 708 1.1 yamaguch lp->lp_prio = ntohs(lacpp->lp_actor.lpi_portprio); 709 1.1 yamaguch 710 1.1 yamaguch return 0; 711 1.1 yamaguch } 712 1.1 yamaguch 713 1.1 yamaguch void 714 1.1 yamaguch lacp_startport(struct lagg_proto_softc *xlsc, struct lagg_port *lp) 715 1.1 yamaguch { 716 1.1 yamaguch struct lacp_port *lacpp; 717 1.1 yamaguch uint16_t prio; 718 1.1 yamaguch 719 1.1 yamaguch lacpp = lp->lp_proto_ctx; 720 1.1 yamaguch 721 1.1 yamaguch prio = (uint16_t)MIN(lp->lp_prio, UINT16_MAX); 722 1.1 yamaguch lacpp->lp_actor.lpi_portprio = htons(prio); 723 1.1 yamaguch 724 1.12 yamaguch lacp_linkstate(xlsc, lp); 725 1.1 yamaguch } 726 1.1 yamaguch 727 1.1 yamaguch void 728 1.1 yamaguch lacp_stopport(struct lagg_proto_softc *xlsc, struct lagg_port *lp) 729 1.1 yamaguch { 730 1.1 yamaguch struct lacp_softc *lsc; 731 1.1 yamaguch struct lacp_port *lacpp; 732 1.1 yamaguch int i; 733 1.1 yamaguch 734 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 735 1.1 yamaguch lacpp = lp->lp_proto_ctx; 736 1.1 yamaguch 737 1.1 yamaguch KASSERT(LAGG_LOCKED(lsc->lsc_softc)); 738 1.1 yamaguch 739 1.1 yamaguch LACP_LOCK(lsc); 740 1.1 yamaguch for (i = 0; i < LACP_NTIMER; i++) { 741 1.1 yamaguch LACP_TIMER_DISARM(lacpp, i); 742 1.1 yamaguch } 743 1.1 yamaguch 744 1.1 yamaguch lacp_port_disable(lsc, lacpp); 745 1.1 yamaguch LACP_UNLOCK(lsc); 746 1.1 yamaguch } 747 1.1 yamaguch 748 1.1 yamaguch void 749 1.1 yamaguch lacp_freeport(struct lagg_proto_softc *xlsc, struct lagg_port *lp) 750 1.1 yamaguch { 751 1.1 yamaguch struct lacp_softc *lsc; 752 1.4 yamaguch struct lacp_port *lacpp; 753 1.1 yamaguch struct ifreq ifr; 754 1.1 yamaguch 755 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 756 1.1 yamaguch lacpp = lp->lp_proto_ctx; 757 1.1 yamaguch 758 1.5 mrg KASSERT(LAGG_LOCKED(lsc->lsc_softc)); 759 1.22 yamaguch KASSERT(IFNET_LOCKED(lp->lp_ifp)); 760 1.1 yamaguch 761 1.1 yamaguch lagg_workq_wait(lsc->lsc_workq, &lacpp->lp_work_smtx); 762 1.1 yamaguch lagg_workq_wait(lsc->lsc_workq, &lacpp->lp_work_marker); 763 1.1 yamaguch 764 1.6 yamaguch if (lacpp->lp_added_multi) { 765 1.6 yamaguch lacp_mcastaddr(&ifr, LACP_PORT_XNAME(lacpp)); 766 1.1 yamaguch 767 1.6 yamaguch (void)lp->lp_ioctl(lp->lp_ifp, SIOCDELMULTI, (void *)&ifr); 768 1.6 yamaguch } 769 1.1 yamaguch 770 1.1 yamaguch lp->lp_proto_ctx = NULL; 771 1.1 yamaguch kmem_free(lacpp, sizeof(*lacpp)); 772 1.1 yamaguch } 773 1.1 yamaguch 774 1.1 yamaguch void 775 1.1 yamaguch lacp_protostat(struct lagg_proto_softc *xlsc, struct laggreqproto *resp) 776 1.1 yamaguch { 777 1.1 yamaguch struct laggreq_lacp *rplacp; 778 1.1 yamaguch struct lacp_softc *lsc; 779 1.1 yamaguch struct lacp_aggregator *la; 780 1.1 yamaguch struct lacp_aggregator_systemid *sid; 781 1.1 yamaguch 782 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 783 1.1 yamaguch 784 1.1 yamaguch LACP_LOCK(lsc); 785 1.1 yamaguch la = lsc->lsc_aggregator; 786 1.1 yamaguch rplacp = &resp->rp_lacp; 787 1.1 yamaguch 788 1.1 yamaguch if (lsc->lsc_optimistic) 789 1.1 yamaguch SET(rplacp->flags, LAGGREQLACP_OPTIMISTIC); 790 1.1 yamaguch if (lsc->lsc_dump_du) 791 1.1 yamaguch SET(rplacp->flags, LAGGREQLACP_DUMPDU); 792 1.1 yamaguch if (lsc->lsc_stop_lacpdu) 793 1.1 yamaguch SET(rplacp->flags, LAGGREQLACP_STOPDU); 794 1.1 yamaguch if (lsc->lsc_multi_linkspeed) 795 1.1 yamaguch SET(rplacp->flags, LAGGREQLACP_MULTILS); 796 1.1 yamaguch 797 1.1 yamaguch rplacp->maxports = lsc->lsc_max_ports; 798 1.1 yamaguch rplacp->actor_prio = ntohs(lsc->lsc_system_prio); 799 1.1 yamaguch memcpy(rplacp->actor_mac, lsc->lsc_system_mac, 800 1.1 yamaguch sizeof(rplacp->actor_mac)); 801 1.1 yamaguch rplacp->actor_key = ntohs(lsc->lsc_key); 802 1.1 yamaguch 803 1.1 yamaguch if (la != NULL) { 804 1.1 yamaguch sid = &la->la_sid; 805 1.1 yamaguch rplacp->partner_prio = ntohs(sid->sid_prio); 806 1.1 yamaguch memcpy(rplacp->partner_mac, sid->sid_mac, 807 1.1 yamaguch sizeof(rplacp->partner_mac)); 808 1.1 yamaguch rplacp->partner_key = ntohs(sid->sid_key); 809 1.1 yamaguch } 810 1.1 yamaguch LACP_UNLOCK(lsc); 811 1.1 yamaguch } 812 1.1 yamaguch 813 1.1 yamaguch void 814 1.1 yamaguch lacp_portstat(struct lagg_proto_softc *xlsc, struct lagg_port *lp, 815 1.1 yamaguch struct laggreqport *resp) 816 1.1 yamaguch { 817 1.1 yamaguch struct laggreq_lacpport *llp; 818 1.1 yamaguch struct lacp_softc *lsc; 819 1.1 yamaguch struct lacp_port *lacpp; 820 1.1 yamaguch struct lacp_aggregator *la; 821 1.1 yamaguch struct lacp_aggregator_systemid *sid; 822 1.1 yamaguch 823 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 824 1.1 yamaguch lacpp = lp->lp_proto_ctx; 825 1.1 yamaguch la = lacpp->lp_aggregator; 826 1.1 yamaguch llp = &resp->rp_lacpport; 827 1.1 yamaguch 828 1.1 yamaguch if (lacp_isactive(lsc, lacpp)) 829 1.1 yamaguch SET(resp->rp_flags, LAGG_PORT_ACTIVE); 830 1.1 yamaguch if (lacp_iscollecting(lacpp)) 831 1.1 yamaguch SET(resp->rp_flags, LAGG_PORT_COLLECTING); 832 1.1 yamaguch if (lacp_isdistributing(lacpp)) 833 1.1 yamaguch SET(resp->rp_flags, LAGG_PORT_DISTRIBUTING); 834 1.1 yamaguch if (lacpp->lp_selected == LACP_STANDBY) 835 1.1 yamaguch SET(resp->rp_flags, LAGG_PORT_STANDBY); 836 1.1 yamaguch 837 1.1 yamaguch if (la != NULL) { 838 1.1 yamaguch sid = &la->la_sid; 839 1.1 yamaguch llp->partner_prio = ntohs(sid->sid_prio); 840 1.1 yamaguch memcpy(llp->partner_mac, sid->sid_mac, 841 1.1 yamaguch sizeof(llp->partner_mac)); 842 1.1 yamaguch llp->partner_key = ntohs(sid->sid_key); 843 1.1 yamaguch } 844 1.1 yamaguch 845 1.1 yamaguch llp->actor_portprio = ntohs(lacpp->lp_actor.lpi_portprio); 846 1.1 yamaguch llp->actor_portno = ntohs(lacpp->lp_actor.lpi_portno); 847 1.1 yamaguch llp->actor_state = lacpp->lp_actor.lpi_state; 848 1.1 yamaguch 849 1.1 yamaguch llp->partner_portprio = ntohs(lacpp->lp_partner.lpi_portprio); 850 1.1 yamaguch llp->partner_portno = ntohs(lacpp->lp_partner.lpi_portno); 851 1.1 yamaguch llp->partner_state = lacpp->lp_partner.lpi_state; 852 1.1 yamaguch } 853 1.1 yamaguch 854 1.1 yamaguch void 855 1.12 yamaguch lacp_linkstate_ifnet_locked(struct lagg_proto_softc *xlsc, struct lagg_port *lp) 856 1.1 yamaguch { 857 1.1 yamaguch struct lacp_softc *lsc; 858 1.1 yamaguch struct lacp_port *lacpp; 859 1.1 yamaguch struct ifmediareq ifmr; 860 1.1 yamaguch struct ifnet *ifp_port; 861 1.1 yamaguch uint8_t old_state; 862 1.28 yamaguch uint64_t old_linkspeed, new_linkspeed; 863 1.1 yamaguch int error; 864 1.1 yamaguch 865 1.12 yamaguch KASSERT(IFNET_LOCKED(lp->lp_ifp)); 866 1.12 yamaguch 867 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 868 1.1 yamaguch 869 1.1 yamaguch ifp_port = lp->lp_ifp; 870 1.1 yamaguch lacpp = lp->lp_proto_ctx; 871 1.1 yamaguch 872 1.1 yamaguch memset(&ifmr, 0, sizeof(ifmr)); 873 1.1 yamaguch ifmr.ifm_count = 0; 874 1.10 riastrad error = if_ioctl(ifp_port, SIOCGIFMEDIA, (void *)&ifmr); 875 1.1 yamaguch if (error == 0) { 876 1.28 yamaguch new_linkspeed = ifmedia_baudrate(ifmr.ifm_active); 877 1.28 yamaguch #ifdef LACP_NOFDX 878 1.28 yamaguch /* 879 1.28 yamaguch * some driver that has no media, e.g. vioif(4), 880 1.28 yamaguch * returns (IFM_ETHER | IFM_AUTO) 881 1.28 yamaguch */ 882 1.28 yamaguch if ((ifmr.ifm_active & ~(IFM_ETHER | IFM_AUTO)) == 0) 883 1.28 yamaguch ifmr.ifm_active |= IFM_FDX; 884 1.28 yamaguch #endif 885 1.28 yamaguch } else if (error == ENOTTY) { 886 1.28 yamaguch ifmr.ifm_active = IFM_FDX | IF_Gbps(0); 887 1.28 yamaguch new_linkspeed = 0; 888 1.28 yamaguch } else { 889 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 890 1.1 yamaguch "SIOCGIFMEDIA failed (%d)\n", error)); 891 1.1 yamaguch return; 892 1.1 yamaguch } 893 1.1 yamaguch 894 1.1 yamaguch LACP_LOCK(lsc); 895 1.1 yamaguch if (lsc->lsc_running) { 896 1.28 yamaguch old_linkspeed = lacpp->lp_linkspeed; 897 1.1 yamaguch old_state = lacpp->lp_actor.lpi_state; 898 1.1 yamaguch 899 1.28 yamaguch if (new_linkspeed != old_linkspeed) { 900 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 901 1.28 yamaguch "linkspeed changed %"PRIu64" -> %"PRIu64"\n", 902 1.28 yamaguch old_linkspeed, new_linkspeed)); 903 1.28 yamaguch lacpp->lp_linkspeed = new_linkspeed; 904 1.1 yamaguch } 905 1.1 yamaguch 906 1.28 yamaguch if (ISSET(ifmr.ifm_active, IFM_FDX) && 907 1.28 yamaguch ISSET(ifp_port->if_flags, IFF_RUNNING) && 908 1.28 yamaguch ifp_port->if_link_state != LINK_STATE_DOWN) { 909 1.1 yamaguch lacp_port_enable(lsc, lacpp); 910 1.1 yamaguch } else { 911 1.28 yamaguch LACP_DPRINTF((lsc, lacpp, 912 1.28 yamaguch "FDX=%d, RUNNING=%d, link=%d\n", 913 1.28 yamaguch ISSET(ifmr.ifm_active, IFM_FDX) != 0, 914 1.28 yamaguch ISSET(ifp_port->if_flags, IFF_RUNNING) != 0, 915 1.28 yamaguch ifp_port->if_link_state != LINK_STATE_DOWN)); 916 1.1 yamaguch lacp_port_disable(lsc, lacpp); 917 1.1 yamaguch } 918 1.1 yamaguch 919 1.1 yamaguch if (old_state != lacpp->lp_actor.lpi_state || 920 1.28 yamaguch old_linkspeed != new_linkspeed) { 921 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 922 1.1 yamaguch "state changed to UNSELECTED\n")); 923 1.1 yamaguch lacpp->lp_selected = LACP_UNSELECTED; 924 1.1 yamaguch } 925 1.1 yamaguch } else { 926 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 927 1.1 yamaguch "LACP is inactive, skip linkstate\n")); 928 1.1 yamaguch } 929 1.1 yamaguch LACP_UNLOCK(lsc); 930 1.1 yamaguch } 931 1.1 yamaguch 932 1.1 yamaguch int 933 1.1 yamaguch lacp_ioctl(struct lagg_proto_softc *xlsc, struct laggreqproto *lreq) 934 1.1 yamaguch { 935 1.1 yamaguch struct lacp_softc *lsc; 936 1.1 yamaguch struct laggreq_lacp *rplacp; 937 1.1 yamaguch struct lacp_aggregator *la; 938 1.1 yamaguch int error; 939 1.1 yamaguch size_t maxports; 940 1.1 yamaguch bool set; 941 1.1 yamaguch 942 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 943 1.1 yamaguch rplacp = &lreq->rp_lacp; 944 1.1 yamaguch error = 0; 945 1.1 yamaguch 946 1.1 yamaguch switch (rplacp->command) { 947 1.1 yamaguch case LAGGIOC_LACPSETFLAGS: 948 1.1 yamaguch case LAGGIOC_LACPCLRFLAGS: 949 1.1 yamaguch set = (rplacp->command == LAGGIOC_LACPSETFLAGS) ? 950 1.1 yamaguch true : false; 951 1.1 yamaguch 952 1.1 yamaguch LACP_LOCK(lsc); 953 1.1 yamaguch 954 1.1 yamaguch if (ISSET(rplacp->flags, LAGGREQLACP_OPTIMISTIC)) 955 1.1 yamaguch lsc->lsc_optimistic = set; 956 1.1 yamaguch if (ISSET(rplacp->flags, LAGGREQLACP_DUMPDU)) 957 1.1 yamaguch lsc->lsc_dump_du = set; 958 1.1 yamaguch if (ISSET(rplacp->flags, LAGGREQLACP_STOPDU)) 959 1.1 yamaguch lsc->lsc_stop_lacpdu = set; 960 1.19 yamaguch 961 1.19 yamaguch if (ISSET(rplacp->flags, LAGGREQLACP_MULTILS) && 962 1.19 yamaguch lsc->lsc_multi_linkspeed != set) { 963 1.1 yamaguch lsc->lsc_multi_linkspeed = set; 964 1.19 yamaguch TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 965 1.19 yamaguch lacp_selected_update(lsc, la); 966 1.19 yamaguch } 967 1.19 yamaguch } 968 1.1 yamaguch 969 1.1 yamaguch LACP_UNLOCK(lsc); 970 1.1 yamaguch break; 971 1.1 yamaguch case LAGGIOC_LACPSETMAXPORTS: 972 1.1 yamaguch case LAGGIOC_LACPCLRMAXPORTS: 973 1.1 yamaguch maxports = (rplacp->command == LAGGIOC_LACPSETMAXPORTS) ? 974 1.1 yamaguch rplacp->maxports : LACP_MAX_PORTS; 975 1.1 yamaguch if (0 == maxports || LACP_MAX_PORTS < maxports) { 976 1.1 yamaguch error = ERANGE; 977 1.1 yamaguch break; 978 1.1 yamaguch } 979 1.1 yamaguch 980 1.1 yamaguch LACP_LOCK(lsc); 981 1.1 yamaguch if (lsc->lsc_max_ports != maxports) { 982 1.1 yamaguch lsc->lsc_max_ports = maxports; 983 1.1 yamaguch TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 984 1.1 yamaguch lacp_selected_update(lsc, la); 985 1.1 yamaguch } 986 1.1 yamaguch } 987 1.1 yamaguch LACP_UNLOCK(lsc); 988 1.1 yamaguch break; 989 1.1 yamaguch default: 990 1.1 yamaguch error = ENOTTY; 991 1.1 yamaguch } 992 1.1 yamaguch 993 1.1 yamaguch return error; 994 1.1 yamaguch } 995 1.1 yamaguch 996 1.1 yamaguch static int 997 1.1 yamaguch lacp_pdu_input(struct lacp_softc *lsc, struct lacp_port *lacpp, struct mbuf *m) 998 1.1 yamaguch { 999 1.1 yamaguch enum { 1000 1.1 yamaguch LACP_TLV_ACTOR = 0, 1001 1.1 yamaguch LACP_TLV_PARTNER, 1002 1.1 yamaguch LACP_TLV_COLLECTOR, 1003 1.1 yamaguch LACP_TLV_TERM, 1004 1.1 yamaguch LACP_TLV_NUM 1005 1.1 yamaguch }; 1006 1.1 yamaguch 1007 1.1 yamaguch struct lacpdu *du; 1008 1.1 yamaguch struct lacpdu_peerinfo *pi_actor, *pi_partner; 1009 1.1 yamaguch struct lacpdu_collectorinfo *lci; 1010 1.1 yamaguch struct tlv tlvlist_lacp[LACP_TLV_NUM] = { 1011 1.1 yamaguch [LACP_TLV_ACTOR] = { 1012 1.1 yamaguch .tlv_t = LACP_TYPE_ACTORINFO, 1013 1.1 yamaguch .tlv_l = sizeof(*pi_actor)}, 1014 1.1 yamaguch [LACP_TLV_PARTNER] = { 1015 1.1 yamaguch .tlv_t = LACP_TYPE_PARTNERINFO, 1016 1.1 yamaguch .tlv_l = sizeof(*pi_partner)}, 1017 1.1 yamaguch [LACP_TLV_COLLECTOR] = { 1018 1.1 yamaguch .tlv_t = LACP_TYPE_COLLECTORINFO, 1019 1.1 yamaguch .tlv_l = sizeof(*lci)}, 1020 1.1 yamaguch [LACP_TLV_TERM] = { 1021 1.1 yamaguch .tlv_t = TLV_TYPE_TERMINATE, 1022 1.1 yamaguch .tlv_l = 0}, 1023 1.1 yamaguch }; 1024 1.1 yamaguch 1025 1.1 yamaguch if (m->m_pkthdr.len != sizeof(*du)) 1026 1.1 yamaguch goto bad; 1027 1.1 yamaguch 1028 1.1 yamaguch if (m->m_len < (int)sizeof(*du)) { 1029 1.1 yamaguch m = m_pullup(m, sizeof(*du)); 1030 1.1 yamaguch if (m == NULL) { 1031 1.1 yamaguch lsc->lsc_mpullup_failed.ev_count++; 1032 1.1 yamaguch return ENOMEM; 1033 1.1 yamaguch } 1034 1.1 yamaguch } 1035 1.1 yamaguch 1036 1.1 yamaguch du = mtod(m, struct lacpdu *); 1037 1.1 yamaguch 1038 1.1 yamaguch if (memcmp(&du->ldu_eh.ether_dhost, 1039 1.1 yamaguch ethermulticastaddr_slowprotocols, ETHER_ADDR_LEN) != 0) 1040 1.1 yamaguch goto bad; 1041 1.1 yamaguch 1042 1.1 yamaguch LACP_TLV_PARSE(du, struct lacpdu, ldu_tlv_actor, 1043 1.1 yamaguch tlvlist_lacp); 1044 1.1 yamaguch 1045 1.1 yamaguch pi_actor = tlvlist_lacp[LACP_TLV_ACTOR].tlv_v; 1046 1.1 yamaguch pi_partner = tlvlist_lacp[LACP_TLV_PARTNER].tlv_v; 1047 1.1 yamaguch lci = tlvlist_lacp[LACP_TLV_COLLECTOR].tlv_v; 1048 1.1 yamaguch 1049 1.1 yamaguch if (pi_actor == NULL || pi_partner == NULL) 1050 1.1 yamaguch goto bad; 1051 1.1 yamaguch 1052 1.1 yamaguch if (LACP_ISDUMPING(lsc)) { 1053 1.1 yamaguch lacp_dprintf(lsc, lacpp, "lacpdu received\n"); 1054 1.1 yamaguch lacp_dump_lacpdutlv(pi_actor, pi_partner, lci); 1055 1.1 yamaguch } 1056 1.1 yamaguch 1057 1.1 yamaguch LACP_LOCK(lsc); 1058 1.1 yamaguch lacp_sm_rx(lsc, lacpp, pi_partner, pi_actor); 1059 1.1 yamaguch LACP_UNLOCK(lsc); 1060 1.1 yamaguch 1061 1.1 yamaguch m_freem(m); 1062 1.1 yamaguch return 0; 1063 1.1 yamaguch bad: 1064 1.1 yamaguch lsc->lsc_badlacpdu.ev_count++; 1065 1.1 yamaguch m_freem(m); 1066 1.1 yamaguch return EINVAL; 1067 1.1 yamaguch } 1068 1.1 yamaguch 1069 1.1 yamaguch static int 1070 1.1 yamaguch marker_cmp(struct markerdu_info *mi, 1071 1.1 yamaguch struct lacp_softc *lsc, struct lacp_port *lacpp) 1072 1.1 yamaguch { 1073 1.1 yamaguch 1074 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 1075 1.1 yamaguch 1076 1.1 yamaguch if (mi->mi_rq_port != lacpp->lp_actor.lpi_portno) 1077 1.1 yamaguch return -1; 1078 1.1 yamaguch 1079 1.1 yamaguch if (ntohl(mi->mi_rq_xid) != lacpp->lp_marker_xid) 1080 1.1 yamaguch return -1; 1081 1.1 yamaguch 1082 1.1 yamaguch return memcmp(mi->mi_rq_system, lsc->lsc_system_mac, 1083 1.1 yamaguch LACP_MAC_LEN); 1084 1.1 yamaguch } 1085 1.1 yamaguch 1086 1.1 yamaguch static void 1087 1.1 yamaguch lacp_marker_reply(struct lacp_softc *lsc, struct lacp_port *lacpp, 1088 1.1 yamaguch struct mbuf *m_info) 1089 1.1 yamaguch { 1090 1.1 yamaguch struct lagg_port *lp; 1091 1.1 yamaguch struct markerdu *mdu; 1092 1.1 yamaguch struct ifnet *ifp_port; 1093 1.1 yamaguch struct psref psref; 1094 1.1 yamaguch 1095 1.1 yamaguch LACP_LOCK(lsc); 1096 1.1 yamaguch lp = lacpp->lp_laggport; 1097 1.1 yamaguch lagg_port_getref(lp, &psref); 1098 1.1 yamaguch LACP_UNLOCK(lsc); 1099 1.1 yamaguch 1100 1.1 yamaguch ifp_port = lp->lp_ifp; 1101 1.1 yamaguch mdu = mtod(m_info, struct markerdu *); 1102 1.1 yamaguch 1103 1.1 yamaguch mdu->mdu_tlv_info.tlv_type = MARKER_TYPE_RESPONSE; 1104 1.23 yamaguch /* ether_dhost is already ethermulticastaddr_slowprotocols */ 1105 1.23 yamaguch m_info->m_flags |= M_MCAST; 1106 1.1 yamaguch memcpy(mdu->mdu_eh.ether_shost, 1107 1.1 yamaguch CLLADDR(ifp_port->if_sadl), ETHER_ADDR_LEN); 1108 1.1 yamaguch 1109 1.1 yamaguch if (LACP_ISDUMPING(lsc)) { 1110 1.1 yamaguch lacp_dprintf(lsc, lacpp, "markerdu reply\n"); 1111 1.1 yamaguch lacp_dump_markertlv(NULL, &mdu->mdu_info); 1112 1.1 yamaguch } 1113 1.1 yamaguch 1114 1.1 yamaguch lagg_port_xmit(lp, m_info); 1115 1.1 yamaguch lagg_port_putref(lp, &psref); 1116 1.1 yamaguch } 1117 1.1 yamaguch 1118 1.1 yamaguch static int 1119 1.1 yamaguch lacp_marker_recv_response(struct lacp_softc *lsc, struct lacp_port *lacpp, 1120 1.1 yamaguch struct markerdu_info *mi_res) 1121 1.1 yamaguch { 1122 1.1 yamaguch struct lagg_softc *sc; 1123 1.1 yamaguch struct lagg_port *lp0; 1124 1.1 yamaguch struct lacp_port *lacpp0; 1125 1.1 yamaguch bool pending; 1126 1.1 yamaguch 1127 1.1 yamaguch sc = lsc->lsc_softc; 1128 1.1 yamaguch 1129 1.1 yamaguch LACP_LOCK(lsc); 1130 1.1 yamaguch if (marker_cmp(mi_res, lsc, lacpp) != 0) { 1131 1.1 yamaguch LACP_UNLOCK(lsc); 1132 1.1 yamaguch return -1; 1133 1.1 yamaguch } 1134 1.1 yamaguch CLR(lacpp->lp_flags, LACP_PORT_MARK); 1135 1.1 yamaguch LACP_UNLOCK(lsc); 1136 1.1 yamaguch 1137 1.1 yamaguch LAGG_LOCK(sc); 1138 1.1 yamaguch LACP_LOCK(lsc); 1139 1.1 yamaguch 1140 1.1 yamaguch if (lsc->lsc_suppress_distributing) { 1141 1.1 yamaguch pending = false; 1142 1.1 yamaguch LAGG_PORTS_FOREACH(sc, lp0) { 1143 1.1 yamaguch lacpp0 = lp0->lp_proto_ctx; 1144 1.1 yamaguch if (ISSET(lacpp0->lp_flags, LACP_PORT_MARK)) { 1145 1.1 yamaguch pending = true; 1146 1.1 yamaguch break; 1147 1.1 yamaguch } 1148 1.1 yamaguch } 1149 1.1 yamaguch 1150 1.1 yamaguch if (!pending) { 1151 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "queue flush complete\n")); 1152 1.1 yamaguch LACP_PTIMER_DISARM(lsc, LACP_PTIMER_DISTRIBUTING); 1153 1.1 yamaguch lsc->lsc_suppress_distributing = false; 1154 1.1 yamaguch } 1155 1.1 yamaguch } 1156 1.1 yamaguch 1157 1.1 yamaguch LACP_UNLOCK(lsc); 1158 1.1 yamaguch LAGG_UNLOCK(sc); 1159 1.1 yamaguch 1160 1.1 yamaguch return 0; 1161 1.1 yamaguch } 1162 1.1 yamaguch 1163 1.1 yamaguch static int 1164 1.1 yamaguch lacp_marker_input(struct lacp_softc *lsc, struct lacp_port *lacpp, 1165 1.1 yamaguch struct mbuf *m) 1166 1.1 yamaguch { 1167 1.1 yamaguch enum { 1168 1.1 yamaguch MARKER_TLV_INFO = 0, 1169 1.1 yamaguch MARKER_TLV_RESPONSE, 1170 1.1 yamaguch MARKER_TLV_TERM, 1171 1.1 yamaguch MARKER_TLV_NUM 1172 1.1 yamaguch }; 1173 1.1 yamaguch 1174 1.1 yamaguch struct markerdu *mdu; 1175 1.1 yamaguch struct markerdu_info *mi_info, *mi_res; 1176 1.1 yamaguch int error; 1177 1.1 yamaguch struct tlv tlvlist_marker[MARKER_TLV_NUM] = { 1178 1.1 yamaguch [MARKER_TLV_INFO] = { 1179 1.1 yamaguch .tlv_t = MARKER_TYPE_INFO, 1180 1.1 yamaguch .tlv_l = sizeof(*mi_info)}, 1181 1.1 yamaguch [MARKER_TLV_RESPONSE] = { 1182 1.1 yamaguch .tlv_t = MARKER_TYPE_RESPONSE, 1183 1.1 yamaguch .tlv_l = sizeof(*mi_res)}, 1184 1.1 yamaguch [MARKER_TLV_TERM] = { 1185 1.1 yamaguch .tlv_t = TLV_TYPE_TERMINATE, 1186 1.1 yamaguch .tlv_l = 0}, 1187 1.1 yamaguch }; 1188 1.1 yamaguch 1189 1.1 yamaguch if (m->m_pkthdr.len != sizeof(*mdu)) 1190 1.1 yamaguch goto bad; 1191 1.1 yamaguch 1192 1.1 yamaguch if (m->m_len < (int)sizeof(*mdu)) { 1193 1.1 yamaguch m = m_pullup(m, sizeof(*mdu)); 1194 1.1 yamaguch if (m == NULL) { 1195 1.1 yamaguch lsc->lsc_mpullup_failed.ev_count++; 1196 1.1 yamaguch return ENOMEM; 1197 1.1 yamaguch } 1198 1.1 yamaguch } 1199 1.1 yamaguch 1200 1.1 yamaguch mdu = mtod(m, struct markerdu *); 1201 1.1 yamaguch 1202 1.1 yamaguch if (memcmp(mdu->mdu_eh.ether_dhost, 1203 1.1 yamaguch ethermulticastaddr_slowprotocols, ETHER_ADDR_LEN) != 0) 1204 1.1 yamaguch goto bad; 1205 1.1 yamaguch 1206 1.1 yamaguch LACP_TLV_PARSE(mdu, struct markerdu, mdu_tlv_info, 1207 1.1 yamaguch tlvlist_marker); 1208 1.1 yamaguch 1209 1.1 yamaguch mi_info = tlvlist_marker[MARKER_TLV_INFO].tlv_v; 1210 1.1 yamaguch mi_res = tlvlist_marker[MARKER_TLV_RESPONSE].tlv_v; 1211 1.1 yamaguch 1212 1.1 yamaguch if (LACP_ISDUMPING(lsc)) { 1213 1.1 yamaguch lacp_dprintf(lsc, lacpp, "markerdu received\n"); 1214 1.1 yamaguch lacp_dump_markertlv(mi_info, mi_res); 1215 1.1 yamaguch } 1216 1.1 yamaguch 1217 1.1 yamaguch if (mi_info != NULL && mi_res == NULL) { 1218 1.1 yamaguch lacp_marker_reply(lsc, lacpp, m); 1219 1.1 yamaguch } else if (mi_info == NULL && mi_res != NULL) { 1220 1.1 yamaguch error = lacp_marker_recv_response(lsc, lacpp, 1221 1.1 yamaguch mi_res); 1222 1.1 yamaguch if (error != 0) { 1223 1.1 yamaguch goto bad; 1224 1.1 yamaguch } else { 1225 1.1 yamaguch m_freem(m); 1226 1.1 yamaguch } 1227 1.1 yamaguch } else { 1228 1.1 yamaguch goto bad; 1229 1.1 yamaguch } 1230 1.1 yamaguch 1231 1.1 yamaguch return 0; 1232 1.1 yamaguch bad: 1233 1.1 yamaguch lsc->lsc_badmarkerdu.ev_count++; 1234 1.1 yamaguch m_freem(m); 1235 1.1 yamaguch return EINVAL; 1236 1.1 yamaguch } 1237 1.1 yamaguch 1238 1.1 yamaguch struct mbuf * 1239 1.1 yamaguch lacp_input(struct lagg_proto_softc *xlsc, struct lagg_port *lp, struct mbuf *m) 1240 1.1 yamaguch { 1241 1.1 yamaguch struct ifnet *ifp; 1242 1.1 yamaguch struct lacp_softc *lsc; 1243 1.1 yamaguch struct lacp_port *lacpp; 1244 1.1 yamaguch struct ether_header *eh; 1245 1.1 yamaguch uint8_t subtype; 1246 1.1 yamaguch 1247 1.1 yamaguch eh = mtod(m, struct ether_header *); 1248 1.1 yamaguch lsc = (struct lacp_softc *)xlsc; 1249 1.1 yamaguch ifp = &lsc->lsc_softc->sc_if; 1250 1.1 yamaguch lacpp = lp->lp_proto_ctx; 1251 1.1 yamaguch 1252 1.1 yamaguch if (!vlan_has_tag(m) && 1253 1.1 yamaguch eh->ether_type == htons(ETHERTYPE_SLOWPROTOCOLS)) { 1254 1.1 yamaguch if (m->m_pkthdr.len < (int)(sizeof(*eh) + sizeof(subtype))) { 1255 1.1 yamaguch m_freem(m); 1256 1.1 yamaguch return NULL; 1257 1.1 yamaguch } 1258 1.1 yamaguch 1259 1.1 yamaguch m_copydata(m, sizeof(struct ether_header), 1260 1.1 yamaguch sizeof(subtype), &subtype); 1261 1.18 yamaguch 1262 1.1 yamaguch switch (subtype) { 1263 1.1 yamaguch case SLOWPROTOCOLS_SUBTYPE_LACP: 1264 1.1 yamaguch case SLOWPROTOCOLS_SUBTYPE_MARKER: 1265 1.18 yamaguch if (pcq_put(lsc->lsc_du_q, (void *)m)) { 1266 1.18 yamaguch lagg_workq_add(lsc->lsc_workq, 1267 1.18 yamaguch &lsc->lsc_work_rcvdu); 1268 1.18 yamaguch } else { 1269 1.18 yamaguch m_freem(m); 1270 1.18 yamaguch lsc->lsc_duq_nospc.ev_count++; 1271 1.18 yamaguch } 1272 1.1 yamaguch return NULL; 1273 1.1 yamaguch } 1274 1.1 yamaguch } 1275 1.1 yamaguch 1276 1.1 yamaguch if (!lacp_iscollecting(lacpp) || !lacp_isactive(lsc, lacpp)) { 1277 1.1 yamaguch if_statinc(ifp, if_ierrors); 1278 1.1 yamaguch m_freem(m); 1279 1.1 yamaguch return NULL; 1280 1.1 yamaguch } 1281 1.1 yamaguch 1282 1.1 yamaguch return m; 1283 1.1 yamaguch } 1284 1.1 yamaguch 1285 1.18 yamaguch static void 1286 1.18 yamaguch lacp_rcvdu_work(struct lagg_work *lw __unused, void *xlsc) 1287 1.18 yamaguch { 1288 1.18 yamaguch struct lacp_softc *lsc = (struct lacp_softc *)xlsc; 1289 1.18 yamaguch struct ifnet *ifp; 1290 1.18 yamaguch struct psref psref_lp; 1291 1.18 yamaguch struct lagg_port *lp; 1292 1.18 yamaguch struct mbuf *m; 1293 1.18 yamaguch uint8_t subtype; 1294 1.38 yamaguch int bound, s0, s1; 1295 1.18 yamaguch 1296 1.18 yamaguch bound = curlwp_bind(); 1297 1.18 yamaguch 1298 1.18 yamaguch for (;;) { 1299 1.18 yamaguch m = pcq_get(lsc->lsc_du_q); 1300 1.18 yamaguch if (m == NULL) 1301 1.18 yamaguch break; 1302 1.18 yamaguch 1303 1.38 yamaguch ifp = m_get_rcvif(m, &s0); 1304 1.18 yamaguch if (ifp == NULL) { 1305 1.18 yamaguch m_freem(m); 1306 1.18 yamaguch lsc->lsc_norcvif.ev_count++; 1307 1.18 yamaguch continue; 1308 1.18 yamaguch } 1309 1.18 yamaguch 1310 1.38 yamaguch s1 = pserialize_read_enter(); 1311 1.18 yamaguch lp = atomic_load_consume(&ifp->if_lagg); 1312 1.18 yamaguch if (lp == NULL) { 1313 1.38 yamaguch pserialize_read_exit(s1); 1314 1.38 yamaguch m_put_rcvif(ifp, &s0); 1315 1.18 yamaguch m_freem(m); 1316 1.18 yamaguch lsc->lsc_norcvif.ev_count++; 1317 1.18 yamaguch continue; 1318 1.18 yamaguch } 1319 1.18 yamaguch 1320 1.18 yamaguch lagg_port_getref(lp, &psref_lp); 1321 1.38 yamaguch pserialize_read_exit(s1); 1322 1.38 yamaguch m_put_rcvif(ifp, &s0); 1323 1.18 yamaguch 1324 1.18 yamaguch m_copydata(m, sizeof(struct ether_header), 1325 1.18 yamaguch sizeof(subtype), &subtype); 1326 1.18 yamaguch 1327 1.18 yamaguch switch (subtype) { 1328 1.18 yamaguch case SLOWPROTOCOLS_SUBTYPE_LACP: 1329 1.18 yamaguch (void)lacp_pdu_input(lsc, 1330 1.18 yamaguch lp->lp_proto_ctx, m); 1331 1.18 yamaguch break; 1332 1.18 yamaguch case SLOWPROTOCOLS_SUBTYPE_MARKER: 1333 1.18 yamaguch (void)lacp_marker_input(lsc, 1334 1.18 yamaguch lp->lp_proto_ctx, m); 1335 1.18 yamaguch break; 1336 1.18 yamaguch } 1337 1.18 yamaguch 1338 1.18 yamaguch lagg_port_putref(lp, &psref_lp); 1339 1.18 yamaguch } 1340 1.18 yamaguch 1341 1.18 yamaguch curlwp_bindx(bound); 1342 1.18 yamaguch } 1343 1.18 yamaguch 1344 1.1 yamaguch static bool 1345 1.1 yamaguch lacp_port_need_to_tell(struct lacp_port *lacpp) 1346 1.1 yamaguch { 1347 1.1 yamaguch 1348 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, 1349 1.1 yamaguch LACP_STATE_AGGREGATION)) { 1350 1.1 yamaguch return false; 1351 1.1 yamaguch } 1352 1.1 yamaguch 1353 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, 1354 1.1 yamaguch LACP_STATE_ACTIVITY) 1355 1.1 yamaguch && !ISSET(lacpp->lp_partner.lpi_state, 1356 1.1 yamaguch LACP_STATE_ACTIVITY)) { 1357 1.1 yamaguch return false; 1358 1.1 yamaguch } 1359 1.1 yamaguch 1360 1.1 yamaguch if (!ISSET(lacpp->lp_flags, LACP_PORT_NTT)) 1361 1.1 yamaguch return false; 1362 1.1 yamaguch 1363 1.1 yamaguch return true; 1364 1.1 yamaguch } 1365 1.1 yamaguch 1366 1.1 yamaguch static void 1367 1.1 yamaguch lacp_sm_assert_ntt(struct lacp_port *lacpp) 1368 1.1 yamaguch { 1369 1.1 yamaguch 1370 1.1 yamaguch SET(lacpp->lp_flags, LACP_PORT_NTT); 1371 1.1 yamaguch } 1372 1.1 yamaguch 1373 1.1 yamaguch static void 1374 1.1 yamaguch lacp_sm_negate_ntt(struct lacp_port *lacpp) 1375 1.1 yamaguch { 1376 1.1 yamaguch 1377 1.1 yamaguch CLR(lacpp->lp_flags, LACP_PORT_NTT); 1378 1.1 yamaguch } 1379 1.1 yamaguch 1380 1.1 yamaguch static struct mbuf * 1381 1.1 yamaguch lacp_lacpdu_mbuf(struct lacp_softc *lsc, struct lacp_port *lacpp) 1382 1.1 yamaguch { 1383 1.1 yamaguch struct ifnet *ifp_port; 1384 1.1 yamaguch struct mbuf *m; 1385 1.1 yamaguch struct lacpdu *du; 1386 1.1 yamaguch 1387 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 1388 1.1 yamaguch 1389 1.1 yamaguch ifp_port = lacpp->lp_laggport->lp_ifp; 1390 1.1 yamaguch 1391 1.1 yamaguch MGETHDR(m, M_DONTWAIT, MT_DATA); 1392 1.1 yamaguch if (m == NULL) { 1393 1.1 yamaguch lsc->lsc_mgethdr_failed.ev_count++; 1394 1.1 yamaguch return NULL; 1395 1.1 yamaguch } 1396 1.1 yamaguch 1397 1.1 yamaguch m->m_pkthdr.len = m->m_len = sizeof(*du); 1398 1.24 yamaguch m_reset_rcvif(m); 1399 1.1 yamaguch 1400 1.1 yamaguch du = mtod(m, struct lacpdu *); 1401 1.1 yamaguch memset(du, 0, sizeof(*du)); 1402 1.1 yamaguch 1403 1.1 yamaguch m->m_flags |= M_MCAST; 1404 1.1 yamaguch memcpy(du->ldu_eh.ether_dhost, ethermulticastaddr_slowprotocols, 1405 1.1 yamaguch ETHER_ADDR_LEN); 1406 1.1 yamaguch memcpy(du->ldu_eh.ether_shost, CLLADDR(ifp_port->if_sadl), 1407 1.1 yamaguch ETHER_ADDR_LEN); 1408 1.1 yamaguch du->ldu_eh.ether_type = htons(ETHERTYPE_SLOWPROTOCOLS); 1409 1.1 yamaguch du->ldu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_LACP; 1410 1.1 yamaguch du->ldu_sph.sph_version = 1; 1411 1.1 yamaguch 1412 1.1 yamaguch tlv_set(&du->ldu_tlv_actor, LACP_TYPE_ACTORINFO, 1413 1.1 yamaguch sizeof(du->ldu_actor)); 1414 1.1 yamaguch lacp_peerinfo_actor(lsc, lacpp, &du->ldu_actor); 1415 1.1 yamaguch 1416 1.1 yamaguch tlv_set(&du->ldu_tlv_partner, LACP_TYPE_PARTNERINFO, 1417 1.1 yamaguch sizeof(du->ldu_partner)); 1418 1.1 yamaguch lacp_peerinfo_partner(lacpp, &du->ldu_partner); 1419 1.1 yamaguch 1420 1.1 yamaguch tlv_set(&du->ldu_tlv_collector, LACP_TYPE_COLLECTORINFO, 1421 1.1 yamaguch sizeof(du->ldu_collector)); 1422 1.1 yamaguch du->ldu_collector.lci_maxdelay = 0; 1423 1.1 yamaguch 1424 1.1 yamaguch du->ldu_tlv_term.tlv_type = LACP_TYPE_TERMINATE; 1425 1.1 yamaguch du->ldu_tlv_term.tlv_length = 0; 1426 1.1 yamaguch 1427 1.1 yamaguch return m; 1428 1.1 yamaguch } 1429 1.1 yamaguch 1430 1.1 yamaguch static void 1431 1.1 yamaguch lacp_sm_tx_work(struct lagg_work *lw, void *xlsc) 1432 1.1 yamaguch { 1433 1.1 yamaguch struct lacp_softc *lsc; 1434 1.1 yamaguch struct lacp_port *lacpp; 1435 1.1 yamaguch struct lagg_port *lp; 1436 1.1 yamaguch struct lacpdu *du; 1437 1.1 yamaguch struct mbuf *m; 1438 1.1 yamaguch struct psref psref; 1439 1.1 yamaguch int bound; 1440 1.1 yamaguch 1441 1.1 yamaguch lsc = xlsc; 1442 1.1 yamaguch lacpp = container_of(lw, struct lacp_port, lp_work_smtx); 1443 1.1 yamaguch 1444 1.39 yamaguch LACP_LOCK(lsc); 1445 1.39 yamaguch 1446 1.39 yamaguch if (lsc->lsc_stop_lacpdu) { 1447 1.39 yamaguch LACP_UNLOCK(lsc); 1448 1.1 yamaguch return; 1449 1.39 yamaguch } 1450 1.1 yamaguch 1451 1.1 yamaguch m = lacp_lacpdu_mbuf(lsc, lacpp); 1452 1.1 yamaguch if (m == NULL) { 1453 1.1 yamaguch LACP_UNLOCK(lsc); 1454 1.1 yamaguch return; 1455 1.1 yamaguch } 1456 1.1 yamaguch lacp_sm_negate_ntt(lacpp); 1457 1.1 yamaguch lp = lacpp->lp_laggport; 1458 1.1 yamaguch bound = curlwp_bind(); 1459 1.1 yamaguch lagg_port_getref(lp, &psref); 1460 1.1 yamaguch LACP_UNLOCK(lsc); 1461 1.1 yamaguch 1462 1.1 yamaguch if (LACP_ISDUMPING(lsc)) { 1463 1.1 yamaguch lacp_dprintf(lsc, lacpp, "lacpdu transmit\n"); 1464 1.1 yamaguch du = mtod(m, struct lacpdu *); 1465 1.1 yamaguch lacp_dump_lacpdutlv(&du->ldu_actor, 1466 1.1 yamaguch &du->ldu_partner, &du->ldu_collector); 1467 1.1 yamaguch } 1468 1.1 yamaguch 1469 1.1 yamaguch lagg_port_xmit(lp, m); 1470 1.1 yamaguch lagg_port_putref(lp, &psref); 1471 1.1 yamaguch curlwp_bindx(bound); 1472 1.1 yamaguch } 1473 1.1 yamaguch 1474 1.1 yamaguch static void 1475 1.1 yamaguch lacp_sm_tx(struct lacp_softc *lsc, struct lacp_port *lacpp) 1476 1.1 yamaguch { 1477 1.1 yamaguch 1478 1.1 yamaguch if (!lacp_port_need_to_tell(lacpp)) 1479 1.1 yamaguch return; 1480 1.1 yamaguch 1481 1.1 yamaguch lagg_workq_add(lsc->lsc_workq, &lacpp->lp_work_smtx); 1482 1.1 yamaguch } 1483 1.1 yamaguch 1484 1.1 yamaguch static void 1485 1.1 yamaguch lacp_tick(void *xlsc) 1486 1.1 yamaguch { 1487 1.1 yamaguch struct lacp_softc *lsc; 1488 1.1 yamaguch 1489 1.1 yamaguch lsc = xlsc; 1490 1.1 yamaguch 1491 1.40 yamaguch LACP_LOCK(lsc); 1492 1.40 yamaguch 1493 1.40 yamaguch if (!lsc->lsc_running) { 1494 1.40 yamaguch LACP_UNLOCK(lsc); 1495 1.40 yamaguch return; 1496 1.40 yamaguch } 1497 1.40 yamaguch 1498 1.1 yamaguch lagg_workq_add(lsc->lsc_workq, &lsc->lsc_work_tick); 1499 1.40 yamaguch callout_schedule(&lsc->lsc_tick, hz); 1500 1.1 yamaguch 1501 1.1 yamaguch LACP_UNLOCK(lsc); 1502 1.1 yamaguch } 1503 1.1 yamaguch 1504 1.1 yamaguch static void 1505 1.1 yamaguch lacp_run_timers(struct lacp_softc *lsc, struct lacp_port *lacpp) 1506 1.1 yamaguch { 1507 1.1 yamaguch size_t i; 1508 1.1 yamaguch 1509 1.35 yamaguch KASSERT(LACP_LOCKED(lsc)); 1510 1.35 yamaguch 1511 1.1 yamaguch for (i = 0; i < LACP_NTIMER; i++) { 1512 1.1 yamaguch KASSERT(lacpp->lp_timer[i] >= 0); 1513 1.1 yamaguch 1514 1.1 yamaguch if (lacpp->lp_timer[i] == 0) 1515 1.1 yamaguch continue; 1516 1.1 yamaguch if (--lacpp->lp_timer[i] > 0) 1517 1.1 yamaguch continue; 1518 1.1 yamaguch 1519 1.1 yamaguch KASSERT(lacp_timer_funcs[i] != NULL); 1520 1.1 yamaguch lacp_timer_funcs[i](lsc, lacpp); 1521 1.1 yamaguch } 1522 1.1 yamaguch } 1523 1.1 yamaguch 1524 1.1 yamaguch static void 1525 1.1 yamaguch lacp_run_prototimers(struct lacp_softc *lsc) 1526 1.1 yamaguch { 1527 1.1 yamaguch size_t i; 1528 1.1 yamaguch 1529 1.1 yamaguch for (i = 0; i < LACP_NPTIMER; i++) { 1530 1.1 yamaguch KASSERT(lsc->lsc_timer[i] >= 0); 1531 1.1 yamaguch 1532 1.1 yamaguch if (lsc->lsc_timer[i] == 0) 1533 1.1 yamaguch continue; 1534 1.1 yamaguch if (--lsc->lsc_timer[i] > 0) 1535 1.1 yamaguch continue; 1536 1.1 yamaguch 1537 1.1 yamaguch KASSERT(lacp_ptimer_funcs[i] != NULL); 1538 1.1 yamaguch lacp_ptimer_funcs[i](lsc); 1539 1.1 yamaguch } 1540 1.1 yamaguch } 1541 1.1 yamaguch 1542 1.1 yamaguch static void 1543 1.1 yamaguch lacp_tick_work(struct lagg_work *lw __unused, void *xlsc) 1544 1.1 yamaguch { 1545 1.1 yamaguch struct lacp_softc *lsc; 1546 1.1 yamaguch struct lacp_port *lacpp; 1547 1.1 yamaguch struct lagg_softc *sc; 1548 1.1 yamaguch struct lagg_port *lp; 1549 1.1 yamaguch 1550 1.1 yamaguch lsc = xlsc; 1551 1.1 yamaguch sc = lsc->lsc_softc; 1552 1.1 yamaguch 1553 1.1 yamaguch LACP_LOCK(lsc); 1554 1.40 yamaguch if (!lsc->lsc_running) { 1555 1.40 yamaguch LACP_UNLOCK(lsc); 1556 1.40 yamaguch return; 1557 1.40 yamaguch } 1558 1.40 yamaguch 1559 1.1 yamaguch lacp_run_prototimers(lsc); 1560 1.1 yamaguch LACP_UNLOCK(lsc); 1561 1.1 yamaguch 1562 1.1 yamaguch LAGG_LOCK(sc); 1563 1.1 yamaguch LACP_LOCK(lsc); 1564 1.1 yamaguch LAGG_PORTS_FOREACH(sc, lp) { 1565 1.1 yamaguch lacpp = lp->lp_proto_ctx; 1566 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, 1567 1.1 yamaguch LACP_STATE_AGGREGATION)) { 1568 1.1 yamaguch continue; 1569 1.1 yamaguch } 1570 1.1 yamaguch 1571 1.1 yamaguch lacp_run_timers(lsc, lacpp); 1572 1.1 yamaguch lacp_select(lsc, lacpp); 1573 1.1 yamaguch lacp_sm_mux(lsc, lacpp); 1574 1.1 yamaguch lacp_sm_tx(lsc, lacpp); 1575 1.1 yamaguch lacp_sm_ptx_schedule(lacpp); 1576 1.1 yamaguch } 1577 1.1 yamaguch 1578 1.1 yamaguch LACP_UNLOCK(lsc); 1579 1.1 yamaguch LAGG_UNLOCK(sc); 1580 1.1 yamaguch } 1581 1.1 yamaguch 1582 1.1 yamaguch static void 1583 1.1 yamaguch lacp_systemid_str(char *buf, size_t buflen, 1584 1.1 yamaguch uint16_t prio, const uint8_t *mac, uint16_t key) 1585 1.1 yamaguch { 1586 1.1 yamaguch 1587 1.1 yamaguch snprintf(buf, buflen, 1588 1.1 yamaguch "%04X," 1589 1.1 yamaguch "%02X-%02X-%02X-%02X-%02X-%02X," 1590 1.1 yamaguch "%04X", 1591 1.1 yamaguch (unsigned int)ntohs(prio), 1592 1.1 yamaguch (int)mac[0], (int)mac[1], (int)mac[2], 1593 1.1 yamaguch (int)mac[3], (int)mac[4], (int)mac[5], 1594 1.1 yamaguch (unsigned int)htons(key)); 1595 1.1 yamaguch 1596 1.1 yamaguch } 1597 1.1 yamaguch 1598 1.1 yamaguch __LACPDEBUGUSED static void 1599 1.1 yamaguch lacp_aggregator_str(struct lacp_aggregator *la, char *buf, size_t buflen) 1600 1.1 yamaguch { 1601 1.1 yamaguch 1602 1.1 yamaguch lacp_systemid_str(buf, buflen, la->la_sid.sid_prio, 1603 1.1 yamaguch la->la_sid.sid_mac, la->la_sid.sid_key); 1604 1.1 yamaguch } 1605 1.1 yamaguch 1606 1.1 yamaguch static void 1607 1.1 yamaguch lacp_peerinfo_idstr(const struct lacpdu_peerinfo *pi, 1608 1.1 yamaguch char *buf, size_t buflen) 1609 1.1 yamaguch { 1610 1.1 yamaguch 1611 1.1 yamaguch lacp_systemid_str(buf, buflen, pi->lpi_system_prio, 1612 1.1 yamaguch pi->lpi_system_mac, pi->lpi_key); 1613 1.1 yamaguch } 1614 1.1 yamaguch 1615 1.1 yamaguch static void 1616 1.1 yamaguch lacp_state_str(uint8_t state, char *buf, size_t buflen) 1617 1.1 yamaguch { 1618 1.1 yamaguch 1619 1.1 yamaguch snprintb(buf, buflen, LACP_STATE_BITS, state); 1620 1.1 yamaguch } 1621 1.1 yamaguch 1622 1.1 yamaguch static struct lagg_port * 1623 1.1 yamaguch lacp_select_tx_port(struct lacp_softc *lsc, struct mbuf *m, 1624 1.1 yamaguch struct psref *psref) 1625 1.1 yamaguch { 1626 1.1 yamaguch struct lacp_portmap *pm; 1627 1.1 yamaguch struct lagg_port *lp; 1628 1.1 yamaguch uint32_t hash; 1629 1.1 yamaguch size_t act; 1630 1.1 yamaguch int s; 1631 1.1 yamaguch 1632 1.1 yamaguch hash = lagg_hashmbuf(lsc->lsc_softc, m); 1633 1.1 yamaguch 1634 1.1 yamaguch s = pserialize_read_enter(); 1635 1.1 yamaguch act = LACP_PORTMAP_ACTIVE(lsc); 1636 1.1 yamaguch pm = &lsc->lsc_portmaps[act]; 1637 1.1 yamaguch 1638 1.1 yamaguch if (pm->pm_count == 0) { 1639 1.1 yamaguch pserialize_read_exit(s); 1640 1.1 yamaguch return NULL; 1641 1.1 yamaguch } 1642 1.1 yamaguch 1643 1.1 yamaguch hash %= pm->pm_count; 1644 1.1 yamaguch lp = pm->pm_ports[hash]; 1645 1.1 yamaguch lagg_port_getref(lp, psref); 1646 1.1 yamaguch 1647 1.1 yamaguch pserialize_read_exit(s); 1648 1.1 yamaguch 1649 1.1 yamaguch return lp; 1650 1.1 yamaguch } 1651 1.1 yamaguch 1652 1.1 yamaguch static void 1653 1.1 yamaguch lacp_peerinfo_actor(struct lacp_softc *lsc, struct lacp_port *lacpp, 1654 1.1 yamaguch struct lacpdu_peerinfo *dst) 1655 1.1 yamaguch { 1656 1.1 yamaguch 1657 1.1 yamaguch memcpy(dst->lpi_system_mac, lsc->lsc_system_mac, LACP_MAC_LEN); 1658 1.1 yamaguch dst->lpi_system_prio = lsc->lsc_system_prio; 1659 1.1 yamaguch dst->lpi_key = lsc->lsc_key; 1660 1.1 yamaguch dst->lpi_port_no = lacpp->lp_actor.lpi_portno; 1661 1.1 yamaguch dst->lpi_port_prio = lacpp->lp_actor.lpi_portprio; 1662 1.1 yamaguch dst->lpi_state = lacpp->lp_actor.lpi_state; 1663 1.1 yamaguch } 1664 1.1 yamaguch 1665 1.1 yamaguch static void 1666 1.1 yamaguch lacp_peerinfo_partner(struct lacp_port *lacpp, struct lacpdu_peerinfo *dst) 1667 1.1 yamaguch { 1668 1.1 yamaguch struct lacp_aggregator *la; 1669 1.1 yamaguch 1670 1.1 yamaguch la = lacpp->lp_aggregator; 1671 1.1 yamaguch 1672 1.1 yamaguch if (la != NULL) { 1673 1.1 yamaguch memcpy(dst->lpi_system_mac, la->la_sid.sid_mac, LACP_MAC_LEN); 1674 1.1 yamaguch dst->lpi_system_prio = la->la_sid.sid_prio; 1675 1.1 yamaguch dst->lpi_key = la->la_sid.sid_key; 1676 1.1 yamaguch } else { 1677 1.1 yamaguch memset(dst->lpi_system_mac, 0, LACP_MAC_LEN); 1678 1.1 yamaguch dst->lpi_system_prio = 0; 1679 1.1 yamaguch dst->lpi_key = 0; 1680 1.1 yamaguch } 1681 1.1 yamaguch dst->lpi_port_no = lacpp->lp_partner.lpi_portno; 1682 1.1 yamaguch dst->lpi_port_prio = lacpp->lp_partner.lpi_portprio; 1683 1.1 yamaguch dst->lpi_state = lacpp->lp_partner.lpi_state; 1684 1.1 yamaguch } 1685 1.1 yamaguch 1686 1.1 yamaguch static int 1687 1.1 yamaguch lacp_compare_peerinfo(struct lacpdu_peerinfo *a, struct lacpdu_peerinfo *b) 1688 1.1 yamaguch { 1689 1.1 yamaguch 1690 1.1 yamaguch return memcmp(a, b, offsetof(struct lacpdu_peerinfo, lpi_state)); 1691 1.1 yamaguch } 1692 1.1 yamaguch 1693 1.1 yamaguch static void 1694 1.1 yamaguch lacp_sm_rx_record_default(struct lacp_softc *lsc, struct lacp_port *lacpp) 1695 1.1 yamaguch { 1696 1.1 yamaguch uint8_t oldpstate; 1697 1.1 yamaguch struct lacp_portinfo *pi; 1698 1.1 yamaguch char buf[LACP_STATESTR_LEN] __LACPDEBUGUSED; 1699 1.1 yamaguch 1700 1.1 yamaguch pi = &lacpp->lp_partner; 1701 1.1 yamaguch 1702 1.1 yamaguch oldpstate = pi->lpi_state; 1703 1.1 yamaguch pi->lpi_portno = htons(LACP_PORTNO_NONE); 1704 1.1 yamaguch pi->lpi_portprio = htons(0xffff); 1705 1.1 yamaguch 1706 1.1 yamaguch if (lsc->lsc_optimistic) 1707 1.1 yamaguch pi->lpi_state = LACP_PARTNER_ADMIN_OPTIMISTIC; 1708 1.1 yamaguch else 1709 1.1 yamaguch pi->lpi_state = LACP_PARTNER_ADMIN_STRICT; 1710 1.1 yamaguch 1711 1.1 yamaguch SET(lacpp->lp_actor.lpi_state, LACP_STATE_DEFAULTED); 1712 1.1 yamaguch 1713 1.1 yamaguch if (oldpstate != pi->lpi_state) { 1714 1.1 yamaguch LACP_STATE_STR(oldpstate, buf, sizeof(buf)); 1715 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "oldpstate %s\n", buf)); 1716 1.1 yamaguch 1717 1.1 yamaguch LACP_STATE_STR(pi->lpi_state, buf, sizeof(buf)); 1718 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "newpstate %s\n", buf)); 1719 1.1 yamaguch } 1720 1.27 yamaguch 1721 1.27 yamaguch lacp_sm_ptx_update_timeout(lacpp, oldpstate); 1722 1.1 yamaguch } 1723 1.1 yamaguch 1724 1.1 yamaguch static inline bool 1725 1.1 yamaguch lacp_port_is_synced(struct lacp_softc *lsc, struct lacp_port *lacpp, 1726 1.1 yamaguch struct lacpdu_peerinfo *my_pi, struct lacpdu_peerinfo *peer_pi) 1727 1.1 yamaguch { 1728 1.1 yamaguch struct lacpdu_peerinfo actor; 1729 1.1 yamaguch 1730 1.1 yamaguch if (!ISSET(peer_pi->lpi_state, LACP_STATE_ACTIVITY) && 1731 1.1 yamaguch (!ISSET(my_pi->lpi_state, LACP_STATE_ACTIVITY) || 1732 1.1 yamaguch !ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_ACTIVITY))) 1733 1.1 yamaguch return false; 1734 1.1 yamaguch 1735 1.1 yamaguch if (!ISSET(peer_pi->lpi_state, LACP_STATE_AGGREGATION)) 1736 1.1 yamaguch return false; 1737 1.1 yamaguch 1738 1.1 yamaguch lacp_peerinfo_actor(lsc, lacpp, &actor); 1739 1.1 yamaguch if (lacp_compare_peerinfo(&actor, my_pi) != 0) 1740 1.1 yamaguch return false; 1741 1.1 yamaguch 1742 1.1 yamaguch if (!LACP_STATE_EQ(actor.lpi_state, my_pi->lpi_state, 1743 1.1 yamaguch LACP_STATE_AGGREGATION)) { 1744 1.1 yamaguch return false; 1745 1.1 yamaguch } 1746 1.1 yamaguch 1747 1.1 yamaguch return true; 1748 1.1 yamaguch } 1749 1.1 yamaguch 1750 1.1 yamaguch static void 1751 1.1 yamaguch lacp_sm_rx_record_peerinfo(struct lacp_softc *lsc, struct lacp_port *lacpp, 1752 1.1 yamaguch struct lacpdu_peerinfo *my_pi, struct lacpdu_peerinfo *peer_pi) 1753 1.1 yamaguch { 1754 1.1 yamaguch char buf[LACP_STATESTR_LEN] __LACPDEBUGUSED; 1755 1.1 yamaguch uint8_t oldpstate; 1756 1.1 yamaguch struct lacp_portinfo *pi; 1757 1.1 yamaguch struct lacp_aggregator_systemid *sid; 1758 1.1 yamaguch 1759 1.1 yamaguch pi = &lacpp->lp_partner; 1760 1.1 yamaguch sid = &lacpp->lp_aggregator_sidbuf; 1761 1.1 yamaguch 1762 1.1 yamaguch oldpstate = lacpp->lp_partner.lpi_state; 1763 1.1 yamaguch 1764 1.1 yamaguch sid->sid_prio = peer_pi->lpi_system_prio; 1765 1.1 yamaguch sid->sid_key = peer_pi->lpi_key; 1766 1.1 yamaguch memcpy(sid->sid_mac, peer_pi->lpi_system_mac, 1767 1.1 yamaguch sizeof(sid->sid_mac)); 1768 1.1 yamaguch 1769 1.1 yamaguch pi->lpi_portno = peer_pi->lpi_port_no; 1770 1.1 yamaguch pi->lpi_portprio = peer_pi->lpi_port_prio; 1771 1.1 yamaguch pi->lpi_state = peer_pi->lpi_state; 1772 1.1 yamaguch 1773 1.1 yamaguch if (lacp_port_is_synced(lsc, lacpp, my_pi, peer_pi)) { 1774 1.1 yamaguch if (lsc->lsc_optimistic) 1775 1.1 yamaguch SET(lacpp->lp_partner.lpi_state, LACP_STATE_SYNC); 1776 1.1 yamaguch } else { 1777 1.1 yamaguch CLR(lacpp->lp_partner.lpi_state, LACP_STATE_SYNC); 1778 1.1 yamaguch } 1779 1.1 yamaguch 1780 1.1 yamaguch CLR(lacpp->lp_actor.lpi_state, LACP_STATE_DEFAULTED); 1781 1.1 yamaguch 1782 1.1 yamaguch if (oldpstate != lacpp->lp_partner.lpi_state) { 1783 1.1 yamaguch LACP_STATE_STR(oldpstate, buf, sizeof(buf)); 1784 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "oldpstate %s\n", buf)); 1785 1.1 yamaguch 1786 1.1 yamaguch LACP_STATE_STR(lacpp->lp_partner.lpi_state, 1787 1.1 yamaguch buf, sizeof(buf)); 1788 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "newpstate %s\n", buf)); 1789 1.1 yamaguch } 1790 1.1 yamaguch 1791 1.1 yamaguch lacp_sm_ptx_update_timeout(lacpp, oldpstate); 1792 1.1 yamaguch } 1793 1.1 yamaguch 1794 1.1 yamaguch static void 1795 1.1 yamaguch lacp_sm_rx_set_expired(struct lacp_port *lacpp) 1796 1.1 yamaguch { 1797 1.27 yamaguch uint8_t oldpstate; 1798 1.27 yamaguch 1799 1.27 yamaguch oldpstate = lacpp->lp_partner.lpi_state; 1800 1.1 yamaguch 1801 1.1 yamaguch CLR(lacpp->lp_partner.lpi_state, LACP_STATE_SYNC); 1802 1.1 yamaguch SET(lacpp->lp_partner.lpi_state, LACP_STATE_TIMEOUT); 1803 1.1 yamaguch LACP_TIMER_ARM(lacpp, LACP_TIMER_CURRENT_WHILE, 1804 1.1 yamaguch LACP_SHORT_TIMEOUT_TIME); 1805 1.1 yamaguch SET(lacpp->lp_actor.lpi_state, LACP_STATE_EXPIRED); 1806 1.27 yamaguch 1807 1.27 yamaguch lacp_sm_ptx_update_timeout(lacpp, oldpstate); 1808 1.1 yamaguch } 1809 1.1 yamaguch 1810 1.1 yamaguch static void 1811 1.1 yamaguch lacp_sm_port_init(struct lacp_softc *lsc, struct lacp_port *lacpp, 1812 1.1 yamaguch struct lagg_port *lp) 1813 1.1 yamaguch { 1814 1.1 yamaguch 1815 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 1816 1.1 yamaguch 1817 1.1 yamaguch lacpp->lp_laggport = lp; 1818 1.1 yamaguch lacpp->lp_actor.lpi_state = LACP_STATE_ACTIVITY; 1819 1.1 yamaguch lacpp->lp_actor.lpi_portno = htons(if_get_index(lp->lp_ifp)); 1820 1.1 yamaguch lacpp->lp_actor.lpi_portprio = htons(LACP_PORT_PRIO); 1821 1.1 yamaguch lacpp->lp_partner.lpi_state = LACP_STATE_TIMEOUT; 1822 1.1 yamaguch lacpp->lp_aggregator = NULL; 1823 1.1 yamaguch lacpp->lp_marker_xid = 0; 1824 1.1 yamaguch lacpp->lp_mux_state = LACP_MUX_INIT; 1825 1.1 yamaguch 1826 1.1 yamaguch lacp_set_mux(lsc, lacpp, LACP_MUX_DETACHED); 1827 1.1 yamaguch lacp_sm_rx_record_default(lsc, lacpp); 1828 1.1 yamaguch } 1829 1.1 yamaguch 1830 1.1 yamaguch static void 1831 1.1 yamaguch lacp_port_disable(struct lacp_softc *lsc, struct lacp_port *lacpp) 1832 1.1 yamaguch { 1833 1.1 yamaguch 1834 1.35 yamaguch KASSERT(LACP_LOCKED(lsc)); 1835 1.35 yamaguch 1836 1.1 yamaguch if (ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_AGGREGATION)) 1837 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "enable -> disable\n")); 1838 1.1 yamaguch 1839 1.1 yamaguch lacp_set_mux(lsc, lacpp, LACP_MUX_DETACHED); 1840 1.1 yamaguch lacp_sm_rx_record_default(lsc, lacpp); 1841 1.1 yamaguch CLR(lacpp->lp_actor.lpi_state, 1842 1.1 yamaguch LACP_STATE_AGGREGATION | LACP_STATE_EXPIRED); 1843 1.1 yamaguch CLR(lacpp->lp_partner.lpi_state, LACP_STATE_AGGREGATION); 1844 1.1 yamaguch } 1845 1.1 yamaguch 1846 1.1 yamaguch static void 1847 1.1 yamaguch lacp_port_enable(struct lacp_softc *lsc __LACPDEBUGUSED, 1848 1.1 yamaguch struct lacp_port *lacpp) 1849 1.1 yamaguch { 1850 1.1 yamaguch 1851 1.35 yamaguch KASSERT(LACP_LOCKED(lsc)); 1852 1.35 yamaguch 1853 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_AGGREGATION)) 1854 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "disable -> enable\n")); 1855 1.1 yamaguch 1856 1.1 yamaguch SET(lacpp->lp_actor.lpi_state, LACP_STATE_AGGREGATION); 1857 1.1 yamaguch lacp_sm_rx_set_expired(lacpp); 1858 1.1 yamaguch } 1859 1.1 yamaguch 1860 1.1 yamaguch static void 1861 1.1 yamaguch lacp_sm_rx_timer(struct lacp_softc *lsc, struct lacp_port *lacpp) 1862 1.1 yamaguch { 1863 1.1 yamaguch 1864 1.35 yamaguch KASSERT(LACP_LOCKED(lsc)); 1865 1.35 yamaguch 1866 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_EXPIRED)) { 1867 1.1 yamaguch /* CURRENT -> EXPIRED */ 1868 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "CURRENT -> EXPIRED\n")); 1869 1.1 yamaguch lacp_sm_rx_set_expired(lacpp); 1870 1.1 yamaguch } else { 1871 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "EXPIRED -> DEFAULTED\n")); 1872 1.1 yamaguch lacp_set_mux(lsc, lacpp, LACP_MUX_DETACHED); 1873 1.1 yamaguch lacp_sm_rx_record_default(lsc, lacpp); 1874 1.1 yamaguch } 1875 1.1 yamaguch } 1876 1.1 yamaguch 1877 1.1 yamaguch static void 1878 1.1 yamaguch lacp_sm_ptx_timer(struct lacp_softc *lsc __unused, struct lacp_port *lacpp) 1879 1.1 yamaguch { 1880 1.1 yamaguch 1881 1.35 yamaguch KASSERT(LACP_LOCKED(lsc)); 1882 1.1 yamaguch lacp_sm_assert_ntt(lacpp); 1883 1.1 yamaguch } 1884 1.1 yamaguch 1885 1.1 yamaguch static void 1886 1.1 yamaguch lacp_sm_ptx_schedule(struct lacp_port *lacpp) 1887 1.1 yamaguch { 1888 1.1 yamaguch int timeout; 1889 1.1 yamaguch 1890 1.1 yamaguch /* no periodic */ 1891 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_ACTIVITY) && 1892 1.1 yamaguch !ISSET(lacpp->lp_partner.lpi_state, LACP_STATE_ACTIVITY)) { 1893 1.1 yamaguch LACP_TIMER_DISARM(lacpp, LACP_TIMER_PERIODIC); 1894 1.1 yamaguch return; 1895 1.1 yamaguch } 1896 1.1 yamaguch 1897 1.1 yamaguch if (LACP_TIMER_ISARMED(lacpp, LACP_TIMER_PERIODIC)) 1898 1.1 yamaguch return; 1899 1.1 yamaguch 1900 1.26 yamaguch timeout = ISSET(lacpp->lp_partner.lpi_state, LACP_STATE_TIMEOUT) ? 1901 1.1 yamaguch LACP_FAST_PERIODIC_TIME : LACP_SLOW_PERIODIC_TIME; 1902 1.1 yamaguch 1903 1.1 yamaguch LACP_TIMER_ARM(lacpp, LACP_TIMER_PERIODIC, timeout); 1904 1.1 yamaguch } 1905 1.1 yamaguch 1906 1.1 yamaguch static void 1907 1.1 yamaguch lacp_sm_ptx_update_timeout(struct lacp_port *lacpp, uint8_t oldpstate) 1908 1.1 yamaguch { 1909 1.1 yamaguch 1910 1.1 yamaguch if (LACP_STATE_EQ(oldpstate, lacpp->lp_partner.lpi_state, 1911 1.1 yamaguch LACP_STATE_TIMEOUT)) 1912 1.1 yamaguch return; 1913 1.1 yamaguch 1914 1.1 yamaguch LACP_DPRINTF((NULL, lacpp, "partner timeout changed\n")); 1915 1.1 yamaguch 1916 1.1 yamaguch LACP_TIMER_DISARM(lacpp, LACP_TIMER_PERIODIC); 1917 1.1 yamaguch 1918 1.1 yamaguch /* if timeout has been shorted, assert NTT */ 1919 1.1 yamaguch if (ISSET(lacpp->lp_partner.lpi_state, LACP_STATE_TIMEOUT)) 1920 1.1 yamaguch lacp_sm_assert_ntt(lacpp); 1921 1.1 yamaguch } 1922 1.1 yamaguch 1923 1.1 yamaguch static void 1924 1.1 yamaguch lacp_sm_mux_timer(struct lacp_softc *lsc __LACPDEBUGUSED, 1925 1.1 yamaguch struct lacp_port *lacpp) 1926 1.1 yamaguch { 1927 1.1 yamaguch char buf[LACP_SYSTEMIDSTR_LEN] __LACPDEBUGUSED; 1928 1.1 yamaguch 1929 1.35 yamaguch KASSERT(LACP_LOCKED(lsc)); 1930 1.1 yamaguch KASSERT(lacpp->lp_pending > 0); 1931 1.1 yamaguch 1932 1.1 yamaguch LACP_AGGREGATOR_STR(lacpp->lp_aggregator, buf, sizeof(buf)); 1933 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "aggregator %s, pending %d -> %d\n", 1934 1.1 yamaguch buf, lacpp->lp_pending, lacpp->lp_pending -1)); 1935 1.1 yamaguch 1936 1.1 yamaguch lacpp->lp_pending--; 1937 1.1 yamaguch } 1938 1.1 yamaguch 1939 1.1 yamaguch static void 1940 1.1 yamaguch lacp_sm_rx_update_selected(struct lacp_softc *lsc, struct lacp_port *lacpp, 1941 1.1 yamaguch struct lacpdu_peerinfo *peer_pi) 1942 1.1 yamaguch { 1943 1.1 yamaguch struct lacpdu_peerinfo partner; 1944 1.1 yamaguch char str0[LACP_SYSTEMIDSTR_LEN] __LACPDEBUGUSED; 1945 1.1 yamaguch char str1[LACP_SYSTEMIDSTR_LEN] __LACPDEBUGUSED; 1946 1.1 yamaguch 1947 1.1 yamaguch if (lacpp->lp_aggregator == NULL) 1948 1.1 yamaguch return; 1949 1.1 yamaguch 1950 1.1 yamaguch lacp_peerinfo_partner(lacpp, &partner); 1951 1.1 yamaguch if (lacp_compare_peerinfo(peer_pi, &partner) != 0) { 1952 1.1 yamaguch LACP_PEERINFO_IDSTR(&partner, str0, sizeof(str0)); 1953 1.1 yamaguch LACP_PEERINFO_IDSTR(peer_pi, str1, sizeof(str1)); 1954 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 1955 1.1 yamaguch "different peerinfo, %s vs %s\n", str0, str1)); 1956 1.1 yamaguch goto do_unselect; 1957 1.1 yamaguch } 1958 1.1 yamaguch 1959 1.1 yamaguch if (!LACP_STATE_EQ(lacpp->lp_partner.lpi_state, 1960 1.1 yamaguch peer_pi->lpi_state, LACP_STATE_AGGREGATION)) { 1961 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 1962 1.1 yamaguch "STATE_AGGREGATION changed %d -> %d\n", 1963 1.1 yamaguch ISSET(lacpp->lp_partner.lpi_state, 1964 1.1 yamaguch LACP_STATE_AGGREGATION) != 0, 1965 1.1 yamaguch ISSET(peer_pi->lpi_state, LACP_STATE_AGGREGATION) != 0)); 1966 1.1 yamaguch goto do_unselect; 1967 1.1 yamaguch } 1968 1.1 yamaguch 1969 1.1 yamaguch return; 1970 1.1 yamaguch 1971 1.1 yamaguch do_unselect: 1972 1.1 yamaguch lacpp->lp_selected = LACP_UNSELECTED; 1973 1.1 yamaguch /* lacpp->lp_aggregator will be released at lacp_set_mux() */ 1974 1.1 yamaguch } 1975 1.1 yamaguch 1976 1.1 yamaguch static void 1977 1.1 yamaguch lacp_sm_rx_update_ntt(struct lacp_softc *lsc, struct lacp_port *lacpp, 1978 1.1 yamaguch struct lacpdu_peerinfo *my_pi) 1979 1.1 yamaguch { 1980 1.1 yamaguch struct lacpdu_peerinfo actor; 1981 1.1 yamaguch 1982 1.1 yamaguch lacp_peerinfo_actor(lsc, lacpp, &actor); 1983 1.1 yamaguch 1984 1.1 yamaguch if (lacp_compare_peerinfo(&actor, my_pi) != 0 || 1985 1.1 yamaguch !LACP_STATE_EQ(lacpp->lp_actor.lpi_state, my_pi->lpi_state, 1986 1.1 yamaguch LACP_STATE_ACTIVITY | LACP_STATE_SYNC | LACP_STATE_AGGREGATION)) { 1987 1.43 yamaguch if (ppsratecheck(&lacpp->lp_last_lacpdu, &lacpp->lp_lacpdu_sent, 1988 1.43 yamaguch (LACP_SENDDU_PPS / LACP_FAST_PERIODIC_TIME)) == 0) { 1989 1.43 yamaguch LACP_DPRINTF((lsc, lacpp, 1990 1.43 yamaguch "skip ntt due to rate limit")); 1991 1.43 yamaguch } else { 1992 1.43 yamaguch LACP_DPRINTF((lsc, lacpp, "assert ntt\n")); 1993 1.43 yamaguch lacp_sm_assert_ntt(lacpp); 1994 1.43 yamaguch } 1995 1.1 yamaguch } 1996 1.1 yamaguch } 1997 1.1 yamaguch 1998 1.1 yamaguch static void 1999 1.1 yamaguch lacp_sm_rx(struct lacp_softc *lsc, struct lacp_port *lacpp, 2000 1.1 yamaguch struct lacpdu_peerinfo *my_pi, struct lacpdu_peerinfo *peer_pi) 2001 1.1 yamaguch { 2002 1.1 yamaguch int timeout; 2003 1.1 yamaguch 2004 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2005 1.1 yamaguch 2006 1.1 yamaguch /* check LACP disabled first */ 2007 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_AGGREGATION)) 2008 1.1 yamaguch return; 2009 1.1 yamaguch 2010 1.1 yamaguch /* check loopback condition */ 2011 1.1 yamaguch if (memcmp(lsc->lsc_system_mac, peer_pi->lpi_system_mac, 2012 1.1 yamaguch LACP_MAC_LEN) == 0 && 2013 1.1 yamaguch lsc->lsc_system_prio == peer_pi->lpi_system_prio) 2014 1.1 yamaguch return; 2015 1.1 yamaguch 2016 1.1 yamaguch lacp_sm_rx_update_selected(lsc, lacpp, peer_pi); 2017 1.1 yamaguch lacp_sm_rx_update_ntt(lsc, lacpp, my_pi); 2018 1.1 yamaguch lacp_sm_rx_record_peerinfo(lsc, lacpp, my_pi, peer_pi); 2019 1.1 yamaguch 2020 1.1 yamaguch timeout = ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_TIMEOUT) ? 2021 1.1 yamaguch LACP_SHORT_TIMEOUT_TIME : LACP_LONG_TIMEOUT_TIME; 2022 1.1 yamaguch LACP_TIMER_ARM(lacpp, LACP_TIMER_CURRENT_WHILE, timeout); 2023 1.1 yamaguch 2024 1.1 yamaguch CLR(lacpp->lp_actor.lpi_state, LACP_STATE_EXPIRED); 2025 1.1 yamaguch 2026 1.1 yamaguch /* kick transmit machine without timeout. */ 2027 1.1 yamaguch lacp_sm_tx(lsc, lacpp); 2028 1.1 yamaguch } 2029 1.1 yamaguch 2030 1.1 yamaguch static void 2031 1.1 yamaguch lacp_disable_collecting(struct lacp_port *lacpp) 2032 1.1 yamaguch { 2033 1.1 yamaguch 2034 1.1 yamaguch LACP_DPRINTF((NULL, lacpp, "collecting disabled\n")); 2035 1.1 yamaguch CLR(lacpp->lp_actor.lpi_state, LACP_STATE_COLLECTING); 2036 1.1 yamaguch atomic_store_relaxed(&lacpp->lp_collector, false); 2037 1.1 yamaguch } 2038 1.1 yamaguch 2039 1.1 yamaguch static void 2040 1.1 yamaguch lacp_enable_collecting(struct lacp_port *lacpp) 2041 1.1 yamaguch { 2042 1.1 yamaguch LACP_DPRINTF((NULL, lacpp, "collecting enabled\n")); 2043 1.1 yamaguch SET(lacpp->lp_actor.lpi_state, LACP_STATE_COLLECTING); 2044 1.1 yamaguch atomic_store_relaxed(&lacpp->lp_collector, true); 2045 1.1 yamaguch } 2046 1.1 yamaguch 2047 1.1 yamaguch static void 2048 1.1 yamaguch lacp_update_portmap(struct lacp_softc *lsc) 2049 1.1 yamaguch { 2050 1.1 yamaguch struct lagg_softc *sc; 2051 1.1 yamaguch struct lacp_aggregator *la; 2052 1.1 yamaguch struct lacp_portmap *pm_act, *pm_next; 2053 1.1 yamaguch struct lacp_port *lacpp; 2054 1.1 yamaguch size_t pmap, n; 2055 1.1 yamaguch u_int link; 2056 1.1 yamaguch 2057 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2058 1.1 yamaguch 2059 1.1 yamaguch la = lsc->lsc_aggregator; 2060 1.1 yamaguch 2061 1.1 yamaguch pmap = LACP_PORTMAP_ACTIVE(lsc); 2062 1.1 yamaguch pm_act = &lsc->lsc_portmaps[pmap]; 2063 1.1 yamaguch 2064 1.1 yamaguch pmap = LACP_PORTMAP_NEXT(lsc); 2065 1.1 yamaguch pm_next = &lsc->lsc_portmaps[pmap]; 2066 1.1 yamaguch 2067 1.1 yamaguch n = 0; 2068 1.1 yamaguch if (la != NULL) { 2069 1.1 yamaguch LIST_FOREACH(lacpp, &la->la_ports, lp_entry_la) { 2070 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, 2071 1.1 yamaguch LACP_STATE_DISTRIBUTING)) { 2072 1.1 yamaguch continue; 2073 1.1 yamaguch } 2074 1.1 yamaguch 2075 1.1 yamaguch pm_next->pm_ports[n] = lacpp->lp_laggport; 2076 1.1 yamaguch n++; 2077 1.1 yamaguch 2078 1.1 yamaguch if (n >= LACP_MAX_PORTS) 2079 1.1 yamaguch break; 2080 1.1 yamaguch } 2081 1.1 yamaguch } 2082 1.1 yamaguch pm_next->pm_count = n; 2083 1.1 yamaguch 2084 1.1 yamaguch atomic_store_release(&lsc->lsc_activemap, pmap); 2085 1.1 yamaguch pserialize_perform(lsc->lsc_psz); 2086 1.1 yamaguch 2087 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "portmap count updated (%zu -> %zu)\n", 2088 1.1 yamaguch pm_act->pm_count, pm_next->pm_count)); 2089 1.1 yamaguch 2090 1.1 yamaguch link = lacp_portmap_linkstate(pm_next); 2091 1.1 yamaguch if (link != lacp_portmap_linkstate(pm_act)) { 2092 1.1 yamaguch sc = lsc->lsc_softc; 2093 1.1 yamaguch if_link_state_change(&sc->sc_if, link); 2094 1.1 yamaguch } 2095 1.1 yamaguch 2096 1.28 yamaguch lagg_workq_add(lsc->lsc_workq, &lsc->lsc_work_linkspeed); 2097 1.28 yamaguch 2098 1.1 yamaguch /* cleanup */ 2099 1.1 yamaguch pm_act->pm_count = 0; 2100 1.1 yamaguch memset(pm_act->pm_ports, 0, sizeof(pm_act->pm_ports)); 2101 1.1 yamaguch } 2102 1.1 yamaguch 2103 1.1 yamaguch static void 2104 1.1 yamaguch lacp_disable_distributing(struct lacp_softc *lsc, struct lacp_port *lacpp) 2105 1.1 yamaguch { 2106 1.1 yamaguch struct lacp_portmap *pm; 2107 1.1 yamaguch bool do_update; 2108 1.1 yamaguch size_t act, i; 2109 1.1 yamaguch int s; 2110 1.1 yamaguch 2111 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2112 1.1 yamaguch 2113 1.29 yamaguch if (ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_DISTRIBUTING)) { 2114 1.29 yamaguch LAGG_LOG(lsc->lsc_softc, LOG_INFO, 2115 1.29 yamaguch "disable distributing on %s\n", LACP_PORT_XNAME(lacpp)); 2116 1.29 yamaguch CLR(lacpp->lp_actor.lpi_state, LACP_STATE_DISTRIBUTING); 2117 1.29 yamaguch } 2118 1.1 yamaguch 2119 1.1 yamaguch s = pserialize_read_enter(); 2120 1.1 yamaguch act = LACP_PORTMAP_ACTIVE(lsc); 2121 1.1 yamaguch pm = &lsc->lsc_portmaps[act]; 2122 1.1 yamaguch 2123 1.1 yamaguch do_update = false; 2124 1.1 yamaguch for (i = 0; i < pm->pm_count; i++) { 2125 1.1 yamaguch if (pm->pm_ports[i] == lacpp->lp_laggport) { 2126 1.1 yamaguch do_update = true; 2127 1.1 yamaguch break; 2128 1.1 yamaguch } 2129 1.1 yamaguch } 2130 1.1 yamaguch pserialize_read_exit(s); 2131 1.1 yamaguch 2132 1.1 yamaguch if (do_update) 2133 1.1 yamaguch lacp_update_portmap(lsc); 2134 1.1 yamaguch } 2135 1.1 yamaguch 2136 1.1 yamaguch static void 2137 1.1 yamaguch lacp_enable_distributing(struct lacp_softc *lsc, struct lacp_port *lacpp) 2138 1.1 yamaguch { 2139 1.1 yamaguch 2140 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2141 1.1 yamaguch 2142 1.1 yamaguch KASSERT(lacp_isactive(lsc, lacpp)); 2143 1.1 yamaguch 2144 1.29 yamaguch LAGG_LOG(lsc->lsc_softc, LOG_INFO, 2145 1.29 yamaguch "enable distributing on %s\n", LACP_PORT_XNAME(lacpp)); 2146 1.1 yamaguch SET(lacpp->lp_actor.lpi_state, LACP_STATE_DISTRIBUTING); 2147 1.1 yamaguch lacp_suppress_distributing(lsc); 2148 1.1 yamaguch lacp_update_portmap(lsc); 2149 1.1 yamaguch } 2150 1.1 yamaguch 2151 1.1 yamaguch static void 2152 1.1 yamaguch lacp_select_active_aggregator(struct lacp_softc *lsc) 2153 1.1 yamaguch { 2154 1.1 yamaguch struct lacp_aggregator *la, *best_la; 2155 1.1 yamaguch char str[LACP_SYSTEMIDSTR_LEN] __LACPDEBUGUSED; 2156 1.1 yamaguch 2157 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2158 1.1 yamaguch 2159 1.1 yamaguch la = lsc->lsc_aggregator; 2160 1.1 yamaguch if (la != NULL && la->la_attached_port > 0) { 2161 1.1 yamaguch best_la = la; 2162 1.1 yamaguch } else { 2163 1.1 yamaguch best_la = NULL; 2164 1.1 yamaguch } 2165 1.1 yamaguch 2166 1.1 yamaguch TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 2167 1.1 yamaguch if (la->la_attached_port <= 0) 2168 1.1 yamaguch continue; 2169 1.1 yamaguch 2170 1.1 yamaguch if (best_la == NULL || 2171 1.1 yamaguch LACP_SYS_PRI(la) < LACP_SYS_PRI(best_la)) 2172 1.1 yamaguch best_la = la; 2173 1.1 yamaguch } 2174 1.1 yamaguch 2175 1.1 yamaguch if (best_la != lsc->lsc_aggregator) { 2176 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "active aggregator changed\n")); 2177 1.1 yamaguch 2178 1.1 yamaguch if (lsc->lsc_aggregator != NULL) { 2179 1.1 yamaguch LACP_AGGREGATOR_STR(lsc->lsc_aggregator, 2180 1.1 yamaguch str, sizeof(str)); 2181 1.1 yamaguch } else { 2182 1.1 yamaguch snprintf(str, sizeof(str), "(null)"); 2183 1.1 yamaguch } 2184 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "old aggregator=%s\n", str)); 2185 1.1 yamaguch 2186 1.1 yamaguch if (best_la != NULL) { 2187 1.1 yamaguch LACP_AGGREGATOR_STR(best_la, str, sizeof(str)); 2188 1.1 yamaguch } else { 2189 1.1 yamaguch snprintf(str, sizeof(str), "(null)"); 2190 1.1 yamaguch } 2191 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "new aggregator=%s\n", str)); 2192 1.1 yamaguch 2193 1.1 yamaguch lsc->lsc_aggregator = best_la; 2194 1.1 yamaguch } 2195 1.1 yamaguch } 2196 1.1 yamaguch 2197 1.1 yamaguch static void 2198 1.1 yamaguch lacp_port_attached(struct lacp_softc *lsc, struct lacp_port *lacpp) 2199 1.1 yamaguch { 2200 1.1 yamaguch struct lacp_aggregator *la; 2201 1.1 yamaguch 2202 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2203 1.1 yamaguch 2204 1.1 yamaguch if (ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_SYNC)) 2205 1.1 yamaguch return; 2206 1.1 yamaguch 2207 1.1 yamaguch la = lacpp->lp_aggregator; 2208 1.1 yamaguch KASSERT(la != NULL); 2209 1.1 yamaguch KASSERT(la->la_attached_port >= 0); 2210 1.1 yamaguch 2211 1.1 yamaguch SET(lacpp->lp_actor.lpi_state, LACP_STATE_SYNC); 2212 1.1 yamaguch la->la_attached_port++; 2213 1.1 yamaguch lacp_select_active_aggregator(lsc); 2214 1.1 yamaguch } 2215 1.1 yamaguch 2216 1.1 yamaguch static void 2217 1.1 yamaguch lacp_port_detached(struct lacp_softc *lsc, struct lacp_port *lacpp) 2218 1.1 yamaguch { 2219 1.1 yamaguch struct lacp_aggregator *la; 2220 1.1 yamaguch 2221 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2222 1.1 yamaguch 2223 1.1 yamaguch if (!ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_SYNC)) 2224 1.1 yamaguch return; 2225 1.1 yamaguch 2226 1.1 yamaguch la = lacpp->lp_aggregator; 2227 1.1 yamaguch KASSERT(la != NULL); 2228 1.1 yamaguch KASSERT(la->la_attached_port > 0); 2229 1.1 yamaguch 2230 1.1 yamaguch CLR(lacpp->lp_actor.lpi_state, LACP_STATE_SYNC); 2231 1.1 yamaguch la->la_attached_port--; 2232 1.1 yamaguch lacp_select_active_aggregator(lsc); 2233 1.1 yamaguch } 2234 1.1 yamaguch 2235 1.1 yamaguch static int 2236 1.1 yamaguch lacp_set_mux(struct lacp_softc *lsc, struct lacp_port *lacpp, 2237 1.1 yamaguch enum lacp_mux_state new_state) 2238 1.1 yamaguch { 2239 1.1 yamaguch struct lagg_softc *sc; 2240 1.1 yamaguch struct ifnet *ifp; 2241 1.1 yamaguch 2242 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2243 1.1 yamaguch 2244 1.1 yamaguch sc = lacpp->lp_laggport->lp_softc; 2245 1.1 yamaguch ifp = &sc->sc_if; 2246 1.1 yamaguch 2247 1.17 yamaguch if (lacpp->lp_mux_state == new_state) 2248 1.1 yamaguch return -1; 2249 1.1 yamaguch 2250 1.1 yamaguch switch (new_state) { 2251 1.1 yamaguch case LACP_MUX_DETACHED: 2252 1.1 yamaguch lacp_port_detached(lsc, lacpp); 2253 1.1 yamaguch lacp_disable_distributing(lsc, lacpp); 2254 1.1 yamaguch lacp_disable_collecting(lacpp); 2255 1.1 yamaguch lacp_sm_assert_ntt(lacpp); 2256 1.1 yamaguch /* cancel timer */ 2257 1.1 yamaguch if (LACP_TIMER_ISARMED(lacpp, LACP_TIMER_WAIT_WHILE)) { 2258 1.1 yamaguch KASSERT(lacpp->lp_pending > 0); 2259 1.1 yamaguch lacpp->lp_pending--; 2260 1.1 yamaguch LACP_TIMER_DISARM(lacpp, LACP_TIMER_WAIT_WHILE); 2261 1.1 yamaguch } 2262 1.1 yamaguch lacp_unselect(lsc, lacpp); 2263 1.1 yamaguch break; 2264 1.1 yamaguch case LACP_MUX_WAITING: 2265 1.1 yamaguch LACP_TIMER_ARM(lacpp, LACP_TIMER_WAIT_WHILE, 2266 1.1 yamaguch LACP_AGGREGATE_WAIT_TIME); 2267 1.1 yamaguch lacpp->lp_pending++; 2268 1.1 yamaguch break; 2269 1.7 yamaguch case LACP_MUX_STANDBY: 2270 1.8 yamaguch #ifdef LACP_STANDBY_SYNCED 2271 1.8 yamaguch lacp_port_attached(lsc, lacpp); 2272 1.8 yamaguch lacp_disable_collecting(lacpp); 2273 1.8 yamaguch lacp_sm_assert_ntt(lacpp); 2274 1.8 yamaguch #endif 2275 1.8 yamaguch break; 2276 1.1 yamaguch case LACP_MUX_ATTACHED: 2277 1.1 yamaguch lacp_port_attached(lsc, lacpp); 2278 1.1 yamaguch lacp_disable_collecting(lacpp); 2279 1.1 yamaguch lacp_sm_assert_ntt(lacpp); 2280 1.1 yamaguch break; 2281 1.1 yamaguch case LACP_MUX_COLLECTING: 2282 1.1 yamaguch lacp_enable_collecting(lacpp); 2283 1.1 yamaguch lacp_disable_distributing(lsc, lacpp); 2284 1.1 yamaguch lacp_sm_assert_ntt(lacpp); 2285 1.1 yamaguch break; 2286 1.1 yamaguch case LACP_MUX_DISTRIBUTING: 2287 1.1 yamaguch lacp_enable_distributing(lsc, lacpp); 2288 1.1 yamaguch break; 2289 1.1 yamaguch case LACP_MUX_INIT: 2290 1.1 yamaguch default: 2291 1.1 yamaguch panic("%s: unknown state", ifp->if_xname); 2292 1.1 yamaguch } 2293 1.1 yamaguch 2294 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "mux_state %d -> %d\n", 2295 1.1 yamaguch lacpp->lp_mux_state, new_state)); 2296 1.1 yamaguch 2297 1.1 yamaguch lacpp->lp_mux_state = new_state; 2298 1.1 yamaguch return 0; 2299 1.1 yamaguch } 2300 1.1 yamaguch 2301 1.1 yamaguch static void 2302 1.1 yamaguch lacp_sm_mux(struct lacp_softc *lsc, struct lacp_port *lacpp) 2303 1.1 yamaguch { 2304 1.2 hannken struct lacp_aggregator *la __diagused; 2305 1.1 yamaguch enum lacp_mux_state next_state; 2306 1.1 yamaguch enum lacp_selected selected; 2307 1.1 yamaguch bool p_sync, p_collecting; 2308 1.1 yamaguch 2309 1.1 yamaguch p_sync = ISSET(lacpp->lp_partner.lpi_state, LACP_STATE_SYNC); 2310 1.1 yamaguch p_collecting = ISSET(lacpp->lp_partner.lpi_state, 2311 1.1 yamaguch LACP_STATE_COLLECTING); 2312 1.1 yamaguch 2313 1.1 yamaguch do { 2314 1.1 yamaguch next_state = lacpp->lp_mux_state; 2315 1.1 yamaguch la = lacpp->lp_aggregator; 2316 1.1 yamaguch selected = lacpp->lp_selected; 2317 1.1 yamaguch KASSERT(la != NULL || 2318 1.1 yamaguch lacpp->lp_mux_state == LACP_MUX_DETACHED); 2319 1.1 yamaguch 2320 1.1 yamaguch switch (lacpp->lp_mux_state) { 2321 1.1 yamaguch case LACP_MUX_DETACHED: 2322 1.1 yamaguch if (selected != LACP_UNSELECTED) 2323 1.1 yamaguch next_state = LACP_MUX_WAITING; 2324 1.1 yamaguch break; 2325 1.1 yamaguch case LACP_MUX_WAITING: 2326 1.1 yamaguch KASSERTMSG((lacpp->lp_pending > 0 || 2327 1.1 yamaguch !LACP_TIMER_ISARMED(lacpp, LACP_TIMER_WAIT_WHILE)), 2328 1.1 yamaguch "lp_pending=%d, timer=%d", lacpp->lp_pending, 2329 1.1 yamaguch !LACP_TIMER_ISARMED(lacpp, LACP_TIMER_WAIT_WHILE)); 2330 1.1 yamaguch 2331 1.7 yamaguch if (selected == LACP_UNSELECTED) { 2332 1.7 yamaguch next_state = LACP_MUX_DETACHED; 2333 1.7 yamaguch } else if (lacpp->lp_pending == 0) { 2334 1.7 yamaguch if (selected == LACP_SELECTED) { 2335 1.7 yamaguch next_state = LACP_MUX_ATTACHED; 2336 1.7 yamaguch } else if (selected == LACP_STANDBY) { 2337 1.7 yamaguch next_state = LACP_MUX_STANDBY; 2338 1.7 yamaguch } else { 2339 1.7 yamaguch next_state = LACP_MUX_DETACHED; 2340 1.7 yamaguch } 2341 1.7 yamaguch } 2342 1.7 yamaguch break; 2343 1.7 yamaguch case LACP_MUX_STANDBY: 2344 1.7 yamaguch if (selected == LACP_SELECTED) { 2345 1.1 yamaguch next_state = LACP_MUX_ATTACHED; 2346 1.7 yamaguch } else if (selected != LACP_STANDBY) { 2347 1.1 yamaguch next_state = LACP_MUX_DETACHED; 2348 1.1 yamaguch } 2349 1.1 yamaguch break; 2350 1.1 yamaguch case LACP_MUX_ATTACHED: 2351 1.1 yamaguch if (selected != LACP_SELECTED) { 2352 1.31 yamaguch if (selected == LACP_STANDBY) 2353 1.31 yamaguch LAGG_LOG(lsc->lsc_softc, LOG_INFO, 2354 1.31 yamaguch "detaching %s\n", 2355 1.31 yamaguch LACP_PORT_XNAME(lacpp)); 2356 1.1 yamaguch next_state = LACP_MUX_DETACHED; 2357 1.1 yamaguch } else if (lacp_isactive(lsc, lacpp) && p_sync) { 2358 1.1 yamaguch next_state = LACP_MUX_COLLECTING; 2359 1.1 yamaguch } 2360 1.1 yamaguch break; 2361 1.1 yamaguch case LACP_MUX_COLLECTING: 2362 1.1 yamaguch if (selected != LACP_SELECTED || 2363 1.1 yamaguch !lacp_isactive(lsc, lacpp) 2364 1.1 yamaguch || !p_sync) { 2365 1.1 yamaguch next_state = LACP_MUX_ATTACHED; 2366 1.1 yamaguch } else if (p_collecting) { 2367 1.1 yamaguch next_state = LACP_MUX_DISTRIBUTING; 2368 1.1 yamaguch } 2369 1.1 yamaguch break; 2370 1.1 yamaguch case LACP_MUX_DISTRIBUTING: 2371 1.1 yamaguch if (selected != LACP_SELECTED || 2372 1.1 yamaguch !lacp_isactive(lsc, lacpp) 2373 1.1 yamaguch || !p_sync || !p_collecting) { 2374 1.1 yamaguch next_state = LACP_MUX_COLLECTING; 2375 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 2376 1.1 yamaguch "Interface stopped DISTRIBUTING," 2377 1.1 yamaguch " possible flapping\n")); 2378 1.1 yamaguch } 2379 1.1 yamaguch break; 2380 1.1 yamaguch case LACP_MUX_INIT: 2381 1.1 yamaguch default: 2382 1.1 yamaguch panic("%s: unknown state", 2383 1.1 yamaguch lsc->lsc_softc->sc_if.if_xname); 2384 1.1 yamaguch } 2385 1.1 yamaguch } while (lacp_set_mux(lsc, lacpp, next_state) == 0); 2386 1.1 yamaguch } 2387 1.1 yamaguch 2388 1.1 yamaguch static bool 2389 1.1 yamaguch lacp_aggregator_is_match(struct lacp_aggregator_systemid *a, 2390 1.1 yamaguch struct lacp_aggregator_systemid *b) 2391 1.1 yamaguch { 2392 1.1 yamaguch 2393 1.1 yamaguch if (a->sid_prio != b->sid_prio) 2394 1.1 yamaguch return false; 2395 1.1 yamaguch 2396 1.1 yamaguch if (a->sid_key != b->sid_key) 2397 1.1 yamaguch return false; 2398 1.1 yamaguch 2399 1.1 yamaguch if (memcmp(a->sid_mac, b->sid_mac, sizeof(a->sid_mac)) != 0) 2400 1.1 yamaguch return false; 2401 1.1 yamaguch 2402 1.1 yamaguch return true; 2403 1.1 yamaguch } 2404 1.1 yamaguch 2405 1.1 yamaguch static void 2406 1.1 yamaguch lacp_selected_update(struct lacp_softc *lsc, struct lacp_aggregator *la) 2407 1.1 yamaguch { 2408 1.1 yamaguch struct lacp_port *lacpp; 2409 1.29 yamaguch enum lacp_selected next_selected; 2410 1.29 yamaguch const char *msg; 2411 1.1 yamaguch size_t nselected; 2412 1.28 yamaguch uint64_t linkspeed; 2413 1.1 yamaguch 2414 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2415 1.1 yamaguch 2416 1.1 yamaguch lacpp = LIST_FIRST(&la->la_ports); 2417 1.1 yamaguch if (lacpp == NULL) 2418 1.1 yamaguch return; 2419 1.1 yamaguch 2420 1.28 yamaguch linkspeed = lacpp->lp_linkspeed; 2421 1.1 yamaguch nselected = 0; 2422 1.1 yamaguch LIST_FOREACH(lacpp, &la->la_ports, lp_entry_la) { 2423 1.29 yamaguch if (lacpp->lp_selected == LACP_UNSELECTED) 2424 1.29 yamaguch continue; 2425 1.29 yamaguch 2426 1.29 yamaguch next_selected = LACP_SELECTED; 2427 1.29 yamaguch msg = " is selected"; 2428 1.29 yamaguch 2429 1.29 yamaguch if (nselected >= lsc->lsc_max_ports) { 2430 1.29 yamaguch next_selected = LACP_STANDBY; 2431 1.29 yamaguch msg = " is standby because of too many active ports"; 2432 1.29 yamaguch } 2433 1.29 yamaguch 2434 1.29 yamaguch if (!lsc->lsc_multi_linkspeed && 2435 1.29 yamaguch linkspeed != lacpp->lp_linkspeed) { 2436 1.29 yamaguch next_selected = LACP_STANDBY; 2437 1.29 yamaguch msg = " is standby because of link speed mismatch"; 2438 1.1 yamaguch } 2439 1.1 yamaguch 2440 1.29 yamaguch if (lacpp->lp_selected != next_selected) { 2441 1.29 yamaguch lacpp->lp_selected = next_selected; 2442 1.29 yamaguch LAGG_LOG(lsc->lsc_softc, LOG_INFO, 2443 1.29 yamaguch "%s%s\n", LACP_PORT_XNAME(lacpp), msg); 2444 1.29 yamaguch } 2445 1.29 yamaguch 2446 1.29 yamaguch if (lacpp->lp_selected == LACP_SELECTED) 2447 1.1 yamaguch nselected++; 2448 1.1 yamaguch } 2449 1.1 yamaguch } 2450 1.1 yamaguch 2451 1.1 yamaguch static void 2452 1.1 yamaguch lacp_select(struct lacp_softc *lsc, struct lacp_port *lacpp) 2453 1.1 yamaguch { 2454 1.1 yamaguch struct lacp_aggregator *la; 2455 1.1 yamaguch struct lacp_aggregator_systemid *sid; 2456 1.1 yamaguch struct lacp_port *lacpp0; 2457 1.1 yamaguch char buf[LACP_SYSTEMIDSTR_LEN] __LACPDEBUGUSED; 2458 1.1 yamaguch 2459 1.1 yamaguch if (lacpp->lp_aggregator != NULL) 2460 1.1 yamaguch return; 2461 1.1 yamaguch 2462 1.1 yamaguch /* If we haven't heard from our peer, skip this step. */ 2463 1.1 yamaguch if (ISSET(lacpp->lp_actor.lpi_state, LACP_STATE_DEFAULTED)) 2464 1.1 yamaguch return 2465 1.1 yamaguch 2466 1.1 yamaguch KASSERT(!LACP_TIMER_ISARMED(lacpp, LACP_TIMER_WAIT_WHILE)); 2467 1.1 yamaguch 2468 1.1 yamaguch sid = &lacpp->lp_aggregator_sidbuf; 2469 1.1 yamaguch 2470 1.1 yamaguch TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 2471 1.1 yamaguch if (lacp_aggregator_is_match(&la->la_sid, sid)) 2472 1.1 yamaguch break; 2473 1.1 yamaguch } 2474 1.1 yamaguch 2475 1.1 yamaguch if (la == NULL) { 2476 1.1 yamaguch la = kmem_zalloc(sizeof(*la), KM_NOSLEEP); 2477 1.1 yamaguch if (la == NULL) { 2478 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, 2479 1.1 yamaguch "couldn't allocate aggregator\n")); 2480 1.1 yamaguch /* will retry the next tick. */ 2481 1.1 yamaguch return; 2482 1.1 yamaguch } 2483 1.1 yamaguch LIST_INIT(&la->la_ports); 2484 1.1 yamaguch 2485 1.1 yamaguch la->la_sid = *sid; 2486 1.1 yamaguch TAILQ_INSERT_TAIL(&lsc->lsc_aggregators, la, la_q); 2487 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "a new aggregator created\n")); 2488 1.1 yamaguch } else { 2489 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "aggregator found\n")); 2490 1.1 yamaguch } 2491 1.1 yamaguch 2492 1.1 yamaguch KASSERT(la != NULL); 2493 1.1 yamaguch LACP_AGGREGATOR_STR(la, buf, sizeof(buf)); 2494 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "aggregator lagid=%s\n", buf)); 2495 1.1 yamaguch 2496 1.1 yamaguch lacpp->lp_aggregator = la; 2497 1.30 yamaguch lacpp->lp_selected = LACP_READY; 2498 1.1 yamaguch 2499 1.1 yamaguch LIST_FOREACH(lacpp0, &la->la_ports, lp_entry_la) { 2500 1.17 yamaguch if (lacp_port_priority_max(lacpp0, lacpp) == lacpp) { 2501 1.17 yamaguch LIST_INSERT_BEFORE(lacpp0, lacpp, lp_entry_la); 2502 1.1 yamaguch break; 2503 1.17 yamaguch } 2504 1.1 yamaguch 2505 1.1 yamaguch if (LIST_NEXT(lacpp0, lp_entry_la) == NULL) { 2506 1.17 yamaguch LIST_INSERT_AFTER(lacpp0, lacpp, lp_entry_la); 2507 1.1 yamaguch break; 2508 1.1 yamaguch } 2509 1.1 yamaguch } 2510 1.1 yamaguch 2511 1.17 yamaguch if (lacpp0 == NULL) 2512 1.1 yamaguch LIST_INSERT_HEAD(&la->la_ports, lacpp, lp_entry_la); 2513 1.1 yamaguch 2514 1.1 yamaguch lacp_selected_update(lsc, la); 2515 1.1 yamaguch } 2516 1.1 yamaguch 2517 1.1 yamaguch static void 2518 1.1 yamaguch lacp_unselect(struct lacp_softc *lsc, struct lacp_port *lacpp) 2519 1.1 yamaguch { 2520 1.1 yamaguch struct lacp_aggregator *la; 2521 1.1 yamaguch char buf[LACP_SYSTEMIDSTR_LEN] __LACPDEBUGUSED; 2522 1.1 yamaguch bool remove_actaggr; 2523 1.1 yamaguch 2524 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2525 1.1 yamaguch KASSERT(!LACP_TIMER_ISARMED(lacpp, LACP_TIMER_WAIT_WHILE)); 2526 1.1 yamaguch 2527 1.1 yamaguch la = lacpp->lp_aggregator; 2528 1.1 yamaguch lacpp->lp_selected = LACP_UNSELECTED; 2529 1.1 yamaguch 2530 1.1 yamaguch if (la == NULL) 2531 1.1 yamaguch return; 2532 1.1 yamaguch 2533 1.1 yamaguch KASSERT(!LIST_EMPTY(&la->la_ports)); 2534 1.1 yamaguch 2535 1.1 yamaguch LACP_AGGREGATOR_STR(la, buf, sizeof(buf)); 2536 1.1 yamaguch LACP_DPRINTF((lsc, lacpp, "unselect aggregator lagid=%s\n", buf)); 2537 1.1 yamaguch 2538 1.1 yamaguch LIST_REMOVE(lacpp, lp_entry_la); 2539 1.1 yamaguch lacpp->lp_aggregator = NULL; 2540 1.1 yamaguch 2541 1.1 yamaguch if (LIST_EMPTY(&la->la_ports)) { 2542 1.3 yamaguch remove_actaggr = false; 2543 1.3 yamaguch 2544 1.1 yamaguch if (la == lsc->lsc_aggregator) { 2545 1.1 yamaguch LACP_DPRINTF((lsc, NULL, "remove active aggregator\n")); 2546 1.1 yamaguch lsc->lsc_aggregator = NULL; 2547 1.1 yamaguch remove_actaggr = true; 2548 1.1 yamaguch } 2549 1.3 yamaguch 2550 1.1 yamaguch TAILQ_REMOVE(&lsc->lsc_aggregators, la, la_q); 2551 1.1 yamaguch kmem_free(la, sizeof(*la)); 2552 1.3 yamaguch 2553 1.17 yamaguch if (remove_actaggr) 2554 1.1 yamaguch lacp_select_active_aggregator(lsc); 2555 1.1 yamaguch } else { 2556 1.1 yamaguch lacp_selected_update(lsc, la); 2557 1.1 yamaguch } 2558 1.1 yamaguch } 2559 1.1 yamaguch 2560 1.1 yamaguch static void 2561 1.1 yamaguch lacp_suppress_distributing(struct lacp_softc *lsc) 2562 1.1 yamaguch { 2563 1.1 yamaguch struct lacp_aggregator *la; 2564 1.1 yamaguch struct lacp_port *lacpp; 2565 1.42 yamaguch bool marker_scheduled; 2566 1.1 yamaguch 2567 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2568 1.1 yamaguch 2569 1.1 yamaguch la = lsc->lsc_aggregator; 2570 1.42 yamaguch marker_scheduled = false; 2571 1.1 yamaguch 2572 1.1 yamaguch LIST_FOREACH(lacpp, &la->la_ports, lp_entry_la) { 2573 1.1 yamaguch if (ISSET(lacpp->lp_actor.lpi_state, 2574 1.1 yamaguch LACP_STATE_DISTRIBUTING)) { 2575 1.1 yamaguch lagg_workq_add(lsc->lsc_workq, 2576 1.1 yamaguch &lacpp->lp_work_marker); 2577 1.42 yamaguch marker_scheduled = true; 2578 1.1 yamaguch } 2579 1.1 yamaguch } 2580 1.1 yamaguch 2581 1.42 yamaguch lsc->lsc_suppress_distributing = marker_scheduled; 2582 1.1 yamaguch LACP_PTIMER_ARM(lsc, LACP_PTIMER_DISTRIBUTING, 2583 1.1 yamaguch LACP_TRANSIT_DELAY); 2584 1.1 yamaguch } 2585 1.1 yamaguch 2586 1.1 yamaguch static void 2587 1.1 yamaguch lacp_distributing_timer(struct lacp_softc *lsc) 2588 1.1 yamaguch { 2589 1.1 yamaguch 2590 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2591 1.1 yamaguch 2592 1.1 yamaguch if (lsc->lsc_suppress_distributing) { 2593 1.1 yamaguch LACP_DPRINTF((lsc, NULL, 2594 1.1 yamaguch "disable suppress distributing\n")); 2595 1.1 yamaguch lsc->lsc_suppress_distributing = false; 2596 1.1 yamaguch } 2597 1.1 yamaguch } 2598 1.1 yamaguch 2599 1.1 yamaguch static struct mbuf * 2600 1.1 yamaguch lacp_markerdu_mbuf(struct lacp_softc *lsc, struct lacp_port *lacpp) 2601 1.1 yamaguch { 2602 1.1 yamaguch struct ifnet *ifp_port; 2603 1.1 yamaguch struct mbuf *m; 2604 1.1 yamaguch struct markerdu *mdu; 2605 1.1 yamaguch struct markerdu_info *mi; 2606 1.1 yamaguch 2607 1.1 yamaguch KASSERT(LACP_LOCKED(lsc)); 2608 1.1 yamaguch 2609 1.1 yamaguch ifp_port = lacpp->lp_laggport->lp_ifp; 2610 1.1 yamaguch 2611 1.1 yamaguch MGETHDR(m, M_DONTWAIT, MT_DATA); 2612 1.1 yamaguch if (m == NULL) { 2613 1.1 yamaguch lsc->lsc_mgethdr_failed.ev_count++; 2614 1.1 yamaguch return NULL; 2615 1.1 yamaguch } 2616 1.1 yamaguch 2617 1.1 yamaguch m->m_pkthdr.len = m->m_len = sizeof(*mdu); 2618 1.24 yamaguch m_reset_rcvif(m); 2619 1.1 yamaguch 2620 1.1 yamaguch mdu = mtod(m, struct markerdu *); 2621 1.1 yamaguch 2622 1.1 yamaguch memset(mdu, 0, sizeof(*mdu)); 2623 1.1 yamaguch 2624 1.1 yamaguch m->m_flags |= M_MCAST; 2625 1.1 yamaguch memcpy(mdu->mdu_eh.ether_dhost, ethermulticastaddr_slowprotocols, 2626 1.1 yamaguch ETHER_ADDR_LEN); 2627 1.1 yamaguch memcpy(mdu->mdu_eh.ether_shost, CLLADDR(ifp_port->if_sadl), 2628 1.1 yamaguch ETHER_ADDR_LEN); 2629 1.1 yamaguch mdu->mdu_eh.ether_type = ntohs(ETHERTYPE_SLOWPROTOCOLS); 2630 1.1 yamaguch mdu->mdu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_MARKER; 2631 1.1 yamaguch mdu->mdu_sph.sph_version = 1; 2632 1.1 yamaguch 2633 1.1 yamaguch mi = &mdu->mdu_info; 2634 1.1 yamaguch tlv_set(&mdu->mdu_tlv_info, MARKER_TYPE_INFO, 2635 1.1 yamaguch sizeof(*mi)); 2636 1.1 yamaguch mi->mi_rq_port = lacpp->lp_actor.lpi_portno; 2637 1.1 yamaguch mi->mi_rq_xid = htonl(lacpp->lp_marker_xid); 2638 1.1 yamaguch memcpy(mi->mi_rq_system, lsc->lsc_system_mac, LACP_MAC_LEN); 2639 1.1 yamaguch 2640 1.1 yamaguch mdu->mdu_tlv_term.tlv_type = MARKER_TYPE_TERMINATE; 2641 1.1 yamaguch mdu->mdu_tlv_term.tlv_length = 0; 2642 1.1 yamaguch 2643 1.1 yamaguch return m; 2644 1.1 yamaguch } 2645 1.1 yamaguch 2646 1.1 yamaguch static void 2647 1.1 yamaguch lacp_marker_work(struct lagg_work *lw, void *xlsc) 2648 1.1 yamaguch { 2649 1.1 yamaguch struct lacp_softc *lsc; 2650 1.1 yamaguch struct lacp_port *lacpp; 2651 1.1 yamaguch struct lagg_port *lp; 2652 1.1 yamaguch struct markerdu *mdu; 2653 1.1 yamaguch struct mbuf *m; 2654 1.1 yamaguch struct psref psref; 2655 1.1 yamaguch int bound; 2656 1.1 yamaguch 2657 1.1 yamaguch lsc = xlsc; 2658 1.1 yamaguch lacpp = container_of(lw, struct lacp_port, lp_work_marker); 2659 1.1 yamaguch 2660 1.1 yamaguch LACP_LOCK(lsc); 2661 1.1 yamaguch lacpp->lp_marker_xid++; 2662 1.1 yamaguch m = lacp_markerdu_mbuf(lsc, lacpp); 2663 1.1 yamaguch if (m == NULL) { 2664 1.1 yamaguch LACP_UNLOCK(lsc); 2665 1.1 yamaguch return; 2666 1.1 yamaguch } 2667 1.1 yamaguch SET(lacpp->lp_flags, LACP_PORT_MARK); 2668 1.1 yamaguch lp = lacpp->lp_laggport; 2669 1.1 yamaguch bound = curlwp_bind(); 2670 1.1 yamaguch lagg_port_getref(lp, &psref); 2671 1.1 yamaguch LACP_UNLOCK(lsc); 2672 1.1 yamaguch 2673 1.1 yamaguch if (LACP_ISDUMPING(lsc)) { 2674 1.1 yamaguch lacp_dprintf(lsc, lacpp, "markerdu transmit\n"); 2675 1.1 yamaguch mdu = mtod(m, struct markerdu *); 2676 1.1 yamaguch lacp_dump_markertlv(&mdu->mdu_info, NULL); 2677 1.1 yamaguch } 2678 1.1 yamaguch 2679 1.1 yamaguch lagg_port_xmit(lp, m); 2680 1.1 yamaguch lagg_port_putref(lp, &psref); 2681 1.1 yamaguch curlwp_bindx(bound); 2682 1.1 yamaguch } 2683 1.1 yamaguch 2684 1.1 yamaguch static void 2685 1.1 yamaguch lacp_dump_lacpdutlv(const struct lacpdu_peerinfo *pi_actor, 2686 1.1 yamaguch const struct lacpdu_peerinfo *pi_partner, 2687 1.1 yamaguch const struct lacpdu_collectorinfo *lci) 2688 1.1 yamaguch { 2689 1.1 yamaguch char str[LACP_STATESTR_LEN]; 2690 1.1 yamaguch 2691 1.1 yamaguch if (pi_actor != NULL) { 2692 1.1 yamaguch lacp_peerinfo_idstr(pi_actor, str, sizeof(str)); 2693 1.1 yamaguch printf("actor=%s\n", str); 2694 1.1 yamaguch lacp_state_str(pi_actor->lpi_state, 2695 1.1 yamaguch str, sizeof(str)); 2696 1.1 yamaguch printf("actor.state=%s portno=%d portprio=0x%04x\n", 2697 1.1 yamaguch str, 2698 1.1 yamaguch ntohs(pi_actor->lpi_port_no), 2699 1.13 rillig ntohs(pi_actor->lpi_port_prio)); 2700 1.1 yamaguch } else { 2701 1.1 yamaguch printf("no actor info\n"); 2702 1.1 yamaguch } 2703 1.1 yamaguch 2704 1.1 yamaguch if (pi_partner != NULL) { 2705 1.1 yamaguch lacp_peerinfo_idstr(pi_partner, str, sizeof(str)); 2706 1.1 yamaguch printf("partner=%s\n", str); 2707 1.1 yamaguch lacp_state_str(pi_partner->lpi_state, 2708 1.1 yamaguch str, sizeof(str)); 2709 1.1 yamaguch printf("partner.state=%s portno=%d portprio=0x%04x\n", 2710 1.1 yamaguch str, 2711 1.1 yamaguch ntohs(pi_partner->lpi_port_no), 2712 1.1 yamaguch ntohs(pi_partner->lpi_port_prio)); 2713 1.1 yamaguch } else { 2714 1.1 yamaguch printf("no partner info\n"); 2715 1.1 yamaguch } 2716 1.1 yamaguch 2717 1.1 yamaguch if (lci != NULL) { 2718 1.1 yamaguch printf("maxdelay=%d\n", ntohs(lci->lci_maxdelay)); 2719 1.1 yamaguch } else { 2720 1.1 yamaguch printf("no collector info\n"); 2721 1.1 yamaguch } 2722 1.1 yamaguch } 2723 1.1 yamaguch 2724 1.1 yamaguch static void 2725 1.1 yamaguch lacp_dump_markertlv(const struct markerdu_info *mi_info, 2726 1.1 yamaguch const struct markerdu_info *mi_res) 2727 1.1 yamaguch { 2728 1.1 yamaguch 2729 1.1 yamaguch if (mi_info != NULL) { 2730 1.1 yamaguch printf("marker info: port=%d, sys=%s, id=%u\n", 2731 1.1 yamaguch ntohs(mi_info->mi_rq_port), 2732 1.1 yamaguch ether_sprintf(mi_info->mi_rq_system), 2733 1.1 yamaguch ntohl(mi_info->mi_rq_xid)); 2734 1.1 yamaguch } 2735 1.1 yamaguch 2736 1.1 yamaguch if (mi_res != NULL) { 2737 1.1 yamaguch printf("marker resp: port=%d, sys=%s, id=%u\n", 2738 1.1 yamaguch ntohs(mi_res->mi_rq_port), 2739 1.1 yamaguch ether_sprintf(mi_res->mi_rq_system), 2740 1.1 yamaguch ntohl(mi_res->mi_rq_xid)); 2741 1.1 yamaguch } 2742 1.1 yamaguch } 2743 1.1 yamaguch 2744 1.37 yamaguch /* 2745 1.37 yamaguch * lacp_linkstate: 2746 1.37 yamaguch * callback on link state changed. 2747 1.37 yamaguch * enable, disable or reset LACP processing on the physical port. 2748 1.37 yamaguch */ 2749 1.37 yamaguch 2750 1.28 yamaguch static void 2751 1.28 yamaguch lacp_linkstate(struct lagg_proto_softc *xlsc, struct lagg_port *lp) 2752 1.1 yamaguch { 2753 1.1 yamaguch 2754 1.28 yamaguch IFNET_ASSERT_UNLOCKED(lp->lp_ifp); 2755 1.1 yamaguch 2756 1.28 yamaguch IFNET_LOCK(lp->lp_ifp); 2757 1.28 yamaguch lacp_linkstate_ifnet_locked(xlsc, lp); 2758 1.28 yamaguch IFNET_UNLOCK(lp->lp_ifp); 2759 1.1 yamaguch } 2760 1.12 yamaguch 2761 1.12 yamaguch static void 2762 1.28 yamaguch lacp_linkspeed_work(struct lagg_work *lw __unused, void *xlsc) 2763 1.12 yamaguch { 2764 1.28 yamaguch struct lacp_softc *lsc = (struct lacp_softc *)xlsc; 2765 1.28 yamaguch struct lagg_softc *sc = lsc->lsc_softc; 2766 1.28 yamaguch struct lacp_portmap *pm; 2767 1.28 yamaguch struct lagg_port *lp; 2768 1.28 yamaguch struct lacp_port *lacpp; 2769 1.28 yamaguch uint64_t linkspeed; 2770 1.28 yamaguch size_t act, i; 2771 1.28 yamaguch 2772 1.28 yamaguch linkspeed = 0; 2773 1.12 yamaguch 2774 1.28 yamaguch LACP_LOCK(lsc); 2775 1.28 yamaguch act = LACP_PORTMAP_ACTIVE(lsc); 2776 1.28 yamaguch pm = &lsc->lsc_portmaps[act]; 2777 1.28 yamaguch for (i = 0; i < pm->pm_count; i++) { 2778 1.28 yamaguch lp = pm->pm_ports[i]; 2779 1.28 yamaguch lacpp = lp->lp_proto_ctx; 2780 1.28 yamaguch linkspeed = MAX(linkspeed, lacpp->lp_linkspeed); 2781 1.28 yamaguch } 2782 1.28 yamaguch LACP_UNLOCK(lsc); 2783 1.12 yamaguch 2784 1.28 yamaguch LAGG_LOCK(sc); 2785 1.28 yamaguch lagg_set_linkspeed(sc, linkspeed); 2786 1.28 yamaguch LAGG_UNLOCK(sc); 2787 1.12 yamaguch } 2788