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