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