1 /* $OpenBSD: if_trunk.c,v 1.127 2016/04/13 11:41:15 mpi 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 < (sizeof(trunk_protos) / 667 sizeof(trunk_protos[0])); i++) { 668 if (trunk_protos[i].ti_proto == ra->ra_proto) { 669 if (tr->tr_ifflags & IFF_DEBUG) 670 printf("%s: using proto %u\n", 671 tr->tr_ifname, 672 trunk_protos[i].ti_proto); 673 tr->tr_proto = trunk_protos[i].ti_proto; 674 if (tr->tr_proto != TRUNK_PROTO_NONE) 675 error = trunk_protos[i].ti_attach(tr); 676 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 677 if_ih_insert(tp->tp_if, 678 trunk_input, tp); 679 goto out; 680 } 681 } 682 error = EPROTONOSUPPORT; 683 break; 684 case SIOCGTRUNKPORT: 685 if (rp->rp_portname[0] == '\0' || 686 (tpif = ifunit(rp->rp_portname)) == NULL) { 687 error = EINVAL; 688 break; 689 } 690 691 /* Search in all trunks if the global flag is set */ 692 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 693 NULL : tr, tpif)) == NULL) { 694 error = ENOENT; 695 break; 696 } 697 698 trunk_port2req(tp, rp); 699 break; 700 case SIOCSTRUNKPORT: 701 if ((error = suser(curproc, 0)) != 0) { 702 error = EPERM; 703 break; 704 } 705 if (rp->rp_portname[0] == '\0' || 706 (tpif = ifunit(rp->rp_portname)) == NULL) { 707 error = EINVAL; 708 break; 709 } 710 error = trunk_port_create(tr, tpif); 711 break; 712 case SIOCSTRUNKDELPORT: 713 if ((error = suser(curproc, 0)) != 0) { 714 error = EPERM; 715 break; 716 } 717 if (rp->rp_portname[0] == '\0' || 718 (tpif = ifunit(rp->rp_portname)) == NULL) { 719 error = EINVAL; 720 break; 721 } 722 723 /* Search in all trunks if the global flag is set */ 724 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 725 NULL : tr, tpif)) == NULL) { 726 error = ENOENT; 727 break; 728 } 729 730 error = trunk_port_destroy(tp); 731 break; 732 case SIOCSIFADDR: 733 ifp->if_flags |= IFF_UP; 734 /* FALLTHROUGH */ 735 case SIOCSIFFLAGS: 736 error = ENETRESET; 737 break; 738 case SIOCADDMULTI: 739 error = trunk_ether_addmulti(tr, ifr); 740 break; 741 case SIOCDELMULTI: 742 error = trunk_ether_delmulti(tr, ifr); 743 break; 744 case SIOCSIFMEDIA: 745 case SIOCGIFMEDIA: 746 error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd); 747 break; 748 case SIOCSIFLLADDR: 749 /* Update the port lladdrs as well */ 750 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 751 trunk_port_lladdr(tp, ifr->ifr_addr.sa_data); 752 error = ENETRESET; 753 break; 754 default: 755 error = ether_ioctl(ifp, &tr->tr_ac, cmd, data); 756 } 757 758 if (error == ENETRESET) { 759 if (ifp->if_flags & IFF_UP) { 760 if ((ifp->if_flags & IFF_RUNNING) == 0) 761 trunk_init(ifp); 762 } else { 763 if (ifp->if_flags & IFF_RUNNING) 764 trunk_stop(ifp); 765 } 766 error = 0; 767 } 768 769 out: 770 splx(s); 771 return (error); 772 } 773 774 int 775 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr) 776 { 777 struct trunk_mc *mc; 778 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 779 int error; 780 781 /* Ignore ENETRESET error code */ 782 if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET) 783 return (error); 784 785 if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) { 786 error = ENOMEM; 787 goto failed; 788 } 789 790 ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 791 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm); 792 bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len); 793 SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries); 794 795 if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI, 796 (caddr_t)ifr)) != 0) { 797 trunk_ether_delmulti(tr, ifr); 798 return (error); 799 } 800 801 return (error); 802 803 failed: 804 ether_delmulti(ifr, &tr->tr_ac); 805 806 return (error); 807 } 808 809 int 810 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr) 811 { 812 struct ether_multi *enm; 813 struct trunk_mc *mc; 814 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 815 int error; 816 817 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 818 return (error); 819 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm); 820 if (enm == NULL) 821 return (EINVAL); 822 823 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) 824 if (mc->mc_enm == enm) 825 break; 826 827 /* We won't delete entries we didn't add */ 828 if (mc == NULL) 829 return (EINVAL); 830 831 if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET) 832 return (error); 833 834 /* We no longer use this multicast address. Tell parent so. */ 835 error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 836 if (error == 0) { 837 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 838 free(mc, M_DEVBUF, sizeof(*mc)); 839 } else { 840 /* XXX At least one port failed to remove the address */ 841 if (tr->tr_ifflags & IFF_DEBUG) { 842 printf("%s: failed to remove multicast address " 843 "on all ports (%d)\n", tr->tr_ifname, error); 844 } 845 (void)ether_addmulti(ifr, &tr->tr_ac); 846 } 847 848 return (0); 849 } 850 851 void 852 trunk_ether_purgemulti(struct trunk_softc *tr) 853 { 854 struct trunk_mc *mc; 855 struct trunk_ifreq ifs; 856 struct ifreq *ifr = &ifs.ifreq.ifreq; 857 858 while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) { 859 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 860 861 /* Try to remove multicast address on all ports */ 862 trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 863 864 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 865 free(mc, M_DEVBUF, sizeof(*mc)); 866 } 867 } 868 869 int 870 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd) 871 { 872 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 873 struct trunk_mc *mc; 874 struct trunk_ifreq ifs; 875 struct ifreq *ifr = &ifs.ifreq.ifreq; 876 int ret, error = 0; 877 878 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 879 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) { 880 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 881 882 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) { 883 if (tr->tr_ifflags & IFF_DEBUG) { 884 printf("%s: ioctl %lu failed on %s: %d\n", 885 tr->tr_ifname, cmd, tp->tp_ifname, ret); 886 } 887 /* Store last known error and continue */ 888 error = ret; 889 } 890 } 891 892 return (error); 893 } 894 895 int 896 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data) 897 { 898 struct ifreq *ifr = (struct ifreq *)data; 899 struct trunk_port *tp; 900 int ret, error = 0; 901 902 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 903 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 904 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) { 905 if (tr->tr_ifflags & IFF_DEBUG) { 906 printf("%s: ioctl %lu failed on %s: %d\n", 907 tr->tr_ifname, cmd, tp->tp_ifname, ret); 908 } 909 /* Store last known error and continue */ 910 error = ret; 911 } 912 } 913 914 return (error); 915 } 916 917 void 918 trunk_start(struct ifnet *ifp) 919 { 920 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 921 struct mbuf *m; 922 int error; 923 924 for (;;) { 925 IFQ_DEQUEUE(&ifp->if_snd, m); 926 if (m == NULL) 927 break; 928 929 #if NBPFILTER > 0 930 if (ifp->if_bpf) 931 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); 932 #endif 933 934 if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) { 935 error = (*tr->tr_start)(tr, m); 936 if (error == 0) 937 ifp->if_opackets++; 938 else 939 ifp->if_oerrors++; 940 } else { 941 m_freem(m); 942 if (tr->tr_proto != TRUNK_PROTO_NONE) 943 ifp->if_oerrors++; 944 } 945 } 946 } 947 948 u_int32_t 949 trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key) 950 { 951 u_int16_t etype, ether_vtag; 952 u_int32_t p = 0; 953 u_int16_t *vlan, vlanbuf[2]; 954 int off; 955 struct ether_header *eh; 956 struct ip *ip, ipbuf; 957 #ifdef INET6 958 u_int32_t flow; 959 struct ip6_hdr *ip6, ip6buf; 960 #endif 961 SIPHASH_CTX ctx; 962 963 if (m->m_pkthdr.ph_flowid & M_FLOWID_VALID) 964 return (m->m_pkthdr.ph_flowid & M_FLOWID_MASK); 965 966 SipHash24_Init(&ctx, key); 967 off = sizeof(*eh); 968 if (m->m_len < off) 969 goto done; 970 eh = mtod(m, struct ether_header *); 971 etype = ntohs(eh->ether_type); 972 SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN); 973 SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN); 974 975 /* Special handling for encapsulating VLAN frames */ 976 if (m->m_flags & M_VLANTAG) { 977 ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 978 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 979 } else if (etype == ETHERTYPE_VLAN) { 980 if ((vlan = (u_int16_t *) 981 trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL) 982 return (p); 983 ether_vtag = EVL_VLANOFTAG(*vlan); 984 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 985 etype = ntohs(vlan[1]); 986 off += EVL_ENCAPLEN; 987 } 988 989 switch (etype) { 990 case ETHERTYPE_IP: 991 if ((ip = (struct ip *) 992 trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL) 993 return (p); 994 SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr)); 995 SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr)); 996 break; 997 #ifdef INET6 998 case ETHERTYPE_IPV6: 999 if ((ip6 = (struct ip6_hdr *) 1000 trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL) 1001 return (p); 1002 SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr)); 1003 SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr)); 1004 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 1005 SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */ 1006 break; 1007 #endif 1008 } 1009 1010 done: 1011 return SipHash24_End(&ctx); 1012 } 1013 1014 void 1015 trunk_init(struct ifnet *ifp) 1016 { 1017 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1018 int s; 1019 1020 s = splnet(); 1021 1022 ifp->if_flags |= IFF_RUNNING; 1023 1024 if (tr->tr_init != NULL) 1025 (*tr->tr_init)(tr); 1026 1027 splx(s); 1028 } 1029 1030 void 1031 trunk_stop(struct ifnet *ifp) 1032 { 1033 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1034 int s; 1035 1036 s = splnet(); 1037 1038 ifp->if_flags &= ~IFF_RUNNING; 1039 1040 if (tr->tr_stop != NULL) 1041 (*tr->tr_stop)(tr); 1042 1043 splx(s); 1044 } 1045 1046 int 1047 trunk_input(struct ifnet *ifp, struct mbuf *m, void *cookie) 1048 { 1049 struct trunk_softc *tr; 1050 struct trunk_port *tp; 1051 struct ifnet *trifp = NULL; 1052 struct ether_header *eh; 1053 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1054 1055 eh = mtod(m, struct ether_header *); 1056 if (ETHER_IS_MULTICAST(eh->ether_dhost)) 1057 ifp->if_imcasts++; 1058 1059 /* Should be checked by the caller */ 1060 if (ifp->if_type != IFT_IEEE8023ADLAG) 1061 goto bad; 1062 1063 tp = (struct trunk_port *)cookie; 1064 if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL) 1065 goto bad; 1066 1067 trifp = &tr->tr_ac.ac_if; 1068 if (tr->tr_proto == TRUNK_PROTO_NONE) 1069 goto bad; 1070 1071 if ((*tr->tr_input)(tr, tp, m)) { 1072 /* 1073 * We stop here if the packet has been consumed 1074 * by the protocol routine. 1075 */ 1076 return (1); 1077 } 1078 1079 if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1080 goto bad; 1081 1082 /* 1083 * Drop promiscuously received packets if we are not in 1084 * promiscuous mode. 1085 */ 1086 if (!ETHER_IS_MULTICAST(eh->ether_dhost) && 1087 (ifp->if_flags & IFF_PROMISC) && 1088 (trifp->if_flags & IFF_PROMISC) == 0) { 1089 if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost, 1090 ETHER_ADDR_LEN)) { 1091 m_freem(m); 1092 return (1); 1093 } 1094 } 1095 1096 1097 ml_enqueue(&ml, m); 1098 if_input(trifp, &ml); 1099 return (1); 1100 1101 bad: 1102 if (trifp != NULL) 1103 trifp->if_ierrors++; 1104 m_freem(m); 1105 return (1); 1106 } 1107 1108 int 1109 trunk_media_change(struct ifnet *ifp) 1110 { 1111 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1112 1113 if (tr->tr_ifflags & IFF_DEBUG) 1114 printf("%s\n", __func__); 1115 1116 /* Ignore */ 1117 return (0); 1118 } 1119 1120 void 1121 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr) 1122 { 1123 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1124 struct trunk_port *tp; 1125 1126 imr->ifm_status = IFM_AVALID; 1127 imr->ifm_active = IFM_ETHER | IFM_AUTO; 1128 1129 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1130 if (TRUNK_PORTACTIVE(tp)) 1131 imr->ifm_status |= IFM_ACTIVE; 1132 } 1133 } 1134 1135 void 1136 trunk_port_state(void *arg) 1137 { 1138 struct trunk_port *tp = (struct trunk_port *)arg; 1139 struct trunk_softc *tr = NULL; 1140 1141 if (tp != NULL) 1142 tr = (struct trunk_softc *)tp->tp_trunk; 1143 if (tr == NULL) 1144 return; 1145 if (tr->tr_linkstate != NULL) 1146 (*tr->tr_linkstate)(tp); 1147 trunk_link_active(tr, tp); 1148 } 1149 1150 struct trunk_port * 1151 trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp) 1152 { 1153 struct trunk_port *tp_next, *rval = NULL; 1154 int new_link = LINK_STATE_DOWN; 1155 1156 /* 1157 * Search a port which reports an active link state. 1158 */ 1159 1160 if (tp == NULL) 1161 goto search; 1162 if (TRUNK_PORTACTIVE(tp)) { 1163 rval = tp; 1164 goto found; 1165 } 1166 if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL && 1167 TRUNK_PORTACTIVE(tp_next)) { 1168 rval = tp_next; 1169 goto found; 1170 } 1171 1172 search: 1173 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1174 if (TRUNK_PORTACTIVE(tp_next)) { 1175 rval = tp_next; 1176 goto found; 1177 } 1178 } 1179 1180 found: 1181 if (rval != NULL) { 1182 /* 1183 * The IEEE 802.1D standard assumes that a trunk with 1184 * multiple ports is always full duplex. This is valid 1185 * for load sharing trunks and if at least two links 1186 * are active. Unfortunately, checking the latter would 1187 * be too expensive at this point. 1188 */ 1189 if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) && 1190 (tr->tr_count > 1)) 1191 new_link = LINK_STATE_FULL_DUPLEX; 1192 else 1193 new_link = rval->tp_link_state; 1194 } 1195 1196 if (tr->tr_ac.ac_if.if_link_state != new_link) { 1197 tr->tr_ac.ac_if.if_link_state = new_link; 1198 if_link_state_change(&tr->tr_ac.ac_if); 1199 } 1200 1201 return (rval); 1202 } 1203 1204 const void * 1205 trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) 1206 { 1207 if (m->m_pkthdr.len < (off + len)) 1208 return (NULL); 1209 else if (m->m_len < (off + len)) { 1210 m_copydata(m, off, len, buf); 1211 return (buf); 1212 } 1213 return (mtod(m, caddr_t) + off); 1214 } 1215 1216 /* 1217 * Simple round robin trunking 1218 */ 1219 1220 int 1221 trunk_rr_attach(struct trunk_softc *tr) 1222 { 1223 struct trunk_port *tp; 1224 1225 tr->tr_detach = trunk_rr_detach; 1226 tr->tr_start = trunk_rr_start; 1227 tr->tr_input = trunk_rr_input; 1228 tr->tr_init = NULL; 1229 tr->tr_stop = NULL; 1230 tr->tr_linkstate = NULL; 1231 tr->tr_port_create = NULL; 1232 tr->tr_port_destroy = trunk_rr_port_destroy; 1233 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1234 tr->tr_req = NULL; 1235 tr->tr_portreq = NULL; 1236 1237 tp = SLIST_FIRST(&tr->tr_ports); 1238 tr->tr_psc = (caddr_t)tp; 1239 1240 return (0); 1241 } 1242 1243 int 1244 trunk_rr_detach(struct trunk_softc *tr) 1245 { 1246 tr->tr_psc = NULL; 1247 return (0); 1248 } 1249 1250 void 1251 trunk_rr_port_destroy(struct trunk_port *tp) 1252 { 1253 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1254 1255 if (tp == (struct trunk_port *)tr->tr_psc) 1256 tr->tr_psc = NULL; 1257 } 1258 1259 int 1260 trunk_rr_start(struct trunk_softc *tr, struct mbuf *m) 1261 { 1262 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next; 1263 int error = 0; 1264 1265 if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) { 1266 m_freem(m); 1267 return (ENOENT); 1268 } 1269 1270 if ((error = if_enqueue(tp->tp_if, m)) != 0) 1271 return (error); 1272 1273 /* Get next active port */ 1274 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1275 tr->tr_psc = (caddr_t)tp_next; 1276 1277 return (0); 1278 } 1279 1280 int 1281 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1282 { 1283 /* Just pass in the packet to our trunk device */ 1284 return (0); 1285 } 1286 1287 /* 1288 * Active failover 1289 */ 1290 1291 int 1292 trunk_fail_attach(struct trunk_softc *tr) 1293 { 1294 tr->tr_detach = trunk_fail_detach; 1295 tr->tr_start = trunk_fail_start; 1296 tr->tr_input = trunk_fail_input; 1297 tr->tr_init = NULL; 1298 tr->tr_stop = NULL; 1299 tr->tr_port_create = trunk_fail_port_create; 1300 tr->tr_port_destroy = trunk_fail_port_destroy; 1301 tr->tr_linkstate = trunk_fail_linkstate; 1302 tr->tr_req = NULL; 1303 tr->tr_portreq = NULL; 1304 1305 /* Get primary or the next active port */ 1306 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1307 1308 return (0); 1309 } 1310 1311 int 1312 trunk_fail_detach(struct trunk_softc *tr) 1313 { 1314 tr->tr_psc = NULL; 1315 return (0); 1316 } 1317 1318 int 1319 trunk_fail_port_create(struct trunk_port *tp) 1320 { 1321 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1322 1323 /* Get primary or the next active port */ 1324 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1325 return (0); 1326 } 1327 1328 void 1329 trunk_fail_port_destroy(struct trunk_port *tp) 1330 { 1331 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1332 struct trunk_port *tp_next; 1333 1334 if ((caddr_t)tp == tr->tr_psc) { 1335 /* Get the next active port */ 1336 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1337 if (tp_next == tp) 1338 tr->tr_psc = NULL; 1339 else 1340 tr->tr_psc = (caddr_t)tp_next; 1341 } else { 1342 /* Get primary or the next active port */ 1343 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1344 } 1345 } 1346 1347 int 1348 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m) 1349 { 1350 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc; 1351 1352 /* Use the master port if active or the next available port */ 1353 if (tp == NULL) { 1354 m_freem(m); 1355 return (ENOENT); 1356 } 1357 1358 return (if_enqueue(tp->tp_if, m)); 1359 } 1360 1361 int 1362 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1363 { 1364 if ((caddr_t)tp == tr->tr_psc) 1365 return (0); 1366 m_freem(m); 1367 return (-1); 1368 } 1369 1370 void 1371 trunk_fail_linkstate(struct trunk_port *tp) 1372 { 1373 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1374 1375 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1376 } 1377 1378 /* 1379 * Loadbalancing 1380 */ 1381 1382 int 1383 trunk_lb_attach(struct trunk_softc *tr) 1384 { 1385 struct trunk_lb *lb; 1386 1387 if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 1388 return (ENOMEM); 1389 1390 tr->tr_detach = trunk_lb_detach; 1391 tr->tr_start = trunk_lb_start; 1392 tr->tr_input = trunk_lb_input; 1393 tr->tr_port_create = trunk_lb_port_create; 1394 tr->tr_port_destroy = trunk_lb_port_destroy; 1395 tr->tr_linkstate = NULL; 1396 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1397 tr->tr_req = NULL; 1398 tr->tr_portreq = NULL; 1399 tr->tr_init = NULL; 1400 tr->tr_stop = NULL; 1401 1402 arc4random_buf(&lb->lb_key, sizeof(lb->lb_key)); 1403 tr->tr_psc = (caddr_t)lb; 1404 1405 return (0); 1406 } 1407 1408 int 1409 trunk_lb_detach(struct trunk_softc *tr) 1410 { 1411 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1412 1413 free(lb, M_DEVBUF, sizeof *lb); 1414 return (0); 1415 } 1416 1417 int 1418 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp) 1419 { 1420 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1421 struct trunk_port *tp_next; 1422 int i = 0; 1423 1424 bzero(&lb->lb_ports, sizeof(lb->lb_ports)); 1425 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1426 if (tp_next == tp) 1427 continue; 1428 if (i >= TRUNK_MAX_PORTS) 1429 return (EINVAL); 1430 if (tr->tr_ifflags & IFF_DEBUG) 1431 printf("%s: port %s at index %d\n", 1432 tr->tr_ifname, tp_next->tp_ifname, i); 1433 lb->lb_ports[i++] = tp_next; 1434 } 1435 1436 return (0); 1437 } 1438 1439 int 1440 trunk_lb_port_create(struct trunk_port *tp) 1441 { 1442 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1443 return (trunk_lb_porttable(tr, NULL)); 1444 } 1445 1446 void 1447 trunk_lb_port_destroy(struct trunk_port *tp) 1448 { 1449 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1450 trunk_lb_porttable(tr, tp); 1451 } 1452 1453 int 1454 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m) 1455 { 1456 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1457 struct trunk_port *tp = NULL; 1458 u_int32_t p = 0; 1459 1460 p = trunk_hashmbuf(m, &lb->lb_key); 1461 p %= tr->tr_count; 1462 tp = lb->lb_ports[p]; 1463 1464 /* 1465 * Check the port's link state. This will return the next active 1466 * port if the link is down or the port is NULL. 1467 */ 1468 if ((tp = trunk_link_active(tr, tp)) == NULL) { 1469 m_freem(m); 1470 return (ENOENT); 1471 } 1472 1473 return (if_enqueue(tp->tp_if, m)); 1474 } 1475 1476 int 1477 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1478 { 1479 /* Just pass in the packet to our trunk device */ 1480 return (0); 1481 } 1482 1483 /* 1484 * Broadcast mode 1485 */ 1486 1487 int 1488 trunk_bcast_attach(struct trunk_softc *tr) 1489 { 1490 tr->tr_detach = trunk_bcast_detach; 1491 tr->tr_start = trunk_bcast_start; 1492 tr->tr_input = trunk_bcast_input; 1493 tr->tr_init = NULL; 1494 tr->tr_stop = NULL; 1495 tr->tr_port_create = NULL; 1496 tr->tr_port_destroy = NULL; 1497 tr->tr_linkstate = NULL; 1498 tr->tr_req = NULL; 1499 tr->tr_portreq = NULL; 1500 1501 return (0); 1502 } 1503 1504 int 1505 trunk_bcast_detach(struct trunk_softc *tr) 1506 { 1507 return (0); 1508 } 1509 1510 int 1511 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m0) 1512 { 1513 int active_ports = 0; 1514 int errors = 0; 1515 int ret; 1516 struct trunk_port *tp, *last = NULL; 1517 struct mbuf *m; 1518 1519 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1520 if (!TRUNK_PORTACTIVE(tp)) 1521 continue; 1522 1523 active_ports++; 1524 1525 if (last != NULL) { 1526 m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT); 1527 if (m == NULL) { 1528 ret = ENOBUFS; 1529 errors++; 1530 break; 1531 } 1532 1533 ret = if_enqueue(last->tp_if, m); 1534 if (ret != 0) 1535 errors++; 1536 } 1537 last = tp; 1538 } 1539 if (last == NULL) { 1540 m_freem(m0); 1541 return (ENOENT); 1542 } 1543 1544 ret = if_enqueue(last->tp_if, m0); 1545 if (ret != 0) 1546 errors++; 1547 1548 if (errors == active_ports) 1549 return (ret); 1550 1551 return (0); 1552 } 1553 1554 int 1555 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1556 { 1557 return (0); 1558 } 1559 1560 /* 1561 * 802.3ad LACP 1562 */ 1563 1564 int 1565 trunk_lacp_attach(struct trunk_softc *tr) 1566 { 1567 struct trunk_port *tp; 1568 int error; 1569 1570 tr->tr_detach = trunk_lacp_detach; 1571 tr->tr_port_create = lacp_port_create; 1572 tr->tr_port_destroy = lacp_port_destroy; 1573 tr->tr_linkstate = lacp_linkstate; 1574 tr->tr_start = trunk_lacp_start; 1575 tr->tr_input = trunk_lacp_input; 1576 tr->tr_init = lacp_init; 1577 tr->tr_stop = lacp_stop; 1578 tr->tr_req = lacp_req; 1579 tr->tr_portreq = lacp_portreq; 1580 1581 error = lacp_attach(tr); 1582 if (error) 1583 return (error); 1584 1585 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1586 lacp_port_create(tp); 1587 1588 return (error); 1589 } 1590 1591 int 1592 trunk_lacp_detach(struct trunk_softc *tr) 1593 { 1594 struct trunk_port *tp; 1595 int error; 1596 1597 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1598 lacp_port_destroy(tp); 1599 1600 /* unlocking is safe here */ 1601 error = lacp_detach(tr); 1602 1603 return (error); 1604 } 1605 1606 int 1607 trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m) 1608 { 1609 struct trunk_port *tp; 1610 1611 tp = lacp_select_tx_port(tr, m); 1612 if (tp == NULL) { 1613 m_freem(m); 1614 return (EBUSY); 1615 } 1616 1617 return (if_enqueue(tp->tp_if, m)); 1618 } 1619 1620 int 1621 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1622 { 1623 return (lacp_input(tp, m)); 1624 } 1625