1 /* $OpenBSD: if_trunk.c,v 1.144 2019/12/06 02:02:18 dlg 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 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_counters_alloc(ifp); 198 if_attach(ifp); 199 ether_ifattach(ifp); 200 201 /* Insert into the global list of trunks */ 202 SLIST_INSERT_HEAD(&trunk_list, tr, tr_entries); 203 204 return (0); 205 } 206 207 int 208 trunk_clone_destroy(struct ifnet *ifp) 209 { 210 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 211 struct trunk_port *tp; 212 int error; 213 214 /* Remove any multicast groups that we may have joined. */ 215 trunk_ether_purgemulti(tr); 216 217 /* Shutdown and remove trunk ports, return on error */ 218 NET_LOCK(); 219 while ((tp = SLIST_FIRST(&tr->tr_ports)) != NULL) { 220 if ((error = trunk_port_destroy(tp)) != 0) { 221 NET_UNLOCK(); 222 return (error); 223 } 224 } 225 NET_UNLOCK(); 226 227 ifmedia_delete_instance(&tr->tr_media, IFM_INST_ANY); 228 ether_ifdetach(ifp); 229 if_detach(ifp); 230 231 SLIST_REMOVE(&trunk_list, tr, trunk_softc, tr_entries); 232 free(tr, M_DEVBUF, sizeof *tr); 233 234 return (0); 235 } 236 237 void 238 trunk_lladdr(struct arpcom *ac, u_int8_t *lladdr) 239 { 240 struct ifnet *ifp = &ac->ac_if; 241 struct sockaddr_dl *sdl; 242 243 sdl = ifp->if_sadl; 244 sdl->sdl_type = IFT_ETHER; 245 sdl->sdl_alen = ETHER_ADDR_LEN; 246 bcopy(lladdr, LLADDR(sdl), ETHER_ADDR_LEN); 247 bcopy(lladdr, ac->ac_enaddr, ETHER_ADDR_LEN); 248 } 249 250 int 251 trunk_capabilities(struct trunk_softc *tr) 252 { 253 struct trunk_port *tp; 254 int cap = ~0, priv; 255 256 /* Preserve private capabilities */ 257 priv = tr->tr_capabilities & IFCAP_TRUNK_MASK; 258 259 /* Get capabilities from the trunk ports */ 260 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 261 cap &= tp->tp_capabilities; 262 263 if (tr->tr_ifflags & IFF_DEBUG) { 264 printf("%s: capabilities 0x%08x\n", 265 tr->tr_ifname, cap == ~0 ? priv : (cap | priv)); 266 } 267 268 return (cap == ~0 ? priv : (cap | priv)); 269 } 270 271 void 272 trunk_port_lladdr(struct trunk_port *tp, u_int8_t *lladdr) 273 { 274 struct ifnet *ifp = tp->tp_if; 275 276 /* Set the link layer address */ 277 trunk_lladdr((struct arpcom *)ifp, lladdr); 278 279 /* Reset the port to update the lladdr */ 280 ifnewlladdr(ifp); 281 } 282 283 int 284 trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp) 285 { 286 struct trunk_softc *tr_ptr; 287 struct trunk_port *tp; 288 struct arpcom *ac0; 289 int error = 0; 290 291 /* Limit the maximal number of trunk ports */ 292 if (tr->tr_count >= TRUNK_MAX_PORTS) 293 return (ENOSPC); 294 295 /* Check if port has already been associated to a trunk */ 296 if (trunk_port_get(NULL, ifp) != NULL) 297 return (EBUSY); 298 299 /* XXX Disallow non-ethernet interfaces (this should be any of 802) */ 300 if (ifp->if_type != IFT_ETHER) 301 return (EPROTONOSUPPORT); 302 303 ac0 = (struct arpcom *)ifp; 304 if (ac0->ac_trunkport != NULL) 305 return (EBUSY); 306 307 /* Take MTU from the first member port */ 308 if (SLIST_EMPTY(&tr->tr_ports)) { 309 if (tr->tr_ifflags & IFF_DEBUG) 310 printf("%s: first port, setting trunk mtu %u\n", 311 tr->tr_ifname, ifp->if_mtu); 312 tr->tr_ac.ac_if.if_mtu = ifp->if_mtu; 313 tr->tr_ac.ac_if.if_hardmtu = ifp->if_hardmtu; 314 } else if (tr->tr_ac.ac_if.if_mtu != ifp->if_mtu) { 315 printf("%s: adding %s failed, MTU %u != %u\n", tr->tr_ifname, 316 ifp->if_xname, ifp->if_mtu, tr->tr_ac.ac_if.if_mtu); 317 return (EINVAL); 318 } 319 320 if ((error = ifpromisc(ifp, 1)) != 0) 321 return (error); 322 323 if ((tp = malloc(sizeof *tp, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 324 return (ENOMEM); 325 326 /* Check if port is a stacked trunk */ 327 SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) { 328 if (ifp == &tr_ptr->tr_ac.ac_if) { 329 tp->tp_flags |= TRUNK_PORT_STACK; 330 if (trunk_port_checkstacking(tr_ptr) >= 331 TRUNK_MAX_STACKING) { 332 free(tp, M_DEVBUF, sizeof *tp); 333 return (E2BIG); 334 } 335 } 336 } 337 338 /* Change the interface type */ 339 tp->tp_iftype = ifp->if_type; 340 ifp->if_type = IFT_IEEE8023ADLAG; 341 342 tp->tp_ioctl = ifp->if_ioctl; 343 ifp->if_ioctl = trunk_port_ioctl; 344 345 tp->tp_output = ifp->if_output; 346 ifp->if_output = trunk_port_output; 347 348 tp->tp_if = ifp; 349 tp->tp_trunk = tr; 350 351 /* Save port link layer address */ 352 bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN); 353 354 if (SLIST_EMPTY(&tr->tr_ports)) { 355 tr->tr_primary = tp; 356 tp->tp_flags |= TRUNK_PORT_MASTER; 357 trunk_lladdr(&tr->tr_ac, tp->tp_lladdr); 358 } 359 360 /* Insert into the list of ports */ 361 SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries); 362 tr->tr_count++; 363 364 /* Update link layer address for this port */ 365 trunk_port_lladdr(tp, 366 ((struct arpcom *)(tr->tr_primary->tp_if))->ac_enaddr); 367 368 /* Update trunk capabilities */ 369 tr->tr_capabilities = trunk_capabilities(tr); 370 371 /* Add multicast addresses to this port */ 372 trunk_ether_cmdmulti(tp, SIOCADDMULTI); 373 374 /* Register callback for physical link state changes */ 375 task_set(&tp->tp_ltask, trunk_port_state, tp); 376 if_linkstatehook_add(ifp, &tp->tp_ltask); 377 378 /* Register callback if parent wants to unregister */ 379 task_set(&tp->tp_dtask, trunk_port_ifdetach, tp); 380 if_detachhook_add(ifp, &tp->tp_dtask); 381 382 if (tr->tr_port_create != NULL) 383 error = (*tr->tr_port_create)(tp); 384 385 ac0->ac_trunkport = tp; 386 /* Change input handler of the physical interface. */ 387 if_ih_insert(ifp, trunk_input, tp); 388 389 return (error); 390 } 391 392 int 393 trunk_port_checkstacking(struct trunk_softc *tr) 394 { 395 struct trunk_softc *tr_ptr; 396 struct trunk_port *tp; 397 int m = 0; 398 399 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 400 if (tp->tp_flags & TRUNK_PORT_STACK) { 401 tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc; 402 m = MAX(m, trunk_port_checkstacking(tr_ptr)); 403 } 404 } 405 406 return (m + 1); 407 } 408 409 int 410 trunk_port_destroy(struct trunk_port *tp) 411 { 412 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 413 struct trunk_port *tp_ptr; 414 struct ifnet *ifp = tp->tp_if; 415 struct arpcom *ac0 = (struct arpcom *)ifp; 416 417 /* Restore previous input handler. */ 418 if_ih_remove(ifp, trunk_input, tp); 419 ac0->ac_trunkport = NULL; 420 421 /* Remove multicast addresses from this port */ 422 trunk_ether_cmdmulti(tp, SIOCDELMULTI); 423 424 /* Port has to be down */ 425 if (ifp->if_flags & IFF_UP) 426 if_down(ifp); 427 428 ifpromisc(ifp, 0); 429 430 if (tr->tr_port_destroy != NULL) 431 (*tr->tr_port_destroy)(tp); 432 433 /* Restore interface type. */ 434 ifp->if_type = tp->tp_iftype; 435 436 ifp->if_ioctl = tp->tp_ioctl; 437 ifp->if_output = tp->tp_output; 438 439 if_detachhook_del(ifp, &tp->tp_dtask); 440 if_linkstatehook_del(ifp, &tp->tp_ltask); 441 442 /* Finally, remove the port from the trunk */ 443 SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries); 444 tr->tr_count--; 445 446 /* Update the primary interface */ 447 if (tp == tr->tr_primary) { 448 u_int8_t lladdr[ETHER_ADDR_LEN]; 449 450 if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) { 451 bzero(&lladdr, ETHER_ADDR_LEN); 452 } else { 453 bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr, 454 lladdr, ETHER_ADDR_LEN); 455 tp_ptr->tp_flags = TRUNK_PORT_MASTER; 456 } 457 trunk_lladdr(&tr->tr_ac, lladdr); 458 tr->tr_primary = tp_ptr; 459 460 /* Update link layer address for each port */ 461 SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries) 462 trunk_port_lladdr(tp_ptr, lladdr); 463 } 464 465 /* Reset the port lladdr */ 466 trunk_port_lladdr(tp, tp->tp_lladdr); 467 468 free(tp, M_DEVBUF, sizeof *tp); 469 470 /* Update trunk capabilities */ 471 tr->tr_capabilities = trunk_capabilities(tr); 472 473 return (0); 474 } 475 476 int 477 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 478 { 479 struct trunk_reqport *rp = (struct trunk_reqport *)data; 480 struct trunk_softc *tr; 481 struct trunk_port *tp = NULL; 482 int error = 0; 483 484 /* Should be checked by the caller */ 485 if (ifp->if_type != IFT_IEEE8023ADLAG || 486 (tp = trunk_port_get(NULL, ifp)) == NULL || 487 (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) { 488 error = EINVAL; 489 goto fallback; 490 } 491 492 switch (cmd) { 493 case SIOCGTRUNKPORT: 494 if (rp->rp_portname[0] == '\0' || 495 ifunit(rp->rp_portname) != ifp) { 496 error = EINVAL; 497 break; 498 } 499 500 /* Search in all trunks if the global flag is set */ 501 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 502 NULL : tr, ifp)) == NULL) { 503 error = ENOENT; 504 break; 505 } 506 507 trunk_port2req(tp, rp); 508 break; 509 case SIOCSIFMTU: 510 /* Do not allow the MTU to be changed once joined */ 511 error = EINVAL; 512 break; 513 default: 514 error = ENOTTY; 515 goto fallback; 516 } 517 518 return (error); 519 520 fallback: 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 trunk_opts *tro = (struct trunk_opts *)data; 617 struct ifreq *ifr = (struct ifreq *)data; 618 struct lacp_softc *lsc; 619 struct trunk_port *tp; 620 struct lacp_port *lp; 621 struct ifnet *tpif; 622 int i, error = 0; 623 624 bzero(&rpbuf, sizeof(rpbuf)); 625 626 switch (cmd) { 627 case SIOCGTRUNK: 628 ra->ra_proto = tr->tr_proto; 629 if (tr->tr_req != NULL) 630 (*tr->tr_req)(tr, (caddr_t)&ra->ra_psc); 631 ra->ra_ports = i = 0; 632 tp = SLIST_FIRST(&tr->tr_ports); 633 while (tp && ra->ra_size >= 634 i + sizeof(struct trunk_reqport)) { 635 trunk_port2req(tp, &rpbuf); 636 error = copyout(&rpbuf, (caddr_t)ra->ra_port + i, 637 sizeof(struct trunk_reqport)); 638 if (error) 639 break; 640 i += sizeof(struct trunk_reqport); 641 ra->ra_ports++; 642 tp = SLIST_NEXT(tp, tp_entries); 643 } 644 break; 645 case SIOCSTRUNK: 646 if ((error = suser(curproc)) != 0) { 647 error = EPERM; 648 break; 649 } 650 if (ra->ra_proto >= TRUNK_PROTO_MAX) { 651 error = EPROTONOSUPPORT; 652 break; 653 } 654 /* 655 * Serialize modifications to the trunk and trunk 656 * ports via the ifih SRP: detaching trunk_input 657 * from the trunk port will require all currently 658 * running trunk_input's on this port to finish 659 * granting us an exclusive access to it. 660 */ 661 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 662 if_ih_remove(tp->tp_if, trunk_input, tp); 663 if (tr->tr_proto != TRUNK_PROTO_NONE) 664 error = tr->tr_detach(tr); 665 if (error != 0) 666 break; 667 for (i = 0; i < nitems(trunk_protos); 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 /* Update trunk capabilities */ 680 tr->tr_capabilities = trunk_capabilities(tr); 681 goto out; 682 } 683 } 684 error = EPROTONOSUPPORT; 685 break; 686 case SIOCGTRUNKOPTS: 687 /* Only LACP trunks have options atm */ 688 if (tro->to_proto != TRUNK_PROTO_LACP) { 689 error = EPROTONOSUPPORT; 690 break; 691 } 692 lsc = LACP_SOFTC(tr); 693 tro->to_lacpopts.lacp_mode = lsc->lsc_mode; 694 tro->to_lacpopts.lacp_timeout = lsc->lsc_timeout; 695 tro->to_lacpopts.lacp_prio = lsc->lsc_sys_prio; 696 tro->to_lacpopts.lacp_portprio = lsc->lsc_port_prio; 697 tro->to_lacpopts.lacp_ifqprio = lsc->lsc_ifq_prio; 698 break; 699 case SIOCSTRUNKOPTS: 700 if ((error = suser(curproc)) != 0) { 701 error = EPERM; 702 break; 703 } 704 /* Only LACP trunks have options atm */ 705 if (tro->to_proto != TRUNK_PROTO_LACP) { 706 error = EPROTONOSUPPORT; 707 break; 708 } 709 lsc = LACP_SOFTC(tr); 710 switch(tro->to_opts) { 711 case TRUNK_OPT_LACP_MODE: 712 /* 713 * Ensure mode changes occur immediately 714 * on all ports 715 */ 716 lsc->lsc_mode = tro->to_lacpopts.lacp_mode; 717 if (lsc->lsc_mode == 0) { 718 LIST_FOREACH(lp, &lsc->lsc_ports, 719 lp_next) 720 lp->lp_state &= 721 ~LACP_STATE_ACTIVITY; 722 } else { 723 LIST_FOREACH(lp, &lsc->lsc_ports, 724 lp_next) 725 lp->lp_state |= 726 LACP_STATE_ACTIVITY; 727 } 728 break; 729 case TRUNK_OPT_LACP_TIMEOUT: 730 /* 731 * Ensure timeout changes occur immediately 732 * on all ports 733 */ 734 lsc->lsc_timeout = 735 tro->to_lacpopts.lacp_timeout; 736 if (lsc->lsc_timeout == 0) { 737 LIST_FOREACH(lp, &lsc->lsc_ports, 738 lp_next) 739 lp->lp_state &= 740 ~LACP_STATE_TIMEOUT; 741 } else { 742 LIST_FOREACH(lp, &lsc->lsc_ports, 743 lp_next) 744 lp->lp_state |= 745 LACP_STATE_TIMEOUT; 746 } 747 break; 748 case TRUNK_OPT_LACP_SYS_PRIO: 749 if (tro->to_lacpopts.lacp_prio == 0) { 750 error = EINVAL; 751 break; 752 } 753 lsc->lsc_sys_prio = tro->to_lacpopts.lacp_prio; 754 break; 755 case TRUNK_OPT_LACP_PORT_PRIO: 756 if (tro->to_lacpopts.lacp_portprio == 0) { 757 error = EINVAL; 758 break; 759 } 760 lsc->lsc_port_prio = 761 tro->to_lacpopts.lacp_portprio; 762 break; 763 case TRUNK_OPT_LACP_IFQ_PRIO: 764 if (tro->to_lacpopts.lacp_ifqprio > 765 IFQ_MAXPRIO) { 766 error = EINVAL; 767 break; 768 } 769 lsc->lsc_ifq_prio = 770 tro->to_lacpopts.lacp_ifqprio; 771 break; 772 } 773 break; 774 case SIOCGTRUNKPORT: 775 if (rp->rp_portname[0] == '\0' || 776 (tpif = ifunit(rp->rp_portname)) == NULL) { 777 error = EINVAL; 778 break; 779 } 780 781 /* Search in all trunks if the global flag is set */ 782 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 783 NULL : tr, tpif)) == NULL) { 784 error = ENOENT; 785 break; 786 } 787 788 trunk_port2req(tp, rp); 789 break; 790 case SIOCSTRUNKPORT: 791 if ((error = suser(curproc)) != 0) { 792 error = EPERM; 793 break; 794 } 795 if (rp->rp_portname[0] == '\0' || 796 (tpif = ifunit(rp->rp_portname)) == NULL) { 797 error = EINVAL; 798 break; 799 } 800 error = trunk_port_create(tr, tpif); 801 break; 802 case SIOCSTRUNKDELPORT: 803 if ((error = suser(curproc)) != 0) { 804 error = EPERM; 805 break; 806 } 807 if (rp->rp_portname[0] == '\0' || 808 (tpif = ifunit(rp->rp_portname)) == NULL) { 809 error = EINVAL; 810 break; 811 } 812 813 /* Search in all trunks if the global flag is set */ 814 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 815 NULL : tr, tpif)) == NULL) { 816 error = ENOENT; 817 break; 818 } 819 820 error = trunk_port_destroy(tp); 821 break; 822 case SIOCSIFADDR: 823 ifp->if_flags |= IFF_UP; 824 /* FALLTHROUGH */ 825 case SIOCSIFFLAGS: 826 error = ENETRESET; 827 break; 828 case SIOCADDMULTI: 829 error = trunk_ether_addmulti(tr, ifr); 830 break; 831 case SIOCDELMULTI: 832 error = trunk_ether_delmulti(tr, ifr); 833 break; 834 case SIOCSIFMEDIA: 835 case SIOCGIFMEDIA: 836 error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd); 837 break; 838 case SIOCSIFLLADDR: 839 /* Update the port lladdrs as well */ 840 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 841 trunk_port_lladdr(tp, ifr->ifr_addr.sa_data); 842 error = ENETRESET; 843 break; 844 default: 845 error = ether_ioctl(ifp, &tr->tr_ac, cmd, data); 846 } 847 848 if (error == ENETRESET) { 849 if (ifp->if_flags & IFF_UP) { 850 if ((ifp->if_flags & IFF_RUNNING) == 0) 851 trunk_init(ifp); 852 } else { 853 if (ifp->if_flags & IFF_RUNNING) 854 trunk_stop(ifp); 855 } 856 error = 0; 857 } 858 859 out: 860 return (error); 861 } 862 863 int 864 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr) 865 { 866 struct trunk_mc *mc; 867 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 868 int error; 869 870 /* Ignore ENETRESET error code */ 871 if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET) 872 return (error); 873 874 if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) { 875 error = ENOMEM; 876 goto failed; 877 } 878 879 ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 880 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm); 881 bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len); 882 SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries); 883 884 if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI, 885 (caddr_t)ifr)) != 0) { 886 trunk_ether_delmulti(tr, ifr); 887 return (error); 888 } 889 890 return (error); 891 892 failed: 893 ether_delmulti(ifr, &tr->tr_ac); 894 895 return (error); 896 } 897 898 int 899 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr) 900 { 901 struct ether_multi *enm; 902 struct trunk_mc *mc; 903 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 904 int error; 905 906 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 907 return (error); 908 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm); 909 if (enm == NULL) 910 return (EINVAL); 911 912 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) 913 if (mc->mc_enm == enm) 914 break; 915 916 /* We won't delete entries we didn't add */ 917 if (mc == NULL) 918 return (EINVAL); 919 920 if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET) 921 return (error); 922 923 /* We no longer use this multicast address. Tell parent so. */ 924 error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 925 if (error == 0) { 926 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 927 free(mc, M_DEVBUF, sizeof(*mc)); 928 } else { 929 /* XXX At least one port failed to remove the address */ 930 if (tr->tr_ifflags & IFF_DEBUG) { 931 printf("%s: failed to remove multicast address " 932 "on all ports (%d)\n", tr->tr_ifname, error); 933 } 934 (void)ether_addmulti(ifr, &tr->tr_ac); 935 } 936 937 return (0); 938 } 939 940 void 941 trunk_ether_purgemulti(struct trunk_softc *tr) 942 { 943 struct trunk_mc *mc; 944 struct trunk_ifreq ifs; 945 struct ifreq *ifr = &ifs.ifreq.ifreq; 946 947 while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) { 948 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 949 950 /* Try to remove multicast address on all ports */ 951 trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 952 953 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 954 free(mc, M_DEVBUF, sizeof(*mc)); 955 } 956 } 957 958 int 959 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd) 960 { 961 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 962 struct trunk_mc *mc; 963 struct trunk_ifreq ifs; 964 struct ifreq *ifr = &ifs.ifreq.ifreq; 965 int ret, error = 0; 966 967 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 968 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) { 969 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 970 971 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) { 972 if (tr->tr_ifflags & IFF_DEBUG) { 973 printf("%s: ioctl %lu failed on %s: %d\n", 974 tr->tr_ifname, cmd, tp->tp_ifname, ret); 975 } 976 /* Store last known error and continue */ 977 error = ret; 978 } 979 } 980 981 return (error); 982 } 983 984 int 985 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data) 986 { 987 struct ifreq *ifr = (struct ifreq *)data; 988 struct trunk_port *tp; 989 int ret, error = 0; 990 991 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 992 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 993 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) { 994 if (tr->tr_ifflags & IFF_DEBUG) { 995 printf("%s: ioctl %lu failed on %s: %d\n", 996 tr->tr_ifname, cmd, tp->tp_ifname, ret); 997 } 998 /* Store last known error and continue */ 999 error = ret; 1000 } 1001 } 1002 1003 return (error); 1004 } 1005 1006 void 1007 trunk_start(struct ifnet *ifp) 1008 { 1009 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1010 struct mbuf *m; 1011 int error; 1012 1013 for (;;) { 1014 IFQ_DEQUEUE(&ifp->if_snd, m); 1015 if (m == NULL) 1016 break; 1017 1018 #if NBPFILTER > 0 1019 if (ifp->if_bpf) 1020 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1021 #endif 1022 1023 if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) { 1024 error = (*tr->tr_start)(tr, m); 1025 if (error != 0) 1026 ifp->if_oerrors++; 1027 } else { 1028 m_freem(m); 1029 if (tr->tr_proto != TRUNK_PROTO_NONE) 1030 ifp->if_oerrors++; 1031 } 1032 } 1033 } 1034 1035 u_int32_t 1036 trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key) 1037 { 1038 u_int16_t etype, ether_vtag; 1039 u_int32_t p = 0; 1040 u_int16_t *vlan, vlanbuf[2]; 1041 int off; 1042 struct ether_header *eh; 1043 struct ip *ip, ipbuf; 1044 #ifdef INET6 1045 u_int32_t flow; 1046 struct ip6_hdr *ip6, ip6buf; 1047 #endif 1048 SIPHASH_CTX ctx; 1049 1050 if (m->m_pkthdr.ph_flowid & M_FLOWID_VALID) 1051 return (m->m_pkthdr.ph_flowid & M_FLOWID_MASK); 1052 1053 SipHash24_Init(&ctx, key); 1054 off = sizeof(*eh); 1055 if (m->m_len < off) 1056 goto done; 1057 eh = mtod(m, struct ether_header *); 1058 etype = ntohs(eh->ether_type); 1059 SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN); 1060 SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN); 1061 1062 /* Special handling for encapsulating VLAN frames */ 1063 if (m->m_flags & M_VLANTAG) { 1064 ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 1065 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1066 } else if (etype == ETHERTYPE_VLAN) { 1067 if ((vlan = (u_int16_t *) 1068 trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL) 1069 return (p); 1070 ether_vtag = EVL_VLANOFTAG(*vlan); 1071 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1072 etype = ntohs(vlan[1]); 1073 off += EVL_ENCAPLEN; 1074 } 1075 1076 switch (etype) { 1077 case ETHERTYPE_IP: 1078 if ((ip = (struct ip *) 1079 trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL) 1080 return (p); 1081 SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr)); 1082 SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr)); 1083 break; 1084 #ifdef INET6 1085 case ETHERTYPE_IPV6: 1086 if ((ip6 = (struct ip6_hdr *) 1087 trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL) 1088 return (p); 1089 SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr)); 1090 SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr)); 1091 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 1092 SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */ 1093 break; 1094 #endif 1095 } 1096 1097 done: 1098 return SipHash24_End(&ctx); 1099 } 1100 1101 void 1102 trunk_init(struct ifnet *ifp) 1103 { 1104 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1105 1106 ifp->if_flags |= IFF_RUNNING; 1107 1108 if (tr->tr_init != NULL) 1109 (*tr->tr_init)(tr); 1110 } 1111 1112 void 1113 trunk_stop(struct ifnet *ifp) 1114 { 1115 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1116 1117 ifp->if_flags &= ~IFF_RUNNING; 1118 1119 if (tr->tr_stop != NULL) 1120 (*tr->tr_stop)(tr); 1121 } 1122 1123 int 1124 trunk_input(struct ifnet *ifp, struct mbuf *m, void *cookie) 1125 { 1126 struct trunk_softc *tr; 1127 struct trunk_port *tp; 1128 struct ifnet *trifp = NULL; 1129 struct ether_header *eh; 1130 1131 eh = mtod(m, struct ether_header *); 1132 if (ETHER_IS_MULTICAST(eh->ether_dhost)) 1133 ifp->if_imcasts++; 1134 1135 /* Should be checked by the caller */ 1136 if (ifp->if_type != IFT_IEEE8023ADLAG) 1137 goto bad; 1138 1139 tp = (struct trunk_port *)cookie; 1140 if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL) 1141 goto bad; 1142 1143 trifp = &tr->tr_ac.ac_if; 1144 if (tr->tr_proto == TRUNK_PROTO_NONE) 1145 goto bad; 1146 1147 if ((*tr->tr_input)(tr, tp, m)) { 1148 /* 1149 * We stop here if the packet has been consumed 1150 * by the protocol routine. 1151 */ 1152 return (1); 1153 } 1154 1155 if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1156 goto bad; 1157 1158 /* 1159 * Drop promiscuously received packets if we are not in 1160 * promiscuous mode. 1161 */ 1162 if (!ETHER_IS_MULTICAST(eh->ether_dhost) && 1163 (ifp->if_flags & IFF_PROMISC) && 1164 (trifp->if_flags & IFF_PROMISC) == 0) { 1165 if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost, 1166 ETHER_ADDR_LEN)) { 1167 m_freem(m); 1168 return (1); 1169 } 1170 } 1171 1172 1173 if_vinput(trifp, m); 1174 return (1); 1175 1176 bad: 1177 if (trifp != NULL) 1178 trifp->if_ierrors++; 1179 m_freem(m); 1180 return (1); 1181 } 1182 1183 int 1184 trunk_media_change(struct ifnet *ifp) 1185 { 1186 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1187 1188 if (tr->tr_ifflags & IFF_DEBUG) 1189 printf("%s\n", __func__); 1190 1191 /* Ignore */ 1192 return (0); 1193 } 1194 1195 void 1196 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr) 1197 { 1198 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1199 struct trunk_port *tp; 1200 1201 imr->ifm_status = IFM_AVALID; 1202 imr->ifm_active = IFM_ETHER | IFM_AUTO; 1203 1204 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1205 if (TRUNK_PORTACTIVE(tp)) 1206 imr->ifm_status |= IFM_ACTIVE; 1207 } 1208 } 1209 1210 void 1211 trunk_port_state(void *arg) 1212 { 1213 struct trunk_port *tp = (struct trunk_port *)arg; 1214 struct trunk_softc *tr = NULL; 1215 1216 if (tp != NULL) 1217 tr = (struct trunk_softc *)tp->tp_trunk; 1218 if (tr == NULL) 1219 return; 1220 if (tr->tr_linkstate != NULL) 1221 (*tr->tr_linkstate)(tp); 1222 trunk_link_active(tr, tp); 1223 rtm_ifchg(&tr->tr_ac.ac_if); 1224 } 1225 1226 struct trunk_port * 1227 trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp) 1228 { 1229 struct trunk_port *tp_next, *rval = NULL; 1230 int new_link = LINK_STATE_DOWN; 1231 1232 /* 1233 * Search a port which reports an active link state. 1234 */ 1235 1236 if (tp == NULL) 1237 goto search; 1238 if (TRUNK_PORTACTIVE(tp)) { 1239 rval = tp; 1240 goto found; 1241 } 1242 if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL && 1243 TRUNK_PORTACTIVE(tp_next)) { 1244 rval = tp_next; 1245 goto found; 1246 } 1247 1248 search: 1249 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1250 if (TRUNK_PORTACTIVE(tp_next)) { 1251 rval = tp_next; 1252 goto found; 1253 } 1254 } 1255 1256 found: 1257 if (rval != NULL) { 1258 /* 1259 * The IEEE 802.1D standard assumes that a trunk with 1260 * multiple ports is always full duplex. This is valid 1261 * for load sharing trunks and if at least two links 1262 * are active. Unfortunately, checking the latter would 1263 * be too expensive at this point. 1264 */ 1265 if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) && 1266 (tr->tr_count > 1)) 1267 new_link = LINK_STATE_FULL_DUPLEX; 1268 else 1269 new_link = rval->tp_link_state; 1270 } 1271 1272 if (tr->tr_ac.ac_if.if_link_state != new_link) { 1273 tr->tr_ac.ac_if.if_link_state = new_link; 1274 if_link_state_change(&tr->tr_ac.ac_if); 1275 } 1276 1277 return (rval); 1278 } 1279 1280 const void * 1281 trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) 1282 { 1283 if (m->m_pkthdr.len < (off + len)) 1284 return (NULL); 1285 else if (m->m_len < (off + len)) { 1286 m_copydata(m, off, len, buf); 1287 return (buf); 1288 } 1289 return (mtod(m, caddr_t) + off); 1290 } 1291 1292 /* 1293 * Simple round robin trunking 1294 */ 1295 1296 int 1297 trunk_rr_attach(struct trunk_softc *tr) 1298 { 1299 struct trunk_port *tp; 1300 1301 tr->tr_detach = trunk_rr_detach; 1302 tr->tr_start = trunk_rr_start; 1303 tr->tr_input = trunk_rr_input; 1304 tr->tr_init = NULL; 1305 tr->tr_stop = NULL; 1306 tr->tr_linkstate = NULL; 1307 tr->tr_port_create = NULL; 1308 tr->tr_port_destroy = trunk_rr_port_destroy; 1309 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1310 tr->tr_req = NULL; 1311 tr->tr_portreq = NULL; 1312 1313 tp = SLIST_FIRST(&tr->tr_ports); 1314 tr->tr_psc = (caddr_t)tp; 1315 1316 return (0); 1317 } 1318 1319 int 1320 trunk_rr_detach(struct trunk_softc *tr) 1321 { 1322 tr->tr_psc = NULL; 1323 return (0); 1324 } 1325 1326 void 1327 trunk_rr_port_destroy(struct trunk_port *tp) 1328 { 1329 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1330 1331 if (tp == (struct trunk_port *)tr->tr_psc) 1332 tr->tr_psc = NULL; 1333 } 1334 1335 int 1336 trunk_rr_start(struct trunk_softc *tr, struct mbuf *m) 1337 { 1338 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next; 1339 int error = 0; 1340 1341 if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) { 1342 m_freem(m); 1343 return (ENOENT); 1344 } 1345 1346 if ((error = if_enqueue(tp->tp_if, m)) != 0) 1347 return (error); 1348 1349 /* Get next active port */ 1350 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1351 tr->tr_psc = (caddr_t)tp_next; 1352 1353 return (0); 1354 } 1355 1356 int 1357 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1358 { 1359 /* Just pass in the packet to our trunk device */ 1360 return (0); 1361 } 1362 1363 /* 1364 * Active failover 1365 */ 1366 1367 int 1368 trunk_fail_attach(struct trunk_softc *tr) 1369 { 1370 tr->tr_detach = trunk_fail_detach; 1371 tr->tr_start = trunk_fail_start; 1372 tr->tr_input = trunk_fail_input; 1373 tr->tr_init = NULL; 1374 tr->tr_stop = NULL; 1375 tr->tr_port_create = trunk_fail_port_create; 1376 tr->tr_port_destroy = trunk_fail_port_destroy; 1377 tr->tr_linkstate = trunk_fail_linkstate; 1378 tr->tr_req = NULL; 1379 tr->tr_portreq = NULL; 1380 1381 /* Get primary or the next active port */ 1382 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1383 1384 return (0); 1385 } 1386 1387 int 1388 trunk_fail_detach(struct trunk_softc *tr) 1389 { 1390 tr->tr_psc = NULL; 1391 return (0); 1392 } 1393 1394 int 1395 trunk_fail_port_create(struct trunk_port *tp) 1396 { 1397 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1398 1399 /* Get primary or the next active port */ 1400 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1401 return (0); 1402 } 1403 1404 void 1405 trunk_fail_port_destroy(struct trunk_port *tp) 1406 { 1407 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1408 struct trunk_port *tp_next; 1409 1410 if ((caddr_t)tp == tr->tr_psc) { 1411 /* Get the next active port */ 1412 tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries)); 1413 if (tp_next == tp) 1414 tr->tr_psc = NULL; 1415 else 1416 tr->tr_psc = (caddr_t)tp_next; 1417 } else { 1418 /* Get primary or the next active port */ 1419 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1420 } 1421 } 1422 1423 int 1424 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m) 1425 { 1426 struct trunk_port *tp = (struct trunk_port *)tr->tr_psc; 1427 1428 /* Use the master port if active or the next available port */ 1429 if (tp == NULL) { 1430 m_freem(m); 1431 return (ENOENT); 1432 } 1433 1434 return (if_enqueue(tp->tp_if, m)); 1435 } 1436 1437 int 1438 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1439 { 1440 if ((caddr_t)tp == tr->tr_psc) 1441 return (0); 1442 m_freem(m); 1443 return (-1); 1444 } 1445 1446 void 1447 trunk_fail_linkstate(struct trunk_port *tp) 1448 { 1449 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1450 1451 tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary); 1452 } 1453 1454 /* 1455 * Loadbalancing 1456 */ 1457 1458 int 1459 trunk_lb_attach(struct trunk_softc *tr) 1460 { 1461 struct trunk_lb *lb; 1462 1463 if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 1464 return (ENOMEM); 1465 1466 tr->tr_detach = trunk_lb_detach; 1467 tr->tr_start = trunk_lb_start; 1468 tr->tr_input = trunk_lb_input; 1469 tr->tr_port_create = trunk_lb_port_create; 1470 tr->tr_port_destroy = trunk_lb_port_destroy; 1471 tr->tr_linkstate = NULL; 1472 tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX; 1473 tr->tr_req = NULL; 1474 tr->tr_portreq = NULL; 1475 tr->tr_init = NULL; 1476 tr->tr_stop = NULL; 1477 1478 arc4random_buf(&lb->lb_key, sizeof(lb->lb_key)); 1479 tr->tr_psc = (caddr_t)lb; 1480 1481 return (0); 1482 } 1483 1484 int 1485 trunk_lb_detach(struct trunk_softc *tr) 1486 { 1487 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1488 1489 free(lb, M_DEVBUF, sizeof *lb); 1490 return (0); 1491 } 1492 1493 int 1494 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp) 1495 { 1496 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1497 struct trunk_port *tp_next; 1498 int i = 0; 1499 1500 bzero(&lb->lb_ports, sizeof(lb->lb_ports)); 1501 SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) { 1502 if (tp_next == tp) 1503 continue; 1504 if (i >= TRUNK_MAX_PORTS) 1505 return (EINVAL); 1506 if (tr->tr_ifflags & IFF_DEBUG) 1507 printf("%s: port %s at index %d\n", 1508 tr->tr_ifname, tp_next->tp_ifname, i); 1509 lb->lb_ports[i++] = tp_next; 1510 } 1511 1512 return (0); 1513 } 1514 1515 int 1516 trunk_lb_port_create(struct trunk_port *tp) 1517 { 1518 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1519 return (trunk_lb_porttable(tr, NULL)); 1520 } 1521 1522 void 1523 trunk_lb_port_destroy(struct trunk_port *tp) 1524 { 1525 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 1526 trunk_lb_porttable(tr, tp); 1527 } 1528 1529 int 1530 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m) 1531 { 1532 struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc; 1533 struct trunk_port *tp = NULL; 1534 u_int32_t p = 0; 1535 1536 p = trunk_hashmbuf(m, &lb->lb_key); 1537 p %= tr->tr_count; 1538 tp = lb->lb_ports[p]; 1539 1540 /* 1541 * Check the port's link state. This will return the next active 1542 * port if the link is down or the port is NULL. 1543 */ 1544 if ((tp = trunk_link_active(tr, tp)) == NULL) { 1545 m_freem(m); 1546 return (ENOENT); 1547 } 1548 1549 return (if_enqueue(tp->tp_if, m)); 1550 } 1551 1552 int 1553 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1554 { 1555 /* Just pass in the packet to our trunk device */ 1556 return (0); 1557 } 1558 1559 /* 1560 * Broadcast mode 1561 */ 1562 1563 int 1564 trunk_bcast_attach(struct trunk_softc *tr) 1565 { 1566 tr->tr_detach = trunk_bcast_detach; 1567 tr->tr_start = trunk_bcast_start; 1568 tr->tr_input = trunk_bcast_input; 1569 tr->tr_init = NULL; 1570 tr->tr_stop = NULL; 1571 tr->tr_port_create = NULL; 1572 tr->tr_port_destroy = NULL; 1573 tr->tr_linkstate = NULL; 1574 tr->tr_req = NULL; 1575 tr->tr_portreq = NULL; 1576 1577 return (0); 1578 } 1579 1580 int 1581 trunk_bcast_detach(struct trunk_softc *tr) 1582 { 1583 return (0); 1584 } 1585 1586 int 1587 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m0) 1588 { 1589 int active_ports = 0; 1590 int errors = 0; 1591 struct trunk_port *tp, *last = NULL; 1592 struct mbuf *m; 1593 1594 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1595 if (!TRUNK_PORTACTIVE(tp)) 1596 continue; 1597 1598 active_ports++; 1599 1600 if (last != NULL) { 1601 m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT); 1602 if (m == NULL) { 1603 errors++; 1604 break; 1605 } 1606 1607 if (if_enqueue(last->tp_if, m) != 0) 1608 errors++; 1609 } 1610 last = tp; 1611 } 1612 if (last == NULL) { 1613 m_freem(m0); 1614 return (ENOENT); 1615 } 1616 1617 if (if_enqueue(last->tp_if, m0) != 0) 1618 errors++; 1619 1620 if (errors == active_ports) 1621 return (ENOBUFS); 1622 1623 return (0); 1624 } 1625 1626 int 1627 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1628 { 1629 return (0); 1630 } 1631 1632 /* 1633 * 802.3ad LACP 1634 */ 1635 1636 int 1637 trunk_lacp_attach(struct trunk_softc *tr) 1638 { 1639 struct trunk_port *tp; 1640 int error; 1641 1642 tr->tr_detach = trunk_lacp_detach; 1643 tr->tr_port_create = lacp_port_create; 1644 tr->tr_port_destroy = lacp_port_destroy; 1645 tr->tr_linkstate = lacp_linkstate; 1646 tr->tr_start = trunk_lacp_start; 1647 tr->tr_input = trunk_lacp_input; 1648 tr->tr_init = lacp_init; 1649 tr->tr_stop = lacp_stop; 1650 tr->tr_req = lacp_req; 1651 tr->tr_portreq = lacp_portreq; 1652 1653 error = lacp_attach(tr); 1654 if (error) 1655 return (error); 1656 1657 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1658 lacp_port_create(tp); 1659 1660 return (error); 1661 } 1662 1663 int 1664 trunk_lacp_detach(struct trunk_softc *tr) 1665 { 1666 struct trunk_port *tp; 1667 int error; 1668 1669 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 1670 lacp_port_destroy(tp); 1671 1672 /* unlocking is safe here */ 1673 error = lacp_detach(tr); 1674 1675 return (error); 1676 } 1677 1678 int 1679 trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m) 1680 { 1681 struct trunk_port *tp; 1682 1683 tp = lacp_select_tx_port(tr, m); 1684 if (tp == NULL) { 1685 m_freem(m); 1686 return (EBUSY); 1687 } 1688 1689 return (if_enqueue(tp->tp_if, m)); 1690 } 1691 1692 int 1693 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) 1694 { 1695 return (lacp_input(tp, m)); 1696 } 1697