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