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