1 1.13 yamaguch /* $NetBSD: ieee8023ad_lacp.c,v 1.13 2021/11/30 01:17:02 yamaguchi Exp $ */ 2 1.1 yamt 3 1.1 yamt /*- 4 1.1 yamt * Copyright (c)2005 YAMAMOTO Takashi, 5 1.1 yamt * All rights reserved. 6 1.1 yamt * 7 1.1 yamt * Redistribution and use in source and binary forms, with or without 8 1.1 yamt * modification, are permitted provided that the following conditions 9 1.1 yamt * are met: 10 1.1 yamt * 1. Redistributions of source code must retain the above copyright 11 1.1 yamt * notice, this list of conditions and the following disclaimer. 12 1.1 yamt * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 yamt * notice, this list of conditions and the following disclaimer in the 14 1.1 yamt * documentation and/or other materials provided with the distribution. 15 1.1 yamt * 16 1.1 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 yamt * SUCH DAMAGE. 27 1.1 yamt */ 28 1.1 yamt 29 1.1 yamt #include <sys/cdefs.h> 30 1.13 yamaguch __KERNEL_RCSID(0, "$NetBSD: ieee8023ad_lacp.c,v 1.13 2021/11/30 01:17:02 yamaguchi Exp $"); 31 1.1 yamt 32 1.1 yamt #include <sys/param.h> 33 1.2 yamt #include <sys/callout.h> 34 1.1 yamt #include <sys/mbuf.h> 35 1.1 yamt #include <sys/systm.h> 36 1.1 yamt #include <sys/malloc.h> 37 1.1 yamt #include <sys/kernel.h> /* hz */ 38 1.1 yamt 39 1.1 yamt #include <net/if.h> 40 1.1 yamt #include <net/if_dl.h> 41 1.1 yamt #include <net/if_ether.h> 42 1.1 yamt #include <net/if_media.h> 43 1.13 yamaguch #include <net/ether_slowprotocols.h> 44 1.1 yamt 45 1.1 yamt #include <net/agr/if_agrvar_impl.h> 46 1.1 yamt #include <net/agr/if_agrsubr.h> 47 1.1 yamt #include <net/agr/ieee8023_tlv.h> 48 1.1 yamt #include <net/agr/ieee8023ad.h> 49 1.1 yamt #include <net/agr/ieee8023ad_lacp.h> 50 1.1 yamt #include <net/agr/ieee8023ad_lacp_impl.h> 51 1.1 yamt #include <net/agr/ieee8023ad_impl.h> 52 1.1 yamt #include <net/agr/ieee8023ad_lacp_sm.h> 53 1.1 yamt #include <net/agr/ieee8023ad_lacp_debug.h> 54 1.1 yamt 55 1.1 yamt static void lacp_fill_actorinfo(struct agr_port *, struct lacp_peerinfo *); 56 1.1 yamt 57 1.1 yamt static uint64_t lacp_aggregator_bandwidth(struct lacp_aggregator *); 58 1.1 yamt static void lacp_suppress_distributing(struct lacp_softc *, 59 1.1 yamt struct lacp_aggregator *); 60 1.1 yamt static void lacp_transit_expire(void *); 61 1.1 yamt static void lacp_select_active_aggregator(struct lacp_softc *); 62 1.1 yamt static uint16_t lacp_compose_key(struct lacp_port *); 63 1.1 yamt 64 1.1 yamt /* 65 1.1 yamt * actor system priority and port priority. 66 1.1 yamt * XXX should be configurable. 67 1.1 yamt */ 68 1.1 yamt 69 1.1 yamt #define LACP_SYSTEM_PRIO 0x8000 70 1.1 yamt #define LACP_PORT_PRIO 0x8000 71 1.1 yamt 72 1.1 yamt static const struct tlv_template lacp_info_tlv_template[] = { 73 1.1 yamt { LACP_TYPE_ACTORINFO, 74 1.1 yamt sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) }, 75 1.1 yamt { LACP_TYPE_PARTNERINFO, 76 1.1 yamt sizeof(struct tlvhdr) + sizeof(struct lacp_peerinfo) }, 77 1.1 yamt { LACP_TYPE_COLLECTORINFO, 78 1.1 yamt sizeof(struct tlvhdr) + sizeof(struct lacp_collectorinfo) }, 79 1.1 yamt { 0, 0 }, 80 1.1 yamt }; 81 1.1 yamt 82 1.1 yamt /* 83 1.1 yamt * ieee8023ad_lacp_input: process lacpdu 84 1.1 yamt * 85 1.1 yamt * => called from ether_input. (ie. at IPL_NET) 86 1.1 yamt * 87 1.1 yamt * XXX is it better to defer processing to lower IPL? 88 1.1 yamt * XXX anyway input rate should be very low... 89 1.1 yamt */ 90 1.1 yamt 91 1.1 yamt int 92 1.1 yamt ieee8023ad_lacp_input(struct ifnet *ifp, struct mbuf *m) 93 1.1 yamt { 94 1.1 yamt struct lacpdu *du; 95 1.1 yamt struct agr_softc *sc; 96 1.1 yamt struct agr_port *port; 97 1.1 yamt struct lacp_port *lp; 98 1.1 yamt int error = 0; 99 1.1 yamt 100 1.12 yamaguch port = ifp->if_lagg; /* XXX race with agr_remport. */ 101 1.1 yamt if (__predict_false(port->port_flags & AGRPORT_DETACHING)) { 102 1.1 yamt goto bad; 103 1.1 yamt } 104 1.9 darran 105 1.1 yamt sc = AGR_SC_FROM_PORT(port); 106 1.1 yamt KASSERT(port); 107 1.1 yamt 108 1.9 darran /* running static config? */ 109 1.9 darran if (AGR_STATIC(sc)) { 110 1.9 darran /* static config, no lacp */ 111 1.9 darran goto bad; 112 1.9 darran } 113 1.9 darran 114 1.9 darran 115 1.1 yamt if (m->m_pkthdr.len != sizeof(*du)) { 116 1.1 yamt goto bad; 117 1.1 yamt } 118 1.1 yamt 119 1.1 yamt if ((m->m_flags & M_MCAST) == 0) { 120 1.1 yamt goto bad; 121 1.1 yamt } 122 1.1 yamt 123 1.1 yamt if (m->m_len < sizeof(*du)) { 124 1.1 yamt m = m_pullup(m, sizeof(*du)); 125 1.1 yamt if (m == NULL) { 126 1.1 yamt return ENOMEM; 127 1.1 yamt } 128 1.1 yamt } 129 1.1 yamt 130 1.1 yamt du = mtod(m, struct lacpdu *); 131 1.1 yamt 132 1.1 yamt if (memcmp(&du->ldu_eh.ether_dhost, 133 1.1 yamt ðermulticastaddr_slowprotocols, ETHER_ADDR_LEN)) { 134 1.1 yamt goto bad; 135 1.1 yamt } 136 1.1 yamt 137 1.1 yamt KASSERT(du->ldu_sph.sph_subtype == SLOWPROTOCOLS_SUBTYPE_LACP); 138 1.1 yamt 139 1.1 yamt /* 140 1.1 yamt * ignore the version for compatibility with 141 1.1 yamt * the future protocol revisions. 142 1.1 yamt */ 143 1.1 yamt 144 1.1 yamt #if 0 145 1.1 yamt if (du->ldu_sph.sph_version != 1) { 146 1.1 yamt goto bad; 147 1.1 yamt } 148 1.1 yamt #endif 149 1.1 yamt 150 1.1 yamt /* 151 1.1 yamt * ignore tlv types for compatibility with 152 1.1 yamt * the future protocol revisions. 153 1.1 yamt */ 154 1.1 yamt 155 1.1 yamt if (tlv_check(du, sizeof(*du), &du->ldu_tlv_actor, 156 1.5 thorpej lacp_info_tlv_template, false)) { 157 1.1 yamt goto bad; 158 1.1 yamt } 159 1.1 yamt 160 1.6 yamt AGR_LOCK(sc); 161 1.1 yamt lp = LACP_PORT(port); 162 1.1 yamt 163 1.1 yamt #if defined(LACP_DEBUG) 164 1.1 yamt if (lacpdebug) { 165 1.1 yamt LACP_DPRINTF((lp, "lacpdu receive\n")); 166 1.1 yamt lacp_dump_lacpdu(du); 167 1.1 yamt } 168 1.1 yamt #endif /* defined(LACP_DEBUG) */ 169 1.1 yamt lacp_sm_rx(lp, du); 170 1.1 yamt 171 1.6 yamt AGR_UNLOCK(sc); 172 1.1 yamt 173 1.1 yamt m_freem(m); 174 1.1 yamt 175 1.1 yamt return error; 176 1.1 yamt 177 1.1 yamt bad: 178 1.1 yamt m_freem(m); 179 1.1 yamt return EINVAL; 180 1.1 yamt } 181 1.1 yamt 182 1.1 yamt static void 183 1.1 yamt lacp_fill_actorinfo(struct agr_port *port, struct lacp_peerinfo *info) 184 1.1 yamt { 185 1.1 yamt struct lacp_port *lp = LACP_PORT(port); 186 1.1 yamt 187 1.1 yamt info->lip_systemid.lsi_prio = htobe16(LACP_SYSTEM_PRIO); 188 1.1 yamt memcpy(&info->lip_systemid.lsi_mac, 189 1.8 dyoung CLLADDR(port->port_ifp->if_sadl), ETHER_ADDR_LEN); 190 1.1 yamt info->lip_portid.lpi_prio = htobe16(LACP_PORT_PRIO); 191 1.1 yamt info->lip_portid.lpi_portno = htobe16(port->port_ifp->if_index); 192 1.1 yamt info->lip_state = lp->lp_state; 193 1.1 yamt } 194 1.1 yamt 195 1.1 yamt int 196 1.1 yamt lacp_xmit_lacpdu(struct lacp_port *lp) 197 1.1 yamt { 198 1.1 yamt struct agr_port *port = lp->lp_agrport; 199 1.1 yamt struct mbuf *m; 200 1.1 yamt struct lacpdu *du; 201 1.1 yamt int error; 202 1.1 yamt 203 1.9 darran /* running static config? */ 204 1.9 darran if (AGR_STATIC(AGR_SC_FROM_PORT(port))) { 205 1.9 darran /* static config, no lacp transmit */ 206 1.9 darran return 0; 207 1.9 darran } 208 1.9 darran 209 1.1 yamt KDASSERT(MHLEN >= sizeof(*du)); 210 1.1 yamt 211 1.1 yamt m = m_gethdr(M_DONTWAIT, MT_DATA); 212 1.1 yamt if (m == NULL) { 213 1.1 yamt return ENOMEM; 214 1.1 yamt } 215 1.1 yamt m->m_len = m->m_pkthdr.len = sizeof(*du); 216 1.1 yamt 217 1.1 yamt du = mtod(m, struct lacpdu *); 218 1.1 yamt memset(du, 0, sizeof(*du)); 219 1.1 yamt 220 1.1 yamt memcpy(&du->ldu_eh.ether_dhost, ethermulticastaddr_slowprotocols, 221 1.1 yamt ETHER_ADDR_LEN); 222 1.1 yamt memcpy(&du->ldu_eh.ether_shost, &port->port_origlladdr, ETHER_ADDR_LEN); 223 1.1 yamt du->ldu_eh.ether_type = htobe16(ETHERTYPE_SLOWPROTOCOLS); 224 1.1 yamt 225 1.1 yamt du->ldu_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_LACP; 226 1.1 yamt du->ldu_sph.sph_version = 1; 227 1.1 yamt 228 1.1 yamt TLV_SET(&du->ldu_tlv_actor, LACP_TYPE_ACTORINFO, sizeof(du->ldu_actor)); 229 1.1 yamt du->ldu_actor = lp->lp_actor; 230 1.1 yamt 231 1.1 yamt TLV_SET(&du->ldu_tlv_partner, LACP_TYPE_PARTNERINFO, 232 1.1 yamt sizeof(du->ldu_partner)); 233 1.1 yamt du->ldu_partner = lp->lp_partner; 234 1.1 yamt 235 1.1 yamt TLV_SET(&du->ldu_tlv_collector, LACP_TYPE_COLLECTORINFO, 236 1.1 yamt sizeof(du->ldu_collector)); 237 1.1 yamt du->ldu_collector.lci_maxdelay = 0; 238 1.1 yamt 239 1.1 yamt #if defined(LACP_DEBUG) 240 1.1 yamt if (lacpdebug) { 241 1.1 yamt LACP_DPRINTF((lp, "lacpdu transmit\n")); 242 1.1 yamt lacp_dump_lacpdu(du); 243 1.1 yamt } 244 1.1 yamt #endif /* defined(LACP_DEBUG) */ 245 1.1 yamt 246 1.1 yamt m->m_flags |= M_MCAST; 247 1.1 yamt 248 1.1 yamt /* 249 1.1 yamt * XXX should use higher priority queue. 250 1.1 yamt * otherwise network congestion can break aggregation. 251 1.1 yamt */ 252 1.1 yamt 253 1.1 yamt error = agr_xmit_frame(port->port_ifp, m); 254 1.1 yamt return error; 255 1.1 yamt } 256 1.1 yamt 257 1.1 yamt void 258 1.1 yamt ieee8023ad_lacp_portstate(struct agr_port *port) 259 1.1 yamt { 260 1.1 yamt struct lacp_port *lp = LACP_PORT(port); 261 1.1 yamt u_int media = port->port_media; 262 1.1 yamt uint8_t old_state; 263 1.1 yamt uint16_t old_key; 264 1.1 yamt 265 1.1 yamt AGR_ASSERT_LOCKED(AGR_SC_FROM_PORT(port)); 266 1.1 yamt 267 1.1 yamt LACP_DPRINTF((lp, "media changed 0x%x -> 0x%x\n", lp->lp_media, media)); 268 1.1 yamt 269 1.1 yamt old_state = lp->lp_state; 270 1.1 yamt old_key = lp->lp_key; 271 1.1 yamt 272 1.1 yamt lp->lp_media = media; 273 1.1 yamt if ((media & IFM_HDX) != 0) { 274 1.1 yamt lp->lp_state &= ~LACP_STATE_AGGREGATION; 275 1.1 yamt } else { 276 1.1 yamt lp->lp_state |= LACP_STATE_AGGREGATION; 277 1.1 yamt } 278 1.1 yamt lp->lp_key = lacp_compose_key(lp); 279 1.1 yamt 280 1.1 yamt if (old_state != lp->lp_state || old_key != lp->lp_key) { 281 1.1 yamt LACP_DPRINTF((lp, "-> UNSELECTED\n")); 282 1.1 yamt lp->lp_selected = LACP_UNSELECTED; 283 1.1 yamt } 284 1.1 yamt } 285 1.1 yamt 286 1.1 yamt void 287 1.1 yamt ieee8023ad_lacp_porttick(struct agr_softc *sc, struct agr_port *port) 288 1.1 yamt { 289 1.1 yamt struct lacp_port *lp = LACP_PORT(port); 290 1.1 yamt 291 1.1 yamt AGR_ASSERT_LOCKED(sc); 292 1.1 yamt 293 1.1 yamt lacp_run_timers(lp); 294 1.1 yamt 295 1.1 yamt lacp_select(lp); 296 1.1 yamt lacp_sm_mux(lp); 297 1.1 yamt lacp_sm_tx(lp); 298 1.1 yamt lacp_sm_ptx_tx_schedule(lp); 299 1.1 yamt } 300 1.1 yamt 301 1.1 yamt void 302 1.1 yamt lacp_portinit(struct agr_port *port) 303 1.1 yamt { 304 1.1 yamt struct lacp_port *lp = LACP_PORT(port); 305 1.5 thorpej bool active = true; /* XXX should be configurable */ 306 1.5 thorpej bool fast = false; /* XXX should be configurable */ 307 1.1 yamt 308 1.1 yamt lp->lp_agrport = port; 309 1.1 yamt lacp_fill_actorinfo(port, &lp->lp_actor); 310 1.1 yamt lp->lp_state = 311 1.1 yamt (active ? LACP_STATE_ACTIVITY : 0) | 312 1.1 yamt (fast ? LACP_STATE_TIMEOUT : 0); 313 1.1 yamt lp->lp_aggregator = NULL; 314 1.1 yamt lp->lp_media = port->port_media; /* XXX */ 315 1.1 yamt lp->lp_key = lacp_compose_key(lp); 316 1.1 yamt lacp_sm_rx_set_expired(lp); 317 1.1 yamt } 318 1.1 yamt 319 1.1 yamt void 320 1.1 yamt lacp_portfini(struct agr_port *port) 321 1.1 yamt { 322 1.1 yamt struct lacp_port *lp = LACP_PORT(port); 323 1.1 yamt struct lacp_aggregator *la = lp->lp_aggregator; 324 1.1 yamt int i; 325 1.1 yamt 326 1.1 yamt LACP_DPRINTF((lp, "portfini\n")); 327 1.1 yamt 328 1.1 yamt for (i = 0; i < LACP_NTIMER; i++) { 329 1.1 yamt LACP_TIMER_DISARM(lp, i); 330 1.1 yamt } 331 1.1 yamt 332 1.1 yamt if (la == NULL) { 333 1.1 yamt return; 334 1.1 yamt } 335 1.1 yamt 336 1.1 yamt lacp_disable_distributing(lp); 337 1.1 yamt lacp_unselect(lp); 338 1.1 yamt } 339 1.1 yamt 340 1.1 yamt /* -------------------- */ 341 1.1 yamt void 342 1.1 yamt lacp_disable_collecting(struct lacp_port *lp) 343 1.1 yamt { 344 1.1 yamt struct agr_port *port = lp->lp_agrport; 345 1.1 yamt 346 1.1 yamt lp->lp_state &= ~LACP_STATE_COLLECTING; 347 1.1 yamt port->port_flags &= ~AGRPORT_COLLECTING; 348 1.1 yamt } 349 1.1 yamt 350 1.1 yamt void 351 1.1 yamt lacp_enable_collecting(struct lacp_port *lp) 352 1.1 yamt { 353 1.1 yamt struct agr_port *port = lp->lp_agrport; 354 1.1 yamt 355 1.1 yamt lp->lp_state |= LACP_STATE_COLLECTING; 356 1.1 yamt port->port_flags |= AGRPORT_COLLECTING; 357 1.1 yamt } 358 1.1 yamt 359 1.1 yamt void 360 1.1 yamt lacp_disable_distributing(struct lacp_port *lp) 361 1.1 yamt { 362 1.1 yamt struct agr_port *port = lp->lp_agrport; 363 1.1 yamt struct lacp_aggregator *la = lp->lp_aggregator; 364 1.1 yamt struct lacp_softc *lsc = LACP_SOFTC(AGR_SC_FROM_PORT(port)); 365 1.1 yamt #if defined(LACP_DEBUG) 366 1.1 yamt char buf[LACP_LAGIDSTR_MAX+1]; 367 1.1 yamt #endif /* defined(LACP_DEBUG) */ 368 1.1 yamt 369 1.1 yamt if ((lp->lp_state & LACP_STATE_DISTRIBUTING) == 0) { 370 1.1 yamt return; 371 1.1 yamt } 372 1.1 yamt 373 1.1 yamt KASSERT(la); 374 1.1 yamt KASSERT(!TAILQ_EMPTY(&la->la_ports)); 375 1.1 yamt KASSERT(la->la_nports > 0); 376 1.1 yamt KASSERT(la->la_refcnt >= la->la_nports); 377 1.1 yamt 378 1.1 yamt LACP_DPRINTF((lp, "disable distributing on aggregator %s, " 379 1.1 yamt "nports %d -> %d\n", 380 1.1 yamt lacp_format_lagid_aggregator(la, buf, sizeof(buf)), 381 1.1 yamt la->la_nports, la->la_nports - 1)); 382 1.1 yamt 383 1.1 yamt TAILQ_REMOVE(&la->la_ports, lp, lp_dist_q); 384 1.1 yamt la->la_nports--; 385 1.1 yamt 386 1.1 yamt lacp_suppress_distributing(lsc, la); 387 1.1 yamt 388 1.1 yamt lp->lp_state &= ~LACP_STATE_DISTRIBUTING; 389 1.1 yamt port->port_flags &= ~AGRPORT_DISTRIBUTING; 390 1.1 yamt 391 1.1 yamt if (lsc->lsc_active_aggregator == la) { 392 1.1 yamt lacp_select_active_aggregator(lsc); 393 1.1 yamt } 394 1.1 yamt } 395 1.1 yamt 396 1.1 yamt void 397 1.1 yamt lacp_enable_distributing(struct lacp_port *lp) 398 1.1 yamt { 399 1.1 yamt struct agr_port *port = lp->lp_agrport; 400 1.1 yamt struct lacp_aggregator *la = lp->lp_aggregator; 401 1.1 yamt struct lacp_softc *lsc = LACP_SOFTC(AGR_SC_FROM_PORT(port)); 402 1.1 yamt #if defined(LACP_DEBUG) 403 1.1 yamt char buf[LACP_LAGIDSTR_MAX+1]; 404 1.1 yamt #endif /* defined(LACP_DEBUG) */ 405 1.1 yamt 406 1.1 yamt if ((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0) { 407 1.1 yamt return; 408 1.1 yamt } 409 1.1 yamt 410 1.1 yamt KASSERT(la); 411 1.1 yamt 412 1.1 yamt LACP_DPRINTF((lp, "enable distributing on aggregator %s, " 413 1.1 yamt "nports %d -> %d\n", 414 1.1 yamt lacp_format_lagid_aggregator(la, buf, sizeof(buf)), 415 1.1 yamt la->la_nports, la->la_nports + 1)); 416 1.1 yamt 417 1.1 yamt KASSERT(la->la_refcnt > la->la_nports); 418 1.1 yamt TAILQ_INSERT_HEAD(&la->la_ports, lp, lp_dist_q); 419 1.1 yamt la->la_nports++; 420 1.1 yamt 421 1.1 yamt lacp_suppress_distributing(lsc, la); 422 1.1 yamt 423 1.1 yamt lp->lp_state |= LACP_STATE_DISTRIBUTING; 424 1.1 yamt port->port_flags |= AGRPORT_DISTRIBUTING; 425 1.1 yamt 426 1.1 yamt if (lsc->lsc_active_aggregator != la) { 427 1.1 yamt lacp_select_active_aggregator(lsc); 428 1.1 yamt } 429 1.1 yamt } 430 1.1 yamt 431 1.1 yamt static void 432 1.1 yamt lacp_transit_expire(void *vp) 433 1.1 yamt { 434 1.1 yamt struct agr_softc *sc = vp; 435 1.1 yamt struct lacp_softc *lsc = LACP_SOFTC(sc); 436 1.1 yamt 437 1.6 yamt AGR_LOCK(sc); 438 1.1 yamt LACP_DPRINTF((NULL, "%s\n", __func__)); 439 1.5 thorpej lsc->lsc_suppress_distributing = false; 440 1.6 yamt AGR_UNLOCK(sc); 441 1.1 yamt } 442 1.1 yamt 443 1.1 yamt /* -------------------- */ 444 1.1 yamt /* XXX */ 445 1.1 yamt void 446 1.1 yamt ieee8023ad_portinit(struct agr_port *port) 447 1.1 yamt { 448 1.1 yamt struct ieee8023ad_port *iport = IEEE8023AD_PORT(port); 449 1.1 yamt 450 1.10 joerg memset(iport, 0, sizeof(*iport)); 451 1.1 yamt 452 1.1 yamt lacp_portinit(port); 453 1.1 yamt } 454 1.1 yamt 455 1.1 yamt void 456 1.1 yamt ieee8023ad_portfini(struct agr_port *port) 457 1.1 yamt { 458 1.1 yamt struct agr_softc *sc = AGR_SC_FROM_PORT(port); 459 1.1 yamt 460 1.6 yamt AGR_LOCK(sc); 461 1.1 yamt 462 1.1 yamt lacp_portfini(port); 463 1.1 yamt 464 1.6 yamt AGR_UNLOCK(sc); 465 1.1 yamt } 466 1.1 yamt 467 1.1 yamt void 468 1.1 yamt ieee8023ad_ctor(struct agr_softc *sc) 469 1.1 yamt { 470 1.1 yamt struct ieee8023ad_softc *isc = IEEE8023AD_SOFTC(sc); 471 1.1 yamt struct lacp_softc *lsc = &isc->isc_lacpsc; 472 1.1 yamt 473 1.1 yamt lsc->lsc_active_aggregator = NULL; 474 1.1 yamt TAILQ_INIT(&lsc->lsc_aggregators); 475 1.7 ad callout_init(&lsc->lsc_transit_callout, 0); 476 1.1 yamt callout_setfunc(&lsc->lsc_transit_callout, lacp_transit_expire, sc); 477 1.1 yamt } 478 1.1 yamt 479 1.1 yamt void 480 1.1 yamt ieee8023ad_dtor(struct agr_softc *sc) 481 1.1 yamt { 482 1.1 yamt struct ieee8023ad_softc *isc = IEEE8023AD_SOFTC(sc); 483 1.1 yamt struct lacp_softc *lsc = &isc->isc_lacpsc; 484 1.1 yamt 485 1.1 yamt LACP_DPRINTF((NULL, "%s\n", __func__)); 486 1.1 yamt 487 1.1 yamt callout_stop(&lsc->lsc_transit_callout); 488 1.1 yamt KASSERT(TAILQ_EMPTY(&lsc->lsc_aggregators)); 489 1.1 yamt KASSERT(lsc->lsc_active_aggregator == NULL); 490 1.1 yamt } 491 1.1 yamt 492 1.1 yamt /* -------------------- */ 493 1.1 yamt 494 1.1 yamt struct agr_port * 495 1.1 yamt ieee8023ad_select_tx_port(struct agr_softc *sc, struct mbuf *m) 496 1.1 yamt { 497 1.1 yamt const struct lacp_softc *lsc = LACP_SOFTC(sc); 498 1.1 yamt const struct lacp_aggregator *la; 499 1.1 yamt const struct lacp_port *lp; 500 1.1 yamt uint32_t hash; 501 1.1 yamt int nports; 502 1.1 yamt 503 1.1 yamt if (__predict_false(lsc->lsc_suppress_distributing && 504 1.1 yamt !AGR_ROUNDROBIN(sc))) { 505 1.1 yamt LACP_DPRINTF((NULL, "%s: waiting transit\n", __func__)); 506 1.11 thorpej if_statinc(&sc->sc_if, if_collisions); /* XXX abuse */ 507 1.1 yamt return NULL; 508 1.1 yamt } 509 1.1 yamt 510 1.1 yamt la = lsc->lsc_active_aggregator; 511 1.1 yamt if (__predict_false(la == NULL)) { 512 1.1 yamt LACP_DPRINTF((NULL, "%s: no active aggregator\n", __func__)); 513 1.1 yamt return NULL; 514 1.1 yamt } 515 1.1 yamt 516 1.1 yamt nports = la->la_nports; 517 1.1 yamt KASSERT(nports > 0); 518 1.1 yamt 519 1.1 yamt if (AGR_ROUNDROBIN(sc)) { 520 1.1 yamt /* packet ordering rule violation */ 521 1.1 yamt hash = sc->sc_rr_counter++; 522 1.1 yamt } else { 523 1.1 yamt hash = (*sc->sc_iftop->iftop_hashmbuf)(sc, m); 524 1.1 yamt } 525 1.1 yamt hash %= nports; 526 1.1 yamt lp = TAILQ_FIRST(&la->la_ports); 527 1.1 yamt KASSERT(lp != NULL); 528 1.1 yamt while (hash--) { 529 1.1 yamt lp = TAILQ_NEXT(lp, lp_dist_q); 530 1.1 yamt KASSERT(lp != NULL); 531 1.1 yamt } 532 1.1 yamt 533 1.1 yamt KASSERT((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0); 534 1.1 yamt 535 1.1 yamt return lp->lp_agrport; 536 1.1 yamt } 537 1.1 yamt 538 1.1 yamt /* 539 1.1 yamt * lacp_suppress_distributing: drop transmit packets for a while 540 1.1 yamt * to preserve packet ordering. 541 1.1 yamt */ 542 1.1 yamt 543 1.1 yamt static void 544 1.1 yamt lacp_suppress_distributing(struct lacp_softc *lsc, struct lacp_aggregator *la) 545 1.1 yamt { 546 1.1 yamt 547 1.1 yamt if (lsc->lsc_active_aggregator != la) { 548 1.1 yamt return; 549 1.1 yamt } 550 1.1 yamt 551 1.1 yamt LACP_DPRINTF((NULL, "%s\n", __func__)); 552 1.5 thorpej lsc->lsc_suppress_distributing = true; 553 1.1 yamt /* XXX should consider collector max delay */ 554 1.1 yamt callout_schedule(&lsc->lsc_transit_callout, 555 1.1 yamt LACP_TRANSIT_DELAY * hz / 1000); 556 1.1 yamt } 557 1.1 yamt 558 1.1 yamt /* -------------------- */ 559 1.1 yamt 560 1.1 yamt int 561 1.1 yamt lacp_compare_peerinfo(const struct lacp_peerinfo *a, 562 1.1 yamt const struct lacp_peerinfo *b) 563 1.1 yamt { 564 1.1 yamt 565 1.1 yamt return memcmp(a, b, offsetof(struct lacp_peerinfo, lip_state)); 566 1.1 yamt } 567 1.1 yamt 568 1.1 yamt int 569 1.1 yamt lacp_compare_systemid(const struct lacp_systemid *a, 570 1.1 yamt const struct lacp_systemid *b) 571 1.1 yamt { 572 1.1 yamt 573 1.1 yamt return memcmp(a, b, sizeof(*a)); 574 1.1 yamt } 575 1.1 yamt 576 1.1 yamt int 577 1.1 yamt lacp_compare_portid(const struct lacp_portid *a, 578 1.1 yamt const struct lacp_portid *b) 579 1.1 yamt { 580 1.1 yamt 581 1.1 yamt return memcmp(a, b, sizeof(*a)); 582 1.1 yamt } 583 1.1 yamt 584 1.1 yamt /* -------------------- */ 585 1.1 yamt 586 1.1 yamt static uint64_t 587 1.1 yamt lacp_aggregator_bandwidth(struct lacp_aggregator *la) 588 1.1 yamt { 589 1.1 yamt struct lacp_port *lp; 590 1.1 yamt uint64_t speed; 591 1.1 yamt 592 1.1 yamt lp = TAILQ_FIRST(&la->la_ports); 593 1.1 yamt if (lp == NULL) { 594 1.1 yamt return 0; 595 1.1 yamt } 596 1.1 yamt 597 1.1 yamt speed = ifmedia_baudrate(lp->lp_media); 598 1.1 yamt speed *= la->la_nports; 599 1.1 yamt if (speed == 0) { 600 1.1 yamt LACP_DPRINTF((lp, "speed 0? media=0x%x nports=%d\n", 601 1.1 yamt lp->lp_media, la->la_nports)); 602 1.1 yamt } 603 1.1 yamt 604 1.1 yamt return speed; 605 1.1 yamt } 606 1.1 yamt 607 1.1 yamt /* 608 1.1 yamt * lacp_select_active_aggregator: select an aggregator to be used to transmit 609 1.1 yamt * packets from agr(4) interface. 610 1.1 yamt */ 611 1.1 yamt 612 1.1 yamt static void 613 1.1 yamt lacp_select_active_aggregator(struct lacp_softc *lsc) 614 1.1 yamt { 615 1.1 yamt struct lacp_aggregator *la; 616 1.1 yamt struct lacp_aggregator *best_la = NULL; 617 1.1 yamt uint64_t best_speed = 0; 618 1.1 yamt #if defined(LACP_DEBUG) 619 1.1 yamt char buf[LACP_LAGIDSTR_MAX+1]; 620 1.1 yamt #endif /* defined(LACP_DEBUG) */ 621 1.1 yamt 622 1.1 yamt LACP_DPRINTF((NULL, "%s:\n", __func__)); 623 1.1 yamt 624 1.1 yamt TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) { 625 1.1 yamt uint64_t speed; 626 1.1 yamt 627 1.1 yamt if (la->la_nports == 0) { 628 1.1 yamt continue; 629 1.1 yamt } 630 1.1 yamt 631 1.1 yamt speed = lacp_aggregator_bandwidth(la); 632 1.1 yamt LACP_DPRINTF((NULL, "%s, speed=%" PRIu64 ", nports=%d\n", 633 1.1 yamt lacp_format_lagid_aggregator(la, buf, sizeof(buf)), 634 1.1 yamt speed, la->la_nports)); 635 1.1 yamt if (speed > best_speed || 636 1.1 yamt (speed == best_speed && 637 1.1 yamt la == lsc->lsc_active_aggregator)) { 638 1.1 yamt best_la = la; 639 1.1 yamt best_speed = speed; 640 1.1 yamt } 641 1.1 yamt } 642 1.1 yamt 643 1.1 yamt KASSERT(best_la == NULL || best_la->la_nports > 0); 644 1.1 yamt KASSERT(best_la == NULL || !TAILQ_EMPTY(&best_la->la_ports)); 645 1.1 yamt 646 1.1 yamt #if defined(LACP_DEBUG) 647 1.1 yamt if (lsc->lsc_active_aggregator != best_la) { 648 1.1 yamt LACP_DPRINTF((NULL, "active aggregator changed\n")); 649 1.1 yamt LACP_DPRINTF((NULL, "old %s\n", 650 1.1 yamt lacp_format_lagid_aggregator(lsc->lsc_active_aggregator, 651 1.1 yamt buf, sizeof(buf)))); 652 1.1 yamt } else { 653 1.1 yamt LACP_DPRINTF((NULL, "active aggregator not changed\n")); 654 1.1 yamt } 655 1.1 yamt LACP_DPRINTF((NULL, "new %s\n", 656 1.1 yamt lacp_format_lagid_aggregator(best_la, buf, sizeof(buf)))); 657 1.1 yamt #endif /* defined(LACP_DEBUG) */ 658 1.1 yamt 659 1.1 yamt if (lsc->lsc_active_aggregator != best_la) { 660 1.1 yamt lsc->lsc_active_aggregator = best_la; 661 1.1 yamt if (best_la) { 662 1.1 yamt lacp_suppress_distributing(lsc, best_la); 663 1.1 yamt } 664 1.1 yamt } 665 1.1 yamt } 666 1.1 yamt 667 1.1 yamt uint16_t 668 1.1 yamt lacp_compose_key(struct lacp_port *lp) 669 1.1 yamt { 670 1.1 yamt u_int media = lp->lp_media; 671 1.1 yamt uint16_t key; 672 1.1 yamt 673 1.1 yamt KASSERT(IFM_TYPE(media) == IFM_ETHER); 674 1.1 yamt 675 1.1 yamt if (!(lp->lp_state & LACP_STATE_AGGREGATION)) { 676 1.1 yamt 677 1.1 yamt /* 678 1.1 yamt * non-aggregatable links should have unique keys. 679 1.1 yamt * 680 1.1 yamt * XXX this isn't really unique as if_index is 16 bit. 681 1.1 yamt */ 682 1.1 yamt 683 1.1 yamt /* bit 0..14: (some bits of) if_index of this port */ 684 1.1 yamt key = lp->lp_agrport->port_ifp->if_index; 685 1.1 yamt /* bit 15: 1 */ 686 1.1 yamt key |= 0x8000; 687 1.1 yamt } else { 688 1.1 yamt u_int subtype = IFM_SUBTYPE(media); 689 1.1 yamt 690 1.1 yamt KASSERT((media & IFM_HDX) == 0); /* should be handled above */ 691 1.1 yamt KASSERT((subtype & 0x1f) == subtype); 692 1.1 yamt 693 1.1 yamt /* bit 0..4: IFM_SUBTYPE */ 694 1.1 yamt key = subtype; 695 1.1 yamt /* bit 5..14: (some bits of) if_index of agr device */ 696 1.1 yamt key |= 0x7fe0 & ((lp->lp_agrport->port_agrifp->if_index) << 5); 697 1.1 yamt /* bit 15: 0 */ 698 1.1 yamt } 699 1.1 yamt 700 1.1 yamt return htobe16(key); 701 1.1 yamt } 702