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