1 /* $OpenBSD: if_trunk.c,v 1.150 2020/09/12 20:12:09 kn 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 free(tp, M_DEVBUF, sizeof *tp); 467 468 /* Update trunk capabilities */ 469 tr->tr_capabilities = trunk_capabilities(tr); 470 471 return (0); 472 } 473 474 int 475 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 476 { 477 struct trunk_reqport *rp = (struct trunk_reqport *)data; 478 struct trunk_softc *tr; 479 struct trunk_port *tp = NULL; 480 int error = 0; 481 482 /* Should be checked by the caller */ 483 if (ifp->if_type != IFT_IEEE8023ADLAG || 484 (tp = trunk_port_get(NULL, ifp)) == NULL || 485 (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) { 486 error = EINVAL; 487 goto fallback; 488 } 489 490 switch (cmd) { 491 case SIOCGTRUNKPORT: 492 if (rp->rp_portname[0] == '\0' || 493 ifunit(rp->rp_portname) != ifp) { 494 error = EINVAL; 495 break; 496 } 497 498 /* Search in all trunks if the global flag is set */ 499 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 500 NULL : tr, ifp)) == NULL) { 501 error = ENOENT; 502 break; 503 } 504 505 trunk_port2req(tp, rp); 506 break; 507 case SIOCSIFMTU: 508 /* Do not allow the MTU to be changed once joined */ 509 error = EINVAL; 510 break; 511 default: 512 error = ENOTTY; 513 goto fallback; 514 } 515 516 return (error); 517 518 fallback: 519 if (tp != NULL) 520 error = (*tp->tp_ioctl)(ifp, cmd, data); 521 522 return (error); 523 } 524 525 int 526 trunk_port_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 527 struct rtentry *rt) 528 { 529 /* restrict transmission on trunk members to bpf only */ 530 if (ifp->if_type == IFT_IEEE8023ADLAG && 531 (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) { 532 m_freem(m); 533 return (EBUSY); 534 } 535 536 return (ether_output(ifp, m, dst, rt)); 537 } 538 539 void 540 trunk_port_ifdetach(void *arg) 541 { 542 struct trunk_port *tp = (struct trunk_port *)arg; 543 544 trunk_port_destroy(tp); 545 } 546 547 struct trunk_port * 548 trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp) 549 { 550 struct trunk_port *tp; 551 struct trunk_softc *tr_ptr; 552 553 if (tr != NULL) { 554 /* Search port in specified trunk */ 555 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 556 if (tp->tp_if == ifp) 557 return (tp); 558 } 559 } else { 560 /* Search all trunks for the selected port */ 561 SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) { 562 SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) { 563 if (tp->tp_if == ifp) 564 return (tp); 565 } 566 } 567 } 568 569 return (NULL); 570 } 571 572 void 573 trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp) 574 { 575 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 576 577 strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname)); 578 strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname)); 579 rp->rp_prio = tp->tp_prio; 580 if (tr->tr_portreq != NULL) 581 (*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc); 582 583 /* Add protocol specific flags */ 584 switch (tr->tr_proto) { 585 case TRUNK_PROTO_FAILOVER: 586 rp->rp_flags = tp->tp_flags; 587 if (tp == trunk_link_active(tr, tr->tr_primary)) 588 rp->rp_flags |= TRUNK_PORT_ACTIVE; 589 break; 590 591 case TRUNK_PROTO_ROUNDROBIN: 592 case TRUNK_PROTO_LOADBALANCE: 593 case TRUNK_PROTO_BROADCAST: 594 rp->rp_flags = tp->tp_flags; 595 if (TRUNK_PORTACTIVE(tp)) 596 rp->rp_flags |= TRUNK_PORT_ACTIVE; 597 break; 598 599 case TRUNK_PROTO_LACP: 600 /* LACP has a different definition of active */ 601 rp->rp_flags = lacp_port_status(tp); 602 break; 603 default: 604 break; 605 } 606 } 607 608 int 609 trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 610 { 611 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 612 struct trunk_reqall *ra = (struct trunk_reqall *)data; 613 struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf; 614 struct trunk_opts *tro = (struct trunk_opts *)data; 615 struct ifreq *ifr = (struct ifreq *)data; 616 struct lacp_softc *lsc; 617 struct trunk_port *tp; 618 struct lacp_port *lp; 619 struct ifnet *tpif; 620 int i, error = 0; 621 622 bzero(&rpbuf, sizeof(rpbuf)); 623 624 switch (cmd) { 625 case SIOCGTRUNK: 626 ra->ra_proto = tr->tr_proto; 627 if (tr->tr_req != NULL) 628 (*tr->tr_req)(tr, (caddr_t)&ra->ra_psc); 629 ra->ra_ports = i = 0; 630 tp = SLIST_FIRST(&tr->tr_ports); 631 while (tp && ra->ra_size >= 632 i + sizeof(struct trunk_reqport)) { 633 trunk_port2req(tp, &rpbuf); 634 error = copyout(&rpbuf, (caddr_t)ra->ra_port + i, 635 sizeof(struct trunk_reqport)); 636 if (error) 637 break; 638 i += sizeof(struct trunk_reqport); 639 ra->ra_ports++; 640 tp = SLIST_NEXT(tp, tp_entries); 641 } 642 break; 643 case SIOCSTRUNK: 644 if ((error = suser(curproc)) != 0) { 645 error = EPERM; 646 break; 647 } 648 if (ra->ra_proto >= TRUNK_PROTO_MAX) { 649 error = EPROTONOSUPPORT; 650 break; 651 } 652 653 /* 654 * Use of ifp->if_input and ac->ac_trunkport is 655 * protected by NET_LOCK, but that may not be true 656 * in the future. The below comment and code flow is 657 * maintained to help in that future. 658 * 659 * Serialize modifications to the trunk and trunk 660 * ports via the ifih SRP: detaching trunk_input 661 * from the trunk port will require all currently 662 * running trunk_input's on this port to finish 663 * granting us an exclusive access to it. 664 */ 665 NET_ASSERT_LOCKED(); 666 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 667 /* if_ih_remove(tp->tp_if, trunk_input, tp); */ 668 tp->tp_if->if_input = tp->tp_input; 669 } 670 if (tr->tr_proto != TRUNK_PROTO_NONE) 671 error = tr->tr_detach(tr); 672 if (error != 0) 673 break; 674 for (i = 0; i < nitems(trunk_protos); i++) { 675 if (trunk_protos[i].ti_proto == ra->ra_proto) { 676 if (tr->tr_ifflags & IFF_DEBUG) 677 printf("%s: using proto %u\n", 678 tr->tr_ifname, 679 trunk_protos[i].ti_proto); 680 tr->tr_proto = trunk_protos[i].ti_proto; 681 if (tr->tr_proto != TRUNK_PROTO_NONE) 682 error = trunk_protos[i].ti_attach(tr); 683 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 684 /* if_ih_insert(tp->tp_if, 685 trunk_input, tp); */ 686 tp->tp_if->if_input = trunk_input; 687 } 688 /* Update trunk capabilities */ 689 tr->tr_capabilities = trunk_capabilities(tr); 690 goto out; 691 } 692 } 693 error = EPROTONOSUPPORT; 694 break; 695 case SIOCGTRUNKOPTS: 696 /* Only LACP trunks have options atm */ 697 if (tro->to_proto != TRUNK_PROTO_LACP) { 698 error = EPROTONOSUPPORT; 699 break; 700 } 701 lsc = LACP_SOFTC(tr); 702 tro->to_lacpopts.lacp_mode = lsc->lsc_mode; 703 tro->to_lacpopts.lacp_timeout = lsc->lsc_timeout; 704 tro->to_lacpopts.lacp_prio = lsc->lsc_sys_prio; 705 tro->to_lacpopts.lacp_portprio = lsc->lsc_port_prio; 706 tro->to_lacpopts.lacp_ifqprio = lsc->lsc_ifq_prio; 707 break; 708 case SIOCSTRUNKOPTS: 709 if ((error = suser(curproc)) != 0) { 710 error = EPERM; 711 break; 712 } 713 /* Only LACP trunks have options atm */ 714 if (tro->to_proto != TRUNK_PROTO_LACP) { 715 error = EPROTONOSUPPORT; 716 break; 717 } 718 lsc = LACP_SOFTC(tr); 719 switch(tro->to_opts) { 720 case TRUNK_OPT_LACP_MODE: 721 /* 722 * Ensure mode changes occur immediately 723 * on all ports 724 */ 725 lsc->lsc_mode = tro->to_lacpopts.lacp_mode; 726 if (lsc->lsc_mode == 0) { 727 LIST_FOREACH(lp, &lsc->lsc_ports, 728 lp_next) 729 lp->lp_state &= 730 ~LACP_STATE_ACTIVITY; 731 } else { 732 LIST_FOREACH(lp, &lsc->lsc_ports, 733 lp_next) 734 lp->lp_state |= 735 LACP_STATE_ACTIVITY; 736 } 737 break; 738 case TRUNK_OPT_LACP_TIMEOUT: 739 /* 740 * Ensure timeout changes occur immediately 741 * on all ports 742 */ 743 lsc->lsc_timeout = 744 tro->to_lacpopts.lacp_timeout; 745 if (lsc->lsc_timeout == 0) { 746 LIST_FOREACH(lp, &lsc->lsc_ports, 747 lp_next) 748 lp->lp_state &= 749 ~LACP_STATE_TIMEOUT; 750 } else { 751 LIST_FOREACH(lp, &lsc->lsc_ports, 752 lp_next) 753 lp->lp_state |= 754 LACP_STATE_TIMEOUT; 755 } 756 break; 757 case TRUNK_OPT_LACP_SYS_PRIO: 758 if (tro->to_lacpopts.lacp_prio == 0) { 759 error = EINVAL; 760 break; 761 } 762 lsc->lsc_sys_prio = tro->to_lacpopts.lacp_prio; 763 break; 764 case TRUNK_OPT_LACP_PORT_PRIO: 765 if (tro->to_lacpopts.lacp_portprio == 0) { 766 error = EINVAL; 767 break; 768 } 769 lsc->lsc_port_prio = 770 tro->to_lacpopts.lacp_portprio; 771 break; 772 case TRUNK_OPT_LACP_IFQ_PRIO: 773 if (tro->to_lacpopts.lacp_ifqprio > 774 IFQ_MAXPRIO) { 775 error = EINVAL; 776 break; 777 } 778 lsc->lsc_ifq_prio = 779 tro->to_lacpopts.lacp_ifqprio; 780 break; 781 } 782 break; 783 case SIOCGTRUNKPORT: 784 if (rp->rp_portname[0] == '\0' || 785 (tpif = ifunit(rp->rp_portname)) == NULL) { 786 error = EINVAL; 787 break; 788 } 789 790 /* Search in all trunks if the global flag is set */ 791 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 792 NULL : tr, tpif)) == NULL) { 793 error = ENOENT; 794 break; 795 } 796 797 trunk_port2req(tp, rp); 798 break; 799 case SIOCSTRUNKPORT: 800 if ((error = suser(curproc)) != 0) { 801 error = EPERM; 802 break; 803 } 804 if (rp->rp_portname[0] == '\0' || 805 (tpif = ifunit(rp->rp_portname)) == NULL) { 806 error = EINVAL; 807 break; 808 } 809 error = trunk_port_create(tr, tpif); 810 break; 811 case SIOCSTRUNKDELPORT: 812 if ((error = suser(curproc)) != 0) { 813 error = EPERM; 814 break; 815 } 816 if (rp->rp_portname[0] == '\0' || 817 (tpif = ifunit(rp->rp_portname)) == NULL) { 818 error = EINVAL; 819 break; 820 } 821 822 /* Search in all trunks if the global flag is set */ 823 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 824 NULL : tr, tpif)) == NULL) { 825 error = ENOENT; 826 break; 827 } 828 829 error = trunk_port_destroy(tp); 830 break; 831 case SIOCSIFADDR: 832 ifp->if_flags |= IFF_UP; 833 /* FALLTHROUGH */ 834 case SIOCSIFFLAGS: 835 error = ENETRESET; 836 break; 837 case SIOCADDMULTI: 838 error = trunk_ether_addmulti(tr, ifr); 839 break; 840 case SIOCDELMULTI: 841 error = trunk_ether_delmulti(tr, ifr); 842 break; 843 case SIOCSIFMEDIA: 844 case SIOCGIFMEDIA: 845 error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd); 846 break; 847 case SIOCSIFLLADDR: 848 /* Update the port lladdrs as well */ 849 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 850 trunk_port_lladdr(tp, ifr->ifr_addr.sa_data); 851 error = ENETRESET; 852 break; 853 default: 854 error = ether_ioctl(ifp, &tr->tr_ac, cmd, data); 855 } 856 857 if (error == ENETRESET) { 858 if (ifp->if_flags & IFF_UP) { 859 if ((ifp->if_flags & IFF_RUNNING) == 0) 860 trunk_init(ifp); 861 } else { 862 if (ifp->if_flags & IFF_RUNNING) 863 trunk_stop(ifp); 864 } 865 error = 0; 866 } 867 868 out: 869 return (error); 870 } 871 872 int 873 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr) 874 { 875 struct trunk_mc *mc; 876 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 877 int error; 878 879 /* Ignore ENETRESET error code */ 880 if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET) 881 return (error); 882 883 if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) { 884 error = ENOMEM; 885 goto failed; 886 } 887 888 ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 889 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm); 890 bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len); 891 SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries); 892 893 if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI, 894 (caddr_t)ifr)) != 0) { 895 trunk_ether_delmulti(tr, ifr); 896 return (error); 897 } 898 899 return (error); 900 901 failed: 902 ether_delmulti(ifr, &tr->tr_ac); 903 904 return (error); 905 } 906 907 int 908 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr) 909 { 910 struct ether_multi *enm; 911 struct trunk_mc *mc; 912 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 913 int error; 914 915 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 916 return (error); 917 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm); 918 if (enm == NULL) 919 return (EINVAL); 920 921 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) 922 if (mc->mc_enm == enm) 923 break; 924 925 /* We won't delete entries we didn't add */ 926 if (mc == NULL) 927 return (EINVAL); 928 929 if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET) 930 return (error); 931 932 /* We no longer use this multicast address. Tell parent so. */ 933 error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 934 if (error == 0) { 935 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 936 free(mc, M_DEVBUF, sizeof(*mc)); 937 } else { 938 /* XXX At least one port failed to remove the address */ 939 if (tr->tr_ifflags & IFF_DEBUG) { 940 printf("%s: failed to remove multicast address " 941 "on all ports (%d)\n", tr->tr_ifname, error); 942 } 943 (void)ether_addmulti(ifr, &tr->tr_ac); 944 } 945 946 return (0); 947 } 948 949 void 950 trunk_ether_purgemulti(struct trunk_softc *tr) 951 { 952 struct trunk_mc *mc; 953 struct trunk_ifreq ifs; 954 struct ifreq *ifr = &ifs.ifreq.ifreq; 955 956 while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) { 957 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 958 959 /* Try to remove multicast address on all ports */ 960 trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 961 962 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 963 free(mc, M_DEVBUF, sizeof(*mc)); 964 } 965 } 966 967 int 968 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd) 969 { 970 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 971 struct trunk_mc *mc; 972 struct trunk_ifreq ifs; 973 struct ifreq *ifr = &ifs.ifreq.ifreq; 974 int ret, error = 0; 975 976 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 977 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) { 978 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 979 980 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) { 981 if (tr->tr_ifflags & IFF_DEBUG) { 982 printf("%s: ioctl %lu failed on %s: %d\n", 983 tr->tr_ifname, cmd, tp->tp_ifname, ret); 984 } 985 /* Store last known error and continue */ 986 error = ret; 987 } 988 } 989 990 return (error); 991 } 992 993 int 994 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data) 995 { 996 struct ifreq *ifr = (struct ifreq *)data; 997 struct trunk_port *tp; 998 int ret, error = 0; 999 1000 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1001 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 1002 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) { 1003 if (tr->tr_ifflags & IFF_DEBUG) { 1004 printf("%s: ioctl %lu failed on %s: %d\n", 1005 tr->tr_ifname, cmd, tp->tp_ifname, ret); 1006 } 1007 /* Store last known error and continue */ 1008 error = ret; 1009 } 1010 } 1011 1012 return (error); 1013 } 1014 1015 void 1016 trunk_start(struct ifnet *ifp) 1017 { 1018 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1019 struct mbuf *m; 1020 int error; 1021 1022 for (;;) { 1023 m = ifq_dequeue(&ifp->if_snd); 1024 if (m == NULL) 1025 break; 1026 1027 #if NBPFILTER > 0 1028 if (ifp->if_bpf) 1029 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1030 #endif 1031 1032 if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) { 1033 error = (*tr->tr_start)(tr, m); 1034 if (error != 0) 1035 ifp->if_oerrors++; 1036 } else { 1037 m_freem(m); 1038 if (tr->tr_proto != TRUNK_PROTO_NONE) 1039 ifp->if_oerrors++; 1040 } 1041 } 1042 } 1043 1044 u_int32_t 1045 trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key) 1046 { 1047 u_int16_t etype, ether_vtag; 1048 u_int32_t p = 0; 1049 u_int16_t *vlan, vlanbuf[2]; 1050 int off; 1051 struct ether_header *eh; 1052 struct ip *ip, ipbuf; 1053 #ifdef INET6 1054 u_int32_t flow; 1055 struct ip6_hdr *ip6, ip6buf; 1056 #endif 1057 SIPHASH_CTX ctx; 1058 1059 if (m->m_pkthdr.csum_flags & M_FLOWID) 1060 return (m->m_pkthdr.ph_flowid); 1061 1062 SipHash24_Init(&ctx, key); 1063 off = sizeof(*eh); 1064 if (m->m_len < off) 1065 goto done; 1066 eh = mtod(m, struct ether_header *); 1067 etype = ntohs(eh->ether_type); 1068 SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN); 1069 SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN); 1070 1071 /* Special handling for encapsulating VLAN frames */ 1072 if (m->m_flags & M_VLANTAG) { 1073 ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 1074 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1075 } else if (etype == ETHERTYPE_VLAN) { 1076 if ((vlan = (u_int16_t *) 1077 trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL) 1078 return (p); 1079 ether_vtag = EVL_VLANOFTAG(*vlan); 1080 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1081 etype = ntohs(vlan[1]); 1082 off += EVL_ENCAPLEN; 1083 } 1084 1085 switch (etype) { 1086 case ETHERTYPE_IP: 1087 if ((ip = (struct ip *) 1088 trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL) 1089 return (p); 1090 SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr)); 1091 SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr)); 1092 break; 1093 #ifdef INET6 1094 case ETHERTYPE_IPV6: 1095 if ((ip6 = (struct ip6_hdr *) 1096 trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL) 1097 return (p); 1098 SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr)); 1099 SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr)); 1100 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 1101 SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */ 1102 break; 1103 #endif 1104 } 1105 1106 done: 1107 return SipHash24_End(&ctx); 1108 } 1109 1110 void 1111 trunk_init(struct ifnet *ifp) 1112 { 1113 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1114 1115 ifp->if_flags |= IFF_RUNNING; 1116 1117 if (tr->tr_init != NULL) 1118 (*tr->tr_init)(tr); 1119 } 1120 1121 void 1122 trunk_stop(struct ifnet *ifp) 1123 { 1124 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1125 1126 ifp->if_flags &= ~IFF_RUNNING; 1127 1128 if (tr->tr_stop != NULL) 1129 (*tr->tr_stop)(tr); 1130 } 1131 1132 void 1133 trunk_input(struct ifnet *ifp, struct mbuf *m) 1134 { 1135 struct arpcom *ac0 = (struct arpcom *)ifp; 1136 struct trunk_port *tp; 1137 struct trunk_softc *tr; 1138 struct ifnet *trifp = NULL; 1139 struct ether_header *eh; 1140 1141 if (m->m_len < sizeof(*eh)) 1142 goto bad; 1143 1144 eh = mtod(m, struct ether_header *); 1145 if (ETHER_IS_MULTICAST(eh->ether_dhost)) 1146 ifp->if_imcasts++; 1147 1148 /* Should be checked by the caller */ 1149 if (ifp->if_type != IFT_IEEE8023ADLAG) 1150 goto bad; 1151 1152 tp = (struct trunk_port *)ac0->ac_trunkport; 1153 if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL) 1154 goto bad; 1155 1156 trifp = &tr->tr_ac.ac_if; 1157 if (tr->tr_proto == TRUNK_PROTO_NONE) 1158 goto bad; 1159 1160 if ((*tr->tr_input)(tr, tp, m)) { 1161 /* 1162 * We stop here if the packet has been consumed 1163 * by the protocol routine. 1164 */ 1165 return; 1166 } 1167 1168 if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1169 goto bad; 1170 1171 /* 1172 * Drop promiscuously received packets if we are not in 1173 * promiscuous mode. 1174 */ 1175 if (!ETHER_IS_MULTICAST(eh->ether_dhost) && 1176 (ifp->if_flags & IFF_PROMISC) && 1177 (trifp->if_flags & IFF_PROMISC) == 0) { 1178 if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost, 1179 ETHER_ADDR_LEN)) { 1180 m_freem(m); 1181 return; 1182 } 1183 } 1184 1185 1186 if_vinput(trifp, m); 1187 return; 1188 1189 bad: 1190 if (trifp != NULL) 1191 trifp->if_ierrors++; 1192 m_freem(m); 1193 } 1194 1195 int 1196 trunk_media_change(struct ifnet *ifp) 1197 { 1198 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1199 1200 if (tr->tr_ifflags & IFF_DEBUG) 1201 printf("%s\n", __func__); 1202 1203 /* Ignore */ 1204 return (0); 1205 } 1206 1207 void 1208 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr) 1209 { 1210 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1211 struct trunk_port *tp; 1212 1213 imr->ifm_status = IFM_AVALID; 1214 imr->ifm_active = IFM_ETHER | IFM_AUTO; 1215 1216 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1217 if (TRUNK_PORTACTIVE(tp)) 1218 imr->ifm_status |= IFM_ACTIVE; 1219 } 1220 } 1221 1222 void 1223 trunk_port_state(void *arg) 1224 { 1225 struct trunk_port *tp = (struct trunk_port *)arg; 1226 struct trunk_softc *tr = NULL; 1227 1228 if (tp != NULL) 1229 tr = (struct trunk_softc *)tp->tp_trunk; 1230 if (tr == NULL) 1231 return; 1232 if (tr->tr_linkstate != NULL) 1233 (*tr->tr_linkstate)(tp); 1234 trunk_link_active(tr, tp); 1235 rtm_ifchg(&tr->tr_ac.ac_if); 1236 } 1237 1238 struct trunk_port * 1239 trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp) 1240 { 1241 struct trunk_port *tp_next, *rval = NULL; 1242 int new_link = LINK_STATE_DOWN; 1243 1244 /* 1245 * Search a port which reports an active link state. 1246 */ 1247 1248 if (tp == NULL) 1249 goto search; 1250 if (TRUNK_PORTACTIVE(tp)) { 1251 rval = tp; 1252 goto found; 1253 } 1254 if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL && 1255 TRUNK_PORTACTIVE(tp_next)) { 1256 rval = tp_next; 1257 goto found; 1258 } 1259 1260 search: 1261 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1262 if (TRUNK_PORTACTIVE(tp_next)) { 1263 rval = tp_next; 1264 goto found; 1265 } 1266 } 1267 1268 found: 1269 if (rval != NULL) { 1270 /* 1271 * The IEEE 802.1D standard assumes that a trunk with 1272 * multiple ports is always full duplex. This is valid 1273 * for load sharing trunks and if at least two links 1274 * are active. Unfortunately, checking the latter would 1275 * be too expensive at this point. 1276 */ 1277 if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) && 1278 (tr->tr_count > 1)) 1279 new_link = LINK_STATE_FULL_DUPLEX; 1280 else 1281 new_link = rval->tp_link_state; 1282 } 1283 1284 if (tr->tr_ac.ac_if.if_link_state != new_link) { 1285 tr->tr_ac.ac_if.if_link_state = new_link; 1286 if_link_state_change(&tr->tr_ac.ac_if); 1287 } 1288 1289 return (rval); 1290 } 1291 1292 const void * 1293 trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) 1294 { 1295 if (m->m_pkthdr.len < (off + len)) 1296 return (NULL); 1297 else if (m->m_len < (off + len)) { 1298 m_copydata(m, off, len, buf); 1299 return (buf); 1300 } 1301 return (mtod(m, caddr_t) + off); 1302 } 1303 1304 /* 1305 * Simple round robin trunking 1306 */ 1307 1308 int 1309 trunk_rr_attach(struct trunk_softc *tr) 1310 { 1311 struct trunk_port *tp; 1312 1313 tr->tr_detach = trunk_rr_detach; 1314 tr->tr_start = trunk_rr_start; 1315 tr->tr_input = trunk_rr_input; 1316 tr->tr_init = NULL; 1317 tr->tr_stop = NULL; 1318 tr->tr_linkstate = NULL; 1319 tr->tr_port_create = NULL; 1320 tr->tr_port_destroy = trunk_rr_port_destroy; 1321 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1322 tr->tr_req = NULL; 1323 tr->tr_portreq = NULL; 1324 1325 tp = SLIST_FIRST(&tr->tr_ports); 1326 tr->tr_psc = (caddr_t)tp; 1327 1328 return (0); 1329 } 1330 1331 int 1332 trunk_rr_detach(struct trunk_softc *tr) 1333 { 1334 tr->tr_psc = NULL; 1335 return (0); 1336 } 1337 1338 void 1339 trunk_rr_port_destroy(struct trunk_port *tp) 1340 { 1341 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1342 1343 if (tp == (struct trunk_port *)tr->tr_psc) 1344 tr->tr_psc = NULL; 1345 } 1346 1347 int 1348 trunk_rr_start(struct trunk_softc *tr, struct mbuf *m) 1349 { 1350 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next; 1351 int error = 0; 1352 1353 if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) { 1354 m_freem(m); 1355 return (ENOENT); 1356 } 1357 1358 if ((error = if_enqueue(tp->tp_if, m)) != 0) 1359 return (error); 1360 1361 /* Get next active port */ 1362 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1363 tr->tr_psc = (caddr_t)tp_next; 1364 1365 return (0); 1366 } 1367 1368 int 1369 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1370 { 1371 /* Just pass in the packet to our trunk device */ 1372 return (0); 1373 } 1374 1375 /* 1376 * Active failover 1377 */ 1378 1379 int 1380 trunk_fail_attach(struct trunk_softc *tr) 1381 { 1382 tr->tr_detach = trunk_fail_detach; 1383 tr->tr_start = trunk_fail_start; 1384 tr->tr_input = trunk_fail_input; 1385 tr->tr_init = NULL; 1386 tr->tr_stop = NULL; 1387 tr->tr_port_create = trunk_fail_port_create; 1388 tr->tr_port_destroy = trunk_fail_port_destroy; 1389 tr->tr_linkstate = trunk_fail_linkstate; 1390 tr->tr_req = NULL; 1391 tr->tr_portreq = NULL; 1392 1393 /* Get primary or the next active port */ 1394 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1395 1396 return (0); 1397 } 1398 1399 int 1400 trunk_fail_detach(struct trunk_softc *tr) 1401 { 1402 tr->tr_psc = NULL; 1403 return (0); 1404 } 1405 1406 int 1407 trunk_fail_port_create(struct trunk_port *tp) 1408 { 1409 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1410 1411 /* Get primary or the next active port */ 1412 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1413 return (0); 1414 } 1415 1416 void 1417 trunk_fail_port_destroy(struct trunk_port *tp) 1418 { 1419 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1420 struct trunk_port *tp_next; 1421 1422 if ((caddr_t)tp == tr->tr_psc) { 1423 /* Get the next active port */ 1424 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1425 if (tp_next == tp) 1426 tr->tr_psc = NULL; 1427 else 1428 tr->tr_psc = (caddr_t)tp_next; 1429 } else { 1430 /* Get primary or the next active port */ 1431 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1432 } 1433 } 1434 1435 int 1436 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m) 1437 { 1438 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc; 1439 1440 /* Use the master port if active or the next available port */ 1441 if (tp == NULL) { 1442 m_freem(m); 1443 return (ENOENT); 1444 } 1445 1446 return (if_enqueue(tp->tp_if, m)); 1447 } 1448 1449 int 1450 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1451 { 1452 if ((caddr_t)tp == tr->tr_psc) 1453 return (0); 1454 m_freem(m); 1455 return (-1); 1456 } 1457 1458 void 1459 trunk_fail_linkstate(struct trunk_port *tp) 1460 { 1461 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1462 1463 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1464 } 1465 1466 /* 1467 * Loadbalancing 1468 */ 1469 1470 int 1471 trunk_lb_attach(struct trunk_softc *tr) 1472 { 1473 struct trunk_lb *lb; 1474 1475 if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 1476 return (ENOMEM); 1477 1478 tr->tr_detach = trunk_lb_detach; 1479 tr->tr_start = trunk_lb_start; 1480 tr->tr_input = trunk_lb_input; 1481 tr->tr_port_create = trunk_lb_port_create; 1482 tr->tr_port_destroy = trunk_lb_port_destroy; 1483 tr->tr_linkstate = NULL; 1484 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1485 tr->tr_req = NULL; 1486 tr->tr_portreq = NULL; 1487 tr->tr_init = NULL; 1488 tr->tr_stop = NULL; 1489 1490 arc4random_buf(&lb->lb_key, sizeof(lb->lb_key)); 1491 tr->tr_psc = (caddr_t)lb; 1492 1493 return (0); 1494 } 1495 1496 int 1497 trunk_lb_detach(struct trunk_softc *tr) 1498 { 1499 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1500 1501 free(lb, M_DEVBUF, sizeof *lb); 1502 return (0); 1503 } 1504 1505 int 1506 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp) 1507 { 1508 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1509 struct trunk_port *tp_next; 1510 int i = 0; 1511 1512 bzero(&lb->lb_ports, sizeof(lb->lb_ports)); 1513 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1514 if (tp_next == tp) 1515 continue; 1516 if (i >= TRUNK_MAX_PORTS) 1517 return (EINVAL); 1518 if (tr->tr_ifflags & IFF_DEBUG) 1519 printf("%s: port %s at index %d\n", 1520 tr->tr_ifname, tp_next->tp_ifname, i); 1521 lb->lb_ports[i++] = tp_next; 1522 } 1523 1524 return (0); 1525 } 1526 1527 int 1528 trunk_lb_port_create(struct trunk_port *tp) 1529 { 1530 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1531 return (trunk_lb_porttable(tr, NULL)); 1532 } 1533 1534 void 1535 trunk_lb_port_destroy(struct trunk_port *tp) 1536 { 1537 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1538 trunk_lb_porttable(tr, tp); 1539 } 1540 1541 int 1542 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m) 1543 { 1544 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1545 struct trunk_port *tp = NULL; 1546 u_int32_t p = 0; 1547 1548 p = trunk_hashmbuf(m, &lb->lb_key); 1549 p %= tr->tr_count; 1550 tp = lb->lb_ports[p]; 1551 1552 /* 1553 * Check the port's link state. This will return the next active 1554 * port if the link is down or the port is NULL. 1555 */ 1556 if ((tp = trunk_link_active(tr, tp)) == NULL) { 1557 m_freem(m); 1558 return (ENOENT); 1559 } 1560 1561 return (if_enqueue(tp->tp_if, m)); 1562 } 1563 1564 int 1565 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1566 { 1567 /* Just pass in the packet to our trunk device */ 1568 return (0); 1569 } 1570 1571 /* 1572 * Broadcast mode 1573 */ 1574 1575 int 1576 trunk_bcast_attach(struct trunk_softc *tr) 1577 { 1578 tr->tr_detach = trunk_bcast_detach; 1579 tr->tr_start = trunk_bcast_start; 1580 tr->tr_input = trunk_bcast_input; 1581 tr->tr_init = NULL; 1582 tr->tr_stop = NULL; 1583 tr->tr_port_create = NULL; 1584 tr->tr_port_destroy = NULL; 1585 tr->tr_linkstate = NULL; 1586 tr->tr_req = NULL; 1587 tr->tr_portreq = NULL; 1588 1589 return (0); 1590 } 1591 1592 int 1593 trunk_bcast_detach(struct trunk_softc *tr) 1594 { 1595 return (0); 1596 } 1597 1598 int 1599 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m0) 1600 { 1601 int active_ports = 0; 1602 int errors = 0; 1603 struct trunk_port *tp, *last = NULL; 1604 struct mbuf *m; 1605 1606 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1607 if (!TRUNK_PORTACTIVE(tp)) 1608 continue; 1609 1610 active_ports++; 1611 1612 if (last != NULL) { 1613 m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT); 1614 if (m == NULL) { 1615 errors++; 1616 break; 1617 } 1618 1619 if (if_enqueue(last->tp_if, m) != 0) 1620 errors++; 1621 } 1622 last = tp; 1623 } 1624 if (last == NULL) { 1625 m_freem(m0); 1626 return (ENOENT); 1627 } 1628 1629 if (if_enqueue(last->tp_if, m0) != 0) 1630 errors++; 1631 1632 if (errors == active_ports) 1633 return (ENOBUFS); 1634 1635 return (0); 1636 } 1637 1638 int 1639 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1640 { 1641 return (0); 1642 } 1643 1644 /* 1645 * 802.3ad LACP 1646 */ 1647 1648 int 1649 trunk_lacp_attach(struct trunk_softc *tr) 1650 { 1651 struct trunk_port *tp; 1652 int error; 1653 1654 tr->tr_detach = trunk_lacp_detach; 1655 tr->tr_port_create = lacp_port_create; 1656 tr->tr_port_destroy = lacp_port_destroy; 1657 tr->tr_linkstate = lacp_linkstate; 1658 tr->tr_start = trunk_lacp_start; 1659 tr->tr_input = trunk_lacp_input; 1660 tr->tr_init = lacp_init; 1661 tr->tr_stop = lacp_stop; 1662 tr->tr_req = lacp_req; 1663 tr->tr_portreq = lacp_portreq; 1664 1665 error = lacp_attach(tr); 1666 if (error) 1667 return (error); 1668 1669 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1670 lacp_port_create(tp); 1671 1672 return (error); 1673 } 1674 1675 int 1676 trunk_lacp_detach(struct trunk_softc *tr) 1677 { 1678 struct trunk_port *tp; 1679 int error; 1680 1681 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1682 lacp_port_destroy(tp); 1683 1684 /* unlocking is safe here */ 1685 error = lacp_detach(tr); 1686 1687 return (error); 1688 } 1689 1690 int 1691 trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m) 1692 { 1693 struct trunk_port *tp; 1694 1695 tp = lacp_select_tx_port(tr, m); 1696 if (tp == NULL) { 1697 m_freem(m); 1698 return (EBUSY); 1699 } 1700 1701 return (if_enqueue(tp->tp_if, m)); 1702 } 1703 1704 int 1705 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1706 { 1707 return (lacp_input(tp, m)); 1708 } 1709