1 /* $OpenBSD: if_trunk.c,v 1.152 2021/08/02 21:10:55 mvs Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/kernel.h> 21 #include <sys/malloc.h> 22 #include <sys/mbuf.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/sockio.h> 26 #include <sys/systm.h> 27 #include <sys/task.h> 28 #include <sys/timeout.h> 29 30 #include <crypto/siphash.h> 31 32 #include <net/if.h> 33 #include <net/if_dl.h> 34 #include <net/if_media.h> 35 #include <net/if_types.h> 36 #include <net/route.h> 37 38 #include <netinet/in.h> 39 #include <netinet/if_ether.h> 40 #include <netinet/ip.h> 41 42 #ifdef INET6 43 #include <netinet/ip6.h> 44 #endif 45 46 #include <net/if_vlan_var.h> 47 #include <net/if_trunk.h> 48 #include <net/trunklacp.h> 49 50 #include "bpfilter.h" 51 #if NBPFILTER > 0 52 #include <net/bpf.h> 53 #endif 54 55 SLIST_HEAD(__trhead, trunk_softc) trunk_list; /* list of trunks */ 56 57 void trunkattach(int); 58 int trunk_clone_create(struct if_clone *, int); 59 int trunk_clone_destroy(struct ifnet *); 60 void trunk_lladdr(struct arpcom *, u_int8_t *); 61 int trunk_capabilities(struct trunk_softc *); 62 void trunk_port_lladdr(struct trunk_port *, u_int8_t *); 63 int trunk_port_create(struct trunk_softc *, struct ifnet *); 64 int trunk_port_destroy(struct trunk_port *); 65 void trunk_port_state(void *); 66 void trunk_port_ifdetach(void *); 67 int trunk_port_ioctl(struct ifnet *, u_long, caddr_t); 68 int trunk_port_output(struct ifnet *, struct mbuf *, struct sockaddr *, 69 struct rtentry *); 70 struct trunk_port *trunk_port_get(struct trunk_softc *, struct ifnet *); 71 int trunk_port_checkstacking(struct trunk_softc *); 72 void trunk_port2req(struct trunk_port *, struct trunk_reqport *); 73 int trunk_ioctl(struct ifnet *, u_long, caddr_t); 74 int trunk_ether_addmulti(struct trunk_softc *, struct ifreq *); 75 int trunk_ether_delmulti(struct trunk_softc *, struct ifreq *); 76 void trunk_ether_purgemulti(struct trunk_softc *); 77 int trunk_ether_cmdmulti(struct trunk_port *, u_long); 78 int trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t); 79 void trunk_input(struct ifnet *, struct mbuf *); 80 void trunk_start(struct ifnet *); 81 void trunk_init(struct ifnet *); 82 void trunk_stop(struct ifnet *); 83 int trunk_media_change(struct ifnet *); 84 void trunk_media_status(struct ifnet *, struct ifmediareq *); 85 struct trunk_port *trunk_link_active(struct trunk_softc *, 86 struct trunk_port *); 87 const void *trunk_gethdr(struct mbuf *, u_int, u_int, void *); 88 89 struct if_clone trunk_cloner = 90 IF_CLONE_INITIALIZER("trunk", trunk_clone_create, trunk_clone_destroy); 91 92 /* Simple round robin */ 93 int trunk_rr_attach(struct trunk_softc *); 94 int trunk_rr_detach(struct trunk_softc *); 95 void trunk_rr_port_destroy(struct trunk_port *); 96 int trunk_rr_start(struct trunk_softc *, struct mbuf *); 97 int trunk_rr_input(struct trunk_softc *, struct trunk_port *, 98 struct mbuf *); 99 100 /* Active failover */ 101 int trunk_fail_attach(struct trunk_softc *); 102 int trunk_fail_detach(struct trunk_softc *); 103 int trunk_fail_port_create(struct trunk_port *); 104 void trunk_fail_port_destroy(struct trunk_port *); 105 int trunk_fail_start(struct trunk_softc *, struct mbuf *); 106 int trunk_fail_input(struct trunk_softc *, struct trunk_port *, 107 struct mbuf *); 108 void trunk_fail_linkstate(struct trunk_port *); 109 110 /* Loadbalancing */ 111 int trunk_lb_attach(struct trunk_softc *); 112 int trunk_lb_detach(struct trunk_softc *); 113 int trunk_lb_port_create(struct trunk_port *); 114 void trunk_lb_port_destroy(struct trunk_port *); 115 int trunk_lb_start(struct trunk_softc *, struct mbuf *); 116 int trunk_lb_input(struct trunk_softc *, struct trunk_port *, 117 struct mbuf *); 118 int trunk_lb_porttable(struct trunk_softc *, struct trunk_port *); 119 120 /* Broadcast mode */ 121 int trunk_bcast_attach(struct trunk_softc *); 122 int trunk_bcast_detach(struct trunk_softc *); 123 int trunk_bcast_start(struct trunk_softc *, struct mbuf *); 124 int trunk_bcast_input(struct trunk_softc *, struct trunk_port *, 125 struct mbuf *); 126 127 /* 802.3ad LACP */ 128 int trunk_lacp_attach(struct trunk_softc *); 129 int trunk_lacp_detach(struct trunk_softc *); 130 int trunk_lacp_start(struct trunk_softc *, struct mbuf *); 131 int trunk_lacp_input(struct trunk_softc *, struct trunk_port *, 132 struct mbuf *); 133 134 /* Trunk protocol table */ 135 static const struct { 136 enum trunk_proto ti_proto; 137 int (*ti_attach)(struct trunk_softc *); 138 } trunk_protos[] = { 139 { TRUNK_PROTO_ROUNDROBIN, trunk_rr_attach }, 140 { TRUNK_PROTO_FAILOVER, trunk_fail_attach }, 141 { TRUNK_PROTO_LOADBALANCE, trunk_lb_attach }, 142 { TRUNK_PROTO_BROADCAST, trunk_bcast_attach }, 143 { TRUNK_PROTO_LACP, trunk_lacp_attach }, 144 { TRUNK_PROTO_NONE, NULL } 145 }; 146 147 void 148 trunkattach(int count) 149 { 150 SLIST_INIT(&trunk_list); 151 if_clone_attach(&trunk_cloner); 152 } 153 154 int 155 trunk_clone_create(struct if_clone *ifc, int unit) 156 { 157 struct trunk_softc *tr; 158 struct ifnet *ifp; 159 int i, error = 0; 160 161 tr = malloc(sizeof(*tr), M_DEVBUF, M_WAITOK|M_ZERO); 162 tr->tr_proto = TRUNK_PROTO_NONE; 163 for (i = 0; trunk_protos[i].ti_proto != TRUNK_PROTO_NONE; i++) { 164 if (trunk_protos[i].ti_proto == TRUNK_PROTO_DEFAULT) { 165 tr->tr_proto = trunk_protos[i].ti_proto; 166 if ((error = trunk_protos[i].ti_attach(tr)) != 0) { 167 free(tr, M_DEVBUF, sizeof *tr); 168 return (error); 169 } 170 break; 171 } 172 } 173 SLIST_INIT(&tr->tr_ports); 174 175 /* Initialise pseudo media types */ 176 ifmedia_init(&tr->tr_media, 0, trunk_media_change, 177 trunk_media_status); 178 ifmedia_add(&tr->tr_media, IFM_ETHER | IFM_AUTO, 0, NULL); 179 ifmedia_set(&tr->tr_media, IFM_ETHER | IFM_AUTO); 180 181 ifp = &tr->tr_ac.ac_if; 182 ifp->if_softc = tr; 183 ifp->if_start = trunk_start; 184 ifp->if_ioctl = trunk_ioctl; 185 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; 186 ifp->if_capabilities = trunk_capabilities(tr); 187 ifp->if_xflags = IFXF_CLONED; 188 189 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 190 ifc->ifc_name, unit); 191 192 /* 193 * Attach as an ordinary ethernet device, children will be attached 194 * as special device IFT_IEEE8023ADLAG. 195 */ 196 if_counters_alloc(ifp); 197 if_attach(ifp); 198 ether_ifattach(ifp); 199 200 /* Insert into the global list of trunks */ 201 SLIST_INSERT_HEAD(&trunk_list, tr, tr_entries); 202 203 return (0); 204 } 205 206 int 207 trunk_clone_destroy(struct ifnet *ifp) 208 { 209 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 210 struct trunk_port *tp; 211 int error; 212 213 /* Remove any multicast groups that we may have joined. */ 214 trunk_ether_purgemulti(tr); 215 216 /* Shutdown and remove trunk ports, return on error */ 217 NET_LOCK(); 218 while ((tp = SLIST_FIRST(&tr->tr_ports)) != NULL) { 219 if ((error = trunk_port_destroy(tp)) != 0) { 220 NET_UNLOCK(); 221 return (error); 222 } 223 } 224 NET_UNLOCK(); 225 226 ifmedia_delete_instance(&tr->tr_media, IFM_INST_ANY); 227 ether_ifdetach(ifp); 228 if_detach(ifp); 229 230 SLIST_REMOVE(&trunk_list, tr, trunk_softc, tr_entries); 231 free(tr, M_DEVBUF, sizeof *tr); 232 233 return (0); 234 } 235 236 void 237 trunk_lladdr(struct arpcom *ac, u_int8_t *lladdr) 238 { 239 struct ifnet *ifp = &ac->ac_if; 240 struct sockaddr_dl *sdl; 241 242 sdl = ifp->if_sadl; 243 sdl->sdl_type = IFT_ETHER; 244 sdl->sdl_alen = ETHER_ADDR_LEN; 245 bcopy(lladdr, LLADDR(sdl), ETHER_ADDR_LEN); 246 bcopy(lladdr, ac->ac_enaddr, ETHER_ADDR_LEN); 247 } 248 249 int 250 trunk_capabilities(struct trunk_softc *tr) 251 { 252 struct trunk_port *tp; 253 int cap = ~0, priv; 254 255 /* Preserve private capabilities */ 256 priv = tr->tr_capabilities & IFCAP_TRUNK_MASK; 257 258 /* Get capabilities from the trunk ports */ 259 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 260 cap &= tp->tp_capabilities; 261 262 if (tr->tr_ifflags & IFF_DEBUG) { 263 printf("%s: capabilities 0x%08x\n", 264 tr->tr_ifname, cap == ~0 ? priv : (cap | priv)); 265 } 266 267 return (cap == ~0 ? priv : (cap | priv)); 268 } 269 270 void 271 trunk_port_lladdr(struct trunk_port *tp, u_int8_t *lladdr) 272 { 273 struct ifnet *ifp = tp->tp_if; 274 275 /* Set the link layer address */ 276 trunk_lladdr((struct arpcom *)ifp, lladdr); 277 278 /* Reset the port to update the lladdr */ 279 ifnewlladdr(ifp); 280 } 281 282 int 283 trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp) 284 { 285 struct trunk_softc *tr_ptr; 286 struct trunk_port *tp; 287 struct arpcom *ac0; 288 int error = 0; 289 290 /* Limit the maximal number of trunk ports */ 291 if (tr->tr_count >= TRUNK_MAX_PORTS) 292 return (ENOSPC); 293 294 /* Check if port has already been associated to a trunk */ 295 if (trunk_port_get(NULL, ifp) != NULL) 296 return (EBUSY); 297 298 /* XXX Disallow non-ethernet interfaces (this should be any of 802) */ 299 if (ifp->if_type != IFT_ETHER) 300 return (EPROTONOSUPPORT); 301 302 ac0 = (struct arpcom *)ifp; 303 if (ac0->ac_trunkport != NULL) 304 return (EBUSY); 305 306 /* Take MTU from the first member port */ 307 if (SLIST_EMPTY(&tr->tr_ports)) { 308 if (tr->tr_ifflags & IFF_DEBUG) 309 printf("%s: first port, setting trunk mtu %u\n", 310 tr->tr_ifname, ifp->if_mtu); 311 tr->tr_ac.ac_if.if_mtu = ifp->if_mtu; 312 tr->tr_ac.ac_if.if_hardmtu = ifp->if_hardmtu; 313 } else if (tr->tr_ac.ac_if.if_mtu != ifp->if_mtu) { 314 printf("%s: adding %s failed, MTU %u != %u\n", tr->tr_ifname, 315 ifp->if_xname, ifp->if_mtu, tr->tr_ac.ac_if.if_mtu); 316 return (EINVAL); 317 } 318 319 if ((error = ifpromisc(ifp, 1)) != 0) 320 return (error); 321 322 if ((tp = malloc(sizeof *tp, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 323 return (ENOMEM); 324 325 /* Check if port is a stacked trunk */ 326 SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) { 327 if (ifp == &tr_ptr->tr_ac.ac_if) { 328 tp->tp_flags |= TRUNK_PORT_STACK; 329 if (trunk_port_checkstacking(tr_ptr) >= 330 TRUNK_MAX_STACKING) { 331 free(tp, M_DEVBUF, sizeof *tp); 332 return (E2BIG); 333 } 334 } 335 } 336 337 /* Change the interface type */ 338 tp->tp_iftype = ifp->if_type; 339 ifp->if_type = IFT_IEEE8023ADLAG; 340 341 tp->tp_ioctl = ifp->if_ioctl; 342 ifp->if_ioctl = trunk_port_ioctl; 343 344 tp->tp_output = ifp->if_output; 345 ifp->if_output = trunk_port_output; 346 347 tp->tp_if = ifp; 348 tp->tp_trunk = tr; 349 350 /* Save port link layer address */ 351 bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN); 352 353 if (SLIST_EMPTY(&tr->tr_ports)) { 354 tr->tr_primary = tp; 355 tp->tp_flags |= TRUNK_PORT_MASTER; 356 trunk_lladdr(&tr->tr_ac, tp->tp_lladdr); 357 } 358 359 /* Insert into the list of ports */ 360 SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries); 361 tr->tr_count++; 362 363 /* Update link layer address for this port */ 364 trunk_port_lladdr(tp, 365 ((struct arpcom *)(tr->tr_primary->tp_if))->ac_enaddr); 366 367 /* Update trunk capabilities */ 368 tr->tr_capabilities = trunk_capabilities(tr); 369 370 /* Add multicast addresses to this port */ 371 trunk_ether_cmdmulti(tp, SIOCADDMULTI); 372 373 /* Register callback for physical link state changes */ 374 task_set(&tp->tp_ltask, trunk_port_state, tp); 375 if_linkstatehook_add(ifp, &tp->tp_ltask); 376 377 /* Register callback if parent wants to unregister */ 378 task_set(&tp->tp_dtask, trunk_port_ifdetach, tp); 379 if_detachhook_add(ifp, &tp->tp_dtask); 380 381 if (tr->tr_port_create != NULL) 382 error = (*tr->tr_port_create)(tp); 383 384 /* Change input handler of the physical interface. */ 385 tp->tp_input = ifp->if_input; 386 NET_ASSERT_LOCKED(); 387 ac0->ac_trunkport = tp; 388 ifp->if_input = trunk_input; 389 390 return (error); 391 } 392 393 int 394 trunk_port_checkstacking(struct trunk_softc *tr) 395 { 396 struct trunk_softc *tr_ptr; 397 struct trunk_port *tp; 398 int m = 0; 399 400 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 401 if (tp->tp_flags & TRUNK_PORT_STACK) { 402 tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc; 403 m = MAX(m, trunk_port_checkstacking(tr_ptr)); 404 } 405 } 406 407 return (m + 1); 408 } 409 410 int 411 trunk_port_destroy(struct trunk_port *tp) 412 { 413 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 414 struct trunk_port *tp_ptr; 415 struct ifnet *ifp = tp->tp_if; 416 struct arpcom *ac0 = (struct arpcom *)ifp; 417 418 /* Restore previous input handler. */ 419 NET_ASSERT_LOCKED(); 420 ifp->if_input = tp->tp_input; 421 ac0->ac_trunkport = NULL; 422 423 /* Remove multicast addresses from this port */ 424 trunk_ether_cmdmulti(tp, SIOCDELMULTI); 425 426 ifpromisc(ifp, 0); 427 428 if (tr->tr_port_destroy != NULL) 429 (*tr->tr_port_destroy)(tp); 430 431 /* Restore interface type. */ 432 ifp->if_type = tp->tp_iftype; 433 434 ifp->if_ioctl = tp->tp_ioctl; 435 ifp->if_output = tp->tp_output; 436 437 if_detachhook_del(ifp, &tp->tp_dtask); 438 if_linkstatehook_del(ifp, &tp->tp_ltask); 439 440 /* Finally, remove the port from the trunk */ 441 SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries); 442 tr->tr_count--; 443 444 /* Update the primary interface */ 445 if (tp == tr->tr_primary) { 446 u_int8_t lladdr[ETHER_ADDR_LEN]; 447 448 if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) { 449 bzero(&lladdr, ETHER_ADDR_LEN); 450 } else { 451 bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr, 452 lladdr, ETHER_ADDR_LEN); 453 tp_ptr->tp_flags = TRUNK_PORT_MASTER; 454 } 455 trunk_lladdr(&tr->tr_ac, lladdr); 456 tr->tr_primary = tp_ptr; 457 458 /* Update link layer address for each port */ 459 SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries) 460 trunk_port_lladdr(tp_ptr, lladdr); 461 } 462 463 /* Reset the port lladdr */ 464 trunk_port_lladdr(tp, tp->tp_lladdr); 465 466 if_put(ifp); 467 free(tp, M_DEVBUF, sizeof *tp); 468 469 /* Update trunk capabilities */ 470 tr->tr_capabilities = trunk_capabilities(tr); 471 472 return (0); 473 } 474 475 int 476 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 477 { 478 struct trunk_reqport *rp = (struct trunk_reqport *)data; 479 struct trunk_softc *tr; 480 struct trunk_port *tp = NULL; 481 struct ifnet *ifp0 = NULL; 482 int error = 0; 483 484 /* Should be checked by the caller */ 485 if (ifp->if_type != IFT_IEEE8023ADLAG || 486 (tp = trunk_port_get(NULL, ifp)) == NULL || 487 (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) { 488 error = EINVAL; 489 goto fallback; 490 } 491 492 switch (cmd) { 493 case SIOCGTRUNKPORT: 494 if (rp->rp_portname[0] == '\0' || 495 (ifp0 = if_unit(rp->rp_portname)) != ifp) { 496 if_put(ifp0); 497 error = EINVAL; 498 break; 499 } 500 if_put(ifp0); 501 502 /* Search in all trunks if the global flag is set */ 503 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 504 NULL : tr, ifp)) == NULL) { 505 error = ENOENT; 506 break; 507 } 508 509 trunk_port2req(tp, rp); 510 break; 511 case SIOCSIFMTU: 512 /* Do not allow the MTU to be changed once joined */ 513 error = EINVAL; 514 break; 515 default: 516 error = ENOTTY; 517 goto fallback; 518 } 519 520 return (error); 521 522 fallback: 523 if (tp != NULL) 524 error = (*tp->tp_ioctl)(ifp, cmd, data); 525 526 return (error); 527 } 528 529 int 530 trunk_port_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 531 struct rtentry *rt) 532 { 533 /* restrict transmission on trunk members to bpf only */ 534 if (ifp->if_type == IFT_IEEE8023ADLAG && 535 (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) { 536 m_freem(m); 537 return (EBUSY); 538 } 539 540 return (ether_output(ifp, m, dst, rt)); 541 } 542 543 void 544 trunk_port_ifdetach(void *arg) 545 { 546 struct trunk_port *tp = (struct trunk_port *)arg; 547 548 trunk_port_destroy(tp); 549 } 550 551 struct trunk_port * 552 trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp) 553 { 554 struct trunk_port *tp; 555 struct trunk_softc *tr_ptr; 556 557 if (tr != NULL) { 558 /* Search port in specified trunk */ 559 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 560 if (tp->tp_if == ifp) 561 return (tp); 562 } 563 } else { 564 /* Search all trunks for the selected port */ 565 SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) { 566 SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) { 567 if (tp->tp_if == ifp) 568 return (tp); 569 } 570 } 571 } 572 573 return (NULL); 574 } 575 576 void 577 trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp) 578 { 579 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 580 581 strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname)); 582 strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname)); 583 rp->rp_prio = tp->tp_prio; 584 if (tr->tr_portreq != NULL) 585 (*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc); 586 587 /* Add protocol specific flags */ 588 switch (tr->tr_proto) { 589 case TRUNK_PROTO_FAILOVER: 590 rp->rp_flags = tp->tp_flags; 591 if (tp == trunk_link_active(tr, tr->tr_primary)) 592 rp->rp_flags |= TRUNK_PORT_ACTIVE; 593 break; 594 595 case TRUNK_PROTO_ROUNDROBIN: 596 case TRUNK_PROTO_LOADBALANCE: 597 case TRUNK_PROTO_BROADCAST: 598 rp->rp_flags = tp->tp_flags; 599 if (TRUNK_PORTACTIVE(tp)) 600 rp->rp_flags |= TRUNK_PORT_ACTIVE; 601 break; 602 603 case TRUNK_PROTO_LACP: 604 /* LACP has a different definition of active */ 605 rp->rp_flags = lacp_port_status(tp); 606 break; 607 default: 608 break; 609 } 610 } 611 612 int 613 trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 614 { 615 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 616 struct trunk_reqall *ra = (struct trunk_reqall *)data; 617 struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf; 618 struct trunk_opts *tro = (struct trunk_opts *)data; 619 struct ifreq *ifr = (struct ifreq *)data; 620 struct lacp_softc *lsc; 621 struct trunk_port *tp; 622 struct lacp_port *lp; 623 struct ifnet *tpif; 624 int i, error = 0; 625 626 bzero(&rpbuf, sizeof(rpbuf)); 627 628 switch (cmd) { 629 case SIOCGTRUNK: 630 ra->ra_proto = tr->tr_proto; 631 if (tr->tr_req != NULL) 632 (*tr->tr_req)(tr, (caddr_t)&ra->ra_psc); 633 ra->ra_ports = i = 0; 634 tp = SLIST_FIRST(&tr->tr_ports); 635 while (tp && ra->ra_size >= 636 i + sizeof(struct trunk_reqport)) { 637 trunk_port2req(tp, &rpbuf); 638 error = copyout(&rpbuf, (caddr_t)ra->ra_port + i, 639 sizeof(struct trunk_reqport)); 640 if (error) 641 break; 642 i += sizeof(struct trunk_reqport); 643 ra->ra_ports++; 644 tp = SLIST_NEXT(tp, tp_entries); 645 } 646 break; 647 case SIOCSTRUNK: 648 if ((error = suser(curproc)) != 0) { 649 error = EPERM; 650 break; 651 } 652 if (ra->ra_proto >= TRUNK_PROTO_MAX) { 653 error = EPROTONOSUPPORT; 654 break; 655 } 656 657 /* 658 * Use of ifp->if_input and ac->ac_trunkport is 659 * protected by NET_LOCK, but that may not be true 660 * in the future. The below comment and code flow is 661 * maintained to help in that future. 662 * 663 * Serialize modifications to the trunk and trunk 664 * ports via the ifih SRP: detaching trunk_input 665 * from the trunk port will require all currently 666 * running trunk_input's on this port to finish 667 * granting us an exclusive access to it. 668 */ 669 NET_ASSERT_LOCKED(); 670 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 671 /* if_ih_remove(tp->tp_if, trunk_input, tp); */ 672 tp->tp_if->if_input = tp->tp_input; 673 } 674 if (tr->tr_proto != TRUNK_PROTO_NONE) 675 error = tr->tr_detach(tr); 676 if (error != 0) 677 break; 678 for (i = 0; i < nitems(trunk_protos); i++) { 679 if (trunk_protos[i].ti_proto == ra->ra_proto) { 680 if (tr->tr_ifflags & IFF_DEBUG) 681 printf("%s: using proto %u\n", 682 tr->tr_ifname, 683 trunk_protos[i].ti_proto); 684 tr->tr_proto = trunk_protos[i].ti_proto; 685 if (tr->tr_proto != TRUNK_PROTO_NONE) 686 error = trunk_protos[i].ti_attach(tr); 687 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 688 /* if_ih_insert(tp->tp_if, 689 trunk_input, tp); */ 690 tp->tp_if->if_input = trunk_input; 691 } 692 /* Update trunk capabilities */ 693 tr->tr_capabilities = trunk_capabilities(tr); 694 goto out; 695 } 696 } 697 error = EPROTONOSUPPORT; 698 break; 699 case SIOCGTRUNKOPTS: 700 /* Only LACP trunks have options atm */ 701 if (tro->to_proto != TRUNK_PROTO_LACP) { 702 error = EPROTONOSUPPORT; 703 break; 704 } 705 lsc = LACP_SOFTC(tr); 706 tro->to_lacpopts.lacp_mode = lsc->lsc_mode; 707 tro->to_lacpopts.lacp_timeout = lsc->lsc_timeout; 708 tro->to_lacpopts.lacp_prio = lsc->lsc_sys_prio; 709 tro->to_lacpopts.lacp_portprio = lsc->lsc_port_prio; 710 tro->to_lacpopts.lacp_ifqprio = lsc->lsc_ifq_prio; 711 break; 712 case SIOCSTRUNKOPTS: 713 if ((error = suser(curproc)) != 0) { 714 error = EPERM; 715 break; 716 } 717 /* Only LACP trunks have options atm */ 718 if (tro->to_proto != TRUNK_PROTO_LACP) { 719 error = EPROTONOSUPPORT; 720 break; 721 } 722 lsc = LACP_SOFTC(tr); 723 switch(tro->to_opts) { 724 case TRUNK_OPT_LACP_MODE: 725 /* 726 * Ensure mode changes occur immediately 727 * on all ports 728 */ 729 lsc->lsc_mode = tro->to_lacpopts.lacp_mode; 730 if (lsc->lsc_mode == 0) { 731 LIST_FOREACH(lp, &lsc->lsc_ports, 732 lp_next) 733 lp->lp_state &= 734 ~LACP_STATE_ACTIVITY; 735 } else { 736 LIST_FOREACH(lp, &lsc->lsc_ports, 737 lp_next) 738 lp->lp_state |= 739 LACP_STATE_ACTIVITY; 740 } 741 break; 742 case TRUNK_OPT_LACP_TIMEOUT: 743 /* 744 * Ensure timeout changes occur immediately 745 * on all ports 746 */ 747 lsc->lsc_timeout = 748 tro->to_lacpopts.lacp_timeout; 749 if (lsc->lsc_timeout == 0) { 750 LIST_FOREACH(lp, &lsc->lsc_ports, 751 lp_next) 752 lp->lp_state &= 753 ~LACP_STATE_TIMEOUT; 754 } else { 755 LIST_FOREACH(lp, &lsc->lsc_ports, 756 lp_next) 757 lp->lp_state |= 758 LACP_STATE_TIMEOUT; 759 } 760 break; 761 case TRUNK_OPT_LACP_SYS_PRIO: 762 if (tro->to_lacpopts.lacp_prio == 0) { 763 error = EINVAL; 764 break; 765 } 766 lsc->lsc_sys_prio = tro->to_lacpopts.lacp_prio; 767 break; 768 case TRUNK_OPT_LACP_PORT_PRIO: 769 if (tro->to_lacpopts.lacp_portprio == 0) { 770 error = EINVAL; 771 break; 772 } 773 lsc->lsc_port_prio = 774 tro->to_lacpopts.lacp_portprio; 775 break; 776 case TRUNK_OPT_LACP_IFQ_PRIO: 777 if (tro->to_lacpopts.lacp_ifqprio > 778 IFQ_MAXPRIO) { 779 error = EINVAL; 780 break; 781 } 782 lsc->lsc_ifq_prio = 783 tro->to_lacpopts.lacp_ifqprio; 784 break; 785 } 786 break; 787 case SIOCGTRUNKPORT: 788 if (rp->rp_portname[0] == '\0' || 789 (tpif = if_unit(rp->rp_portname)) == NULL) { 790 error = EINVAL; 791 break; 792 } 793 794 /* Search in all trunks if the global flag is set */ 795 tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 796 NULL : tr, tpif); 797 if_put(tpif); 798 799 if(tp == NULL) { 800 error = ENOENT; 801 break; 802 } 803 804 trunk_port2req(tp, rp); 805 break; 806 case SIOCSTRUNKPORT: 807 if ((error = suser(curproc)) != 0) { 808 error = EPERM; 809 break; 810 } 811 if (rp->rp_portname[0] == '\0' || 812 (tpif = if_unit(rp->rp_portname)) == NULL) { 813 error = EINVAL; 814 break; 815 } 816 error = trunk_port_create(tr, tpif); 817 if (error != 0) 818 if_put(tpif); 819 break; 820 case SIOCSTRUNKDELPORT: 821 if ((error = suser(curproc)) != 0) { 822 error = EPERM; 823 break; 824 } 825 if (rp->rp_portname[0] == '\0' || 826 (tpif = if_unit(rp->rp_portname)) == NULL) { 827 error = EINVAL; 828 break; 829 } 830 831 /* Search in all trunks if the global flag is set */ 832 tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 833 NULL : tr, tpif); 834 if_put(tpif); 835 836 if(tp == NULL) { 837 error = ENOENT; 838 break; 839 } 840 841 error = trunk_port_destroy(tp); 842 break; 843 case SIOCSIFADDR: 844 ifp->if_flags |= IFF_UP; 845 /* FALLTHROUGH */ 846 case SIOCSIFFLAGS: 847 error = ENETRESET; 848 break; 849 case SIOCADDMULTI: 850 error = trunk_ether_addmulti(tr, ifr); 851 break; 852 case SIOCDELMULTI: 853 error = trunk_ether_delmulti(tr, ifr); 854 break; 855 case SIOCSIFMEDIA: 856 case SIOCGIFMEDIA: 857 error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd); 858 break; 859 case SIOCSIFLLADDR: 860 /* Update the port lladdrs as well */ 861 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 862 trunk_port_lladdr(tp, ifr->ifr_addr.sa_data); 863 error = ENETRESET; 864 break; 865 default: 866 error = ether_ioctl(ifp, &tr->tr_ac, cmd, data); 867 } 868 869 if (error == ENETRESET) { 870 if (ifp->if_flags & IFF_UP) { 871 if ((ifp->if_flags & IFF_RUNNING) == 0) 872 trunk_init(ifp); 873 } else { 874 if (ifp->if_flags & IFF_RUNNING) 875 trunk_stop(ifp); 876 } 877 error = 0; 878 } 879 880 out: 881 return (error); 882 } 883 884 int 885 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr) 886 { 887 struct trunk_mc *mc; 888 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 889 int error; 890 891 /* Ignore ENETRESET error code */ 892 if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET) 893 return (error); 894 895 if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) { 896 error = ENOMEM; 897 goto failed; 898 } 899 900 ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 901 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm); 902 bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len); 903 SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries); 904 905 if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI, 906 (caddr_t)ifr)) != 0) { 907 trunk_ether_delmulti(tr, ifr); 908 return (error); 909 } 910 911 return (error); 912 913 failed: 914 ether_delmulti(ifr, &tr->tr_ac); 915 916 return (error); 917 } 918 919 int 920 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr) 921 { 922 struct ether_multi *enm; 923 struct trunk_mc *mc; 924 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 925 int error; 926 927 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 928 return (error); 929 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm); 930 if (enm == NULL) 931 return (EINVAL); 932 933 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) 934 if (mc->mc_enm == enm) 935 break; 936 937 /* We won't delete entries we didn't add */ 938 if (mc == NULL) 939 return (EINVAL); 940 941 if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET) 942 return (error); 943 944 /* We no longer use this multicast address. Tell parent so. */ 945 error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 946 if (error == 0) { 947 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 948 free(mc, M_DEVBUF, sizeof(*mc)); 949 } else { 950 /* XXX At least one port failed to remove the address */ 951 if (tr->tr_ifflags & IFF_DEBUG) { 952 printf("%s: failed to remove multicast address " 953 "on all ports (%d)\n", tr->tr_ifname, error); 954 } 955 (void)ether_addmulti(ifr, &tr->tr_ac); 956 } 957 958 return (0); 959 } 960 961 void 962 trunk_ether_purgemulti(struct trunk_softc *tr) 963 { 964 struct trunk_mc *mc; 965 struct trunk_ifreq ifs; 966 struct ifreq *ifr = &ifs.ifreq.ifreq; 967 968 while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) { 969 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 970 971 /* Try to remove multicast address on all ports */ 972 trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 973 974 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 975 free(mc, M_DEVBUF, sizeof(*mc)); 976 } 977 } 978 979 int 980 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd) 981 { 982 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 983 struct trunk_mc *mc; 984 struct trunk_ifreq ifs; 985 struct ifreq *ifr = &ifs.ifreq.ifreq; 986 int ret, error = 0; 987 988 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 989 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) { 990 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 991 992 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) { 993 if (tr->tr_ifflags & IFF_DEBUG) { 994 printf("%s: ioctl %lu failed on %s: %d\n", 995 tr->tr_ifname, cmd, tp->tp_ifname, ret); 996 } 997 /* Store last known error and continue */ 998 error = ret; 999 } 1000 } 1001 1002 return (error); 1003 } 1004 1005 int 1006 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data) 1007 { 1008 struct ifreq *ifr = (struct ifreq *)data; 1009 struct trunk_port *tp; 1010 int ret, error = 0; 1011 1012 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1013 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 1014 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) { 1015 if (tr->tr_ifflags & IFF_DEBUG) { 1016 printf("%s: ioctl %lu failed on %s: %d\n", 1017 tr->tr_ifname, cmd, tp->tp_ifname, ret); 1018 } 1019 /* Store last known error and continue */ 1020 error = ret; 1021 } 1022 } 1023 1024 return (error); 1025 } 1026 1027 void 1028 trunk_start(struct ifnet *ifp) 1029 { 1030 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1031 struct mbuf *m; 1032 int error; 1033 1034 for (;;) { 1035 m = ifq_dequeue(&ifp->if_snd); 1036 if (m == NULL) 1037 break; 1038 1039 #if NBPFILTER > 0 1040 if (ifp->if_bpf) 1041 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1042 #endif 1043 1044 if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) { 1045 error = (*tr->tr_start)(tr, m); 1046 if (error != 0) 1047 ifp->if_oerrors++; 1048 } else { 1049 m_freem(m); 1050 if (tr->tr_proto != TRUNK_PROTO_NONE) 1051 ifp->if_oerrors++; 1052 } 1053 } 1054 } 1055 1056 u_int32_t 1057 trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key) 1058 { 1059 u_int16_t etype, ether_vtag; 1060 u_int32_t p = 0; 1061 u_int16_t *vlan, vlanbuf[2]; 1062 int off; 1063 struct ether_header *eh; 1064 struct ip *ip, ipbuf; 1065 #ifdef INET6 1066 u_int32_t flow; 1067 struct ip6_hdr *ip6, ip6buf; 1068 #endif 1069 SIPHASH_CTX ctx; 1070 1071 if (m->m_pkthdr.csum_flags & M_FLOWID) 1072 return (m->m_pkthdr.ph_flowid); 1073 1074 SipHash24_Init(&ctx, key); 1075 off = sizeof(*eh); 1076 if (m->m_len < off) 1077 goto done; 1078 eh = mtod(m, struct ether_header *); 1079 etype = ntohs(eh->ether_type); 1080 SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN); 1081 SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN); 1082 1083 /* Special handling for encapsulating VLAN frames */ 1084 if (m->m_flags & M_VLANTAG) { 1085 ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 1086 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1087 } else if (etype == ETHERTYPE_VLAN) { 1088 if ((vlan = (u_int16_t *) 1089 trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL) 1090 return (p); 1091 ether_vtag = EVL_VLANOFTAG(*vlan); 1092 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1093 etype = ntohs(vlan[1]); 1094 off += EVL_ENCAPLEN; 1095 } 1096 1097 switch (etype) { 1098 case ETHERTYPE_IP: 1099 if ((ip = (struct ip *) 1100 trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL) 1101 return (p); 1102 SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr)); 1103 SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr)); 1104 break; 1105 #ifdef INET6 1106 case ETHERTYPE_IPV6: 1107 if ((ip6 = (struct ip6_hdr *) 1108 trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL) 1109 return (p); 1110 SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr)); 1111 SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr)); 1112 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 1113 SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */ 1114 break; 1115 #endif 1116 } 1117 1118 done: 1119 return SipHash24_End(&ctx); 1120 } 1121 1122 void 1123 trunk_init(struct ifnet *ifp) 1124 { 1125 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1126 1127 ifp->if_flags |= IFF_RUNNING; 1128 1129 if (tr->tr_init != NULL) 1130 (*tr->tr_init)(tr); 1131 } 1132 1133 void 1134 trunk_stop(struct ifnet *ifp) 1135 { 1136 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1137 1138 ifp->if_flags &= ~IFF_RUNNING; 1139 1140 if (tr->tr_stop != NULL) 1141 (*tr->tr_stop)(tr); 1142 } 1143 1144 void 1145 trunk_input(struct ifnet *ifp, struct mbuf *m) 1146 { 1147 struct arpcom *ac0 = (struct arpcom *)ifp; 1148 struct trunk_port *tp; 1149 struct trunk_softc *tr; 1150 struct ifnet *trifp = NULL; 1151 struct ether_header *eh; 1152 1153 if (m->m_len < sizeof(*eh)) 1154 goto bad; 1155 1156 eh = mtod(m, struct ether_header *); 1157 if (ETHER_IS_MULTICAST(eh->ether_dhost)) 1158 ifp->if_imcasts++; 1159 1160 /* Should be checked by the caller */ 1161 if (ifp->if_type != IFT_IEEE8023ADLAG) 1162 goto bad; 1163 1164 tp = (struct trunk_port *)ac0->ac_trunkport; 1165 if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL) 1166 goto bad; 1167 1168 trifp = &tr->tr_ac.ac_if; 1169 if (tr->tr_proto == TRUNK_PROTO_NONE) 1170 goto bad; 1171 1172 if ((*tr->tr_input)(tr, tp, m)) { 1173 /* 1174 * We stop here if the packet has been consumed 1175 * by the protocol routine. 1176 */ 1177 return; 1178 } 1179 1180 if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1181 goto bad; 1182 1183 /* 1184 * Drop promiscuously received packets if we are not in 1185 * promiscuous mode. 1186 */ 1187 if (!ETHER_IS_MULTICAST(eh->ether_dhost) && 1188 (ifp->if_flags & IFF_PROMISC) && 1189 (trifp->if_flags & IFF_PROMISC) == 0) { 1190 if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost, 1191 ETHER_ADDR_LEN)) { 1192 m_freem(m); 1193 return; 1194 } 1195 } 1196 1197 1198 if_vinput(trifp, m); 1199 return; 1200 1201 bad: 1202 if (trifp != NULL) 1203 trifp->if_ierrors++; 1204 m_freem(m); 1205 } 1206 1207 int 1208 trunk_media_change(struct ifnet *ifp) 1209 { 1210 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1211 1212 if (tr->tr_ifflags & IFF_DEBUG) 1213 printf("%s\n", __func__); 1214 1215 /* Ignore */ 1216 return (0); 1217 } 1218 1219 void 1220 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr) 1221 { 1222 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1223 struct trunk_port *tp; 1224 1225 imr->ifm_status = IFM_AVALID; 1226 imr->ifm_active = IFM_ETHER | IFM_AUTO; 1227 1228 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1229 if (TRUNK_PORTACTIVE(tp)) 1230 imr->ifm_status |= IFM_ACTIVE; 1231 } 1232 } 1233 1234 void 1235 trunk_port_state(void *arg) 1236 { 1237 struct trunk_port *tp = (struct trunk_port *)arg; 1238 struct trunk_softc *tr = NULL; 1239 1240 if (tp != NULL) 1241 tr = (struct trunk_softc *)tp->tp_trunk; 1242 if (tr == NULL) 1243 return; 1244 if (tr->tr_linkstate != NULL) 1245 (*tr->tr_linkstate)(tp); 1246 trunk_link_active(tr, tp); 1247 } 1248 1249 struct trunk_port * 1250 trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp) 1251 { 1252 struct trunk_port *tp_next, *rval = NULL; 1253 int new_link = LINK_STATE_DOWN; 1254 1255 /* 1256 * Search a port which reports an active link state. 1257 */ 1258 1259 if (tp == NULL) 1260 goto search; 1261 if (TRUNK_PORTACTIVE(tp)) { 1262 rval = tp; 1263 goto found; 1264 } 1265 if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL && 1266 TRUNK_PORTACTIVE(tp_next)) { 1267 rval = tp_next; 1268 goto found; 1269 } 1270 1271 search: 1272 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1273 if (TRUNK_PORTACTIVE(tp_next)) { 1274 rval = tp_next; 1275 goto found; 1276 } 1277 } 1278 1279 found: 1280 if (rval != NULL) { 1281 /* 1282 * The IEEE 802.1D standard assumes that a trunk with 1283 * multiple ports is always full duplex. This is valid 1284 * for load sharing trunks and if at least two links 1285 * are active. Unfortunately, checking the latter would 1286 * be too expensive at this point. 1287 */ 1288 if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) && 1289 (tr->tr_count > 1)) 1290 new_link = LINK_STATE_FULL_DUPLEX; 1291 else 1292 new_link = rval->tp_link_state; 1293 } 1294 1295 if (tr->tr_ac.ac_if.if_link_state != new_link) { 1296 tr->tr_ac.ac_if.if_link_state = new_link; 1297 if_link_state_change(&tr->tr_ac.ac_if); 1298 } 1299 1300 return (rval); 1301 } 1302 1303 const void * 1304 trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) 1305 { 1306 if (m->m_pkthdr.len < (off + len)) 1307 return (NULL); 1308 else if (m->m_len < (off + len)) { 1309 m_copydata(m, off, len, buf); 1310 return (buf); 1311 } 1312 return (mtod(m, caddr_t) + off); 1313 } 1314 1315 /* 1316 * Simple round robin trunking 1317 */ 1318 1319 int 1320 trunk_rr_attach(struct trunk_softc *tr) 1321 { 1322 struct trunk_port *tp; 1323 1324 tr->tr_detach = trunk_rr_detach; 1325 tr->tr_start = trunk_rr_start; 1326 tr->tr_input = trunk_rr_input; 1327 tr->tr_init = NULL; 1328 tr->tr_stop = NULL; 1329 tr->tr_linkstate = NULL; 1330 tr->tr_port_create = NULL; 1331 tr->tr_port_destroy = trunk_rr_port_destroy; 1332 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1333 tr->tr_req = NULL; 1334 tr->tr_portreq = NULL; 1335 1336 tp = SLIST_FIRST(&tr->tr_ports); 1337 tr->tr_psc = (caddr_t)tp; 1338 1339 return (0); 1340 } 1341 1342 int 1343 trunk_rr_detach(struct trunk_softc *tr) 1344 { 1345 tr->tr_psc = NULL; 1346 return (0); 1347 } 1348 1349 void 1350 trunk_rr_port_destroy(struct trunk_port *tp) 1351 { 1352 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1353 1354 if (tp == (struct trunk_port *)tr->tr_psc) 1355 tr->tr_psc = NULL; 1356 } 1357 1358 int 1359 trunk_rr_start(struct trunk_softc *tr, struct mbuf *m) 1360 { 1361 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next; 1362 int error = 0; 1363 1364 if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) { 1365 m_freem(m); 1366 return (ENOENT); 1367 } 1368 1369 if ((error = if_enqueue(tp->tp_if, m)) != 0) 1370 return (error); 1371 1372 /* Get next active port */ 1373 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1374 tr->tr_psc = (caddr_t)tp_next; 1375 1376 return (0); 1377 } 1378 1379 int 1380 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1381 { 1382 /* Just pass in the packet to our trunk device */ 1383 return (0); 1384 } 1385 1386 /* 1387 * Active failover 1388 */ 1389 1390 int 1391 trunk_fail_attach(struct trunk_softc *tr) 1392 { 1393 tr->tr_detach = trunk_fail_detach; 1394 tr->tr_start = trunk_fail_start; 1395 tr->tr_input = trunk_fail_input; 1396 tr->tr_init = NULL; 1397 tr->tr_stop = NULL; 1398 tr->tr_port_create = trunk_fail_port_create; 1399 tr->tr_port_destroy = trunk_fail_port_destroy; 1400 tr->tr_linkstate = trunk_fail_linkstate; 1401 tr->tr_req = NULL; 1402 tr->tr_portreq = NULL; 1403 1404 /* Get primary or the next active port */ 1405 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1406 1407 return (0); 1408 } 1409 1410 int 1411 trunk_fail_detach(struct trunk_softc *tr) 1412 { 1413 tr->tr_psc = NULL; 1414 return (0); 1415 } 1416 1417 int 1418 trunk_fail_port_create(struct trunk_port *tp) 1419 { 1420 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1421 1422 /* Get primary or the next active port */ 1423 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1424 return (0); 1425 } 1426 1427 void 1428 trunk_fail_port_destroy(struct trunk_port *tp) 1429 { 1430 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1431 struct trunk_port *tp_next; 1432 1433 if ((caddr_t)tp == tr->tr_psc) { 1434 /* Get the next active port */ 1435 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1436 if (tp_next == tp) 1437 tr->tr_psc = NULL; 1438 else 1439 tr->tr_psc = (caddr_t)tp_next; 1440 } else { 1441 /* Get primary or the next active port */ 1442 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1443 } 1444 } 1445 1446 int 1447 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m) 1448 { 1449 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc; 1450 1451 /* Use the master port if active or the next available port */ 1452 if (tp == NULL) { 1453 m_freem(m); 1454 return (ENOENT); 1455 } 1456 1457 return (if_enqueue(tp->tp_if, m)); 1458 } 1459 1460 int 1461 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1462 { 1463 if ((caddr_t)tp == tr->tr_psc) 1464 return (0); 1465 m_freem(m); 1466 return (-1); 1467 } 1468 1469 void 1470 trunk_fail_linkstate(struct trunk_port *tp) 1471 { 1472 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1473 1474 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1475 } 1476 1477 /* 1478 * Loadbalancing 1479 */ 1480 1481 int 1482 trunk_lb_attach(struct trunk_softc *tr) 1483 { 1484 struct trunk_lb *lb; 1485 1486 if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 1487 return (ENOMEM); 1488 1489 tr->tr_detach = trunk_lb_detach; 1490 tr->tr_start = trunk_lb_start; 1491 tr->tr_input = trunk_lb_input; 1492 tr->tr_port_create = trunk_lb_port_create; 1493 tr->tr_port_destroy = trunk_lb_port_destroy; 1494 tr->tr_linkstate = NULL; 1495 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1496 tr->tr_req = NULL; 1497 tr->tr_portreq = NULL; 1498 tr->tr_init = NULL; 1499 tr->tr_stop = NULL; 1500 1501 arc4random_buf(&lb->lb_key, sizeof(lb->lb_key)); 1502 tr->tr_psc = (caddr_t)lb; 1503 1504 return (0); 1505 } 1506 1507 int 1508 trunk_lb_detach(struct trunk_softc *tr) 1509 { 1510 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1511 1512 free(lb, M_DEVBUF, sizeof *lb); 1513 return (0); 1514 } 1515 1516 int 1517 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp) 1518 { 1519 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1520 struct trunk_port *tp_next; 1521 int i = 0; 1522 1523 bzero(&lb->lb_ports, sizeof(lb->lb_ports)); 1524 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1525 if (tp_next == tp) 1526 continue; 1527 if (i >= TRUNK_MAX_PORTS) 1528 return (EINVAL); 1529 if (tr->tr_ifflags & IFF_DEBUG) 1530 printf("%s: port %s at index %d\n", 1531 tr->tr_ifname, tp_next->tp_ifname, i); 1532 lb->lb_ports[i++] = tp_next; 1533 } 1534 1535 return (0); 1536 } 1537 1538 int 1539 trunk_lb_port_create(struct trunk_port *tp) 1540 { 1541 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1542 return (trunk_lb_porttable(tr, NULL)); 1543 } 1544 1545 void 1546 trunk_lb_port_destroy(struct trunk_port *tp) 1547 { 1548 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1549 trunk_lb_porttable(tr, tp); 1550 } 1551 1552 int 1553 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m) 1554 { 1555 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1556 struct trunk_port *tp = NULL; 1557 u_int32_t p = 0; 1558 1559 p = trunk_hashmbuf(m, &lb->lb_key); 1560 p %= tr->tr_count; 1561 tp = lb->lb_ports[p]; 1562 1563 /* 1564 * Check the port's link state. This will return the next active 1565 * port if the link is down or the port is NULL. 1566 */ 1567 if ((tp = trunk_link_active(tr, tp)) == NULL) { 1568 m_freem(m); 1569 return (ENOENT); 1570 } 1571 1572 return (if_enqueue(tp->tp_if, m)); 1573 } 1574 1575 int 1576 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1577 { 1578 /* Just pass in the packet to our trunk device */ 1579 return (0); 1580 } 1581 1582 /* 1583 * Broadcast mode 1584 */ 1585 1586 int 1587 trunk_bcast_attach(struct trunk_softc *tr) 1588 { 1589 tr->tr_detach = trunk_bcast_detach; 1590 tr->tr_start = trunk_bcast_start; 1591 tr->tr_input = trunk_bcast_input; 1592 tr->tr_init = NULL; 1593 tr->tr_stop = NULL; 1594 tr->tr_port_create = NULL; 1595 tr->tr_port_destroy = NULL; 1596 tr->tr_linkstate = NULL; 1597 tr->tr_req = NULL; 1598 tr->tr_portreq = NULL; 1599 1600 return (0); 1601 } 1602 1603 int 1604 trunk_bcast_detach(struct trunk_softc *tr) 1605 { 1606 return (0); 1607 } 1608 1609 int 1610 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m0) 1611 { 1612 int active_ports = 0; 1613 int errors = 0; 1614 struct trunk_port *tp, *last = NULL; 1615 struct mbuf *m; 1616 1617 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1618 if (!TRUNK_PORTACTIVE(tp)) 1619 continue; 1620 1621 active_ports++; 1622 1623 if (last != NULL) { 1624 m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT); 1625 if (m == NULL) { 1626 errors++; 1627 break; 1628 } 1629 1630 if (if_enqueue(last->tp_if, m) != 0) 1631 errors++; 1632 } 1633 last = tp; 1634 } 1635 if (last == NULL) { 1636 m_freem(m0); 1637 return (ENOENT); 1638 } 1639 1640 if (if_enqueue(last->tp_if, m0) != 0) 1641 errors++; 1642 1643 if (errors == active_ports) 1644 return (ENOBUFS); 1645 1646 return (0); 1647 } 1648 1649 int 1650 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1651 { 1652 return (0); 1653 } 1654 1655 /* 1656 * 802.3ad LACP 1657 */ 1658 1659 int 1660 trunk_lacp_attach(struct trunk_softc *tr) 1661 { 1662 struct trunk_port *tp; 1663 int error; 1664 1665 tr->tr_detach = trunk_lacp_detach; 1666 tr->tr_port_create = lacp_port_create; 1667 tr->tr_port_destroy = lacp_port_destroy; 1668 tr->tr_linkstate = lacp_linkstate; 1669 tr->tr_start = trunk_lacp_start; 1670 tr->tr_input = trunk_lacp_input; 1671 tr->tr_init = lacp_init; 1672 tr->tr_stop = lacp_stop; 1673 tr->tr_req = lacp_req; 1674 tr->tr_portreq = lacp_portreq; 1675 1676 error = lacp_attach(tr); 1677 if (error) 1678 return (error); 1679 1680 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1681 lacp_port_create(tp); 1682 1683 return (error); 1684 } 1685 1686 int 1687 trunk_lacp_detach(struct trunk_softc *tr) 1688 { 1689 struct trunk_port *tp; 1690 int error; 1691 1692 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1693 lacp_port_destroy(tp); 1694 1695 /* unlocking is safe here */ 1696 error = lacp_detach(tr); 1697 1698 return (error); 1699 } 1700 1701 int 1702 trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m) 1703 { 1704 struct trunk_port *tp; 1705 1706 tp = lacp_select_tx_port(tr, m); 1707 if (tp == NULL) { 1708 m_freem(m); 1709 return (EBUSY); 1710 } 1711 1712 return (if_enqueue(tp->tp_if, m)); 1713 } 1714 1715 int 1716 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1717 { 1718 return (lacp_input(tp, m)); 1719 } 1720