1 /* $OpenBSD: if_trunk.c,v 1.140 2019/05/11 18:10:45 florian 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 int error = 0; 289 290 /* Limit the maximal number of trunk ports */ 291 if (tr->tr_count >= TRUNK_MAX_PORTS) 292 return (ENOSPC); 293 294 /* Check if port has already been associated to a trunk */ 295 if (trunk_port_get(NULL, ifp) != NULL) 296 return (EBUSY); 297 298 /* XXX Disallow non-ethernet interfaces (this should be any of 802) */ 299 if (ifp->if_type != IFT_ETHER) 300 return (EPROTONOSUPPORT); 301 302 /* Take MTU from the first member port */ 303 if (SLIST_EMPTY(&tr->tr_ports)) { 304 if (tr->tr_ifflags & IFF_DEBUG) 305 printf("%s: first port, setting trunk mtu %u\n", 306 tr->tr_ifname, ifp->if_mtu); 307 tr->tr_ac.ac_if.if_mtu = ifp->if_mtu; 308 tr->tr_ac.ac_if.if_hardmtu = ifp->if_mtu; 309 } else if (tr->tr_ac.ac_if.if_mtu != ifp->if_mtu) { 310 printf("%s: adding %s failed, MTU %u != %u\n", tr->tr_ifname, 311 ifp->if_xname, ifp->if_mtu, tr->tr_ac.ac_if.if_mtu); 312 return (EINVAL); 313 } 314 315 if ((error = ifpromisc(ifp, 1)) != 0) 316 return (error); 317 318 if ((tp = malloc(sizeof *tp, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 319 return (ENOMEM); 320 321 /* Check if port is a stacked trunk */ 322 SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) { 323 if (ifp == &tr_ptr->tr_ac.ac_if) { 324 tp->tp_flags |= TRUNK_PORT_STACK; 325 if (trunk_port_checkstacking(tr_ptr) >= 326 TRUNK_MAX_STACKING) { 327 free(tp, M_DEVBUF, sizeof *tp); 328 return (E2BIG); 329 } 330 } 331 } 332 333 /* Change the interface type */ 334 tp->tp_iftype = ifp->if_type; 335 ifp->if_type = IFT_IEEE8023ADLAG; 336 337 tp->tp_ioctl = ifp->if_ioctl; 338 ifp->if_ioctl = trunk_port_ioctl; 339 340 tp->tp_output = ifp->if_output; 341 ifp->if_output = trunk_port_output; 342 343 tp->tp_if = ifp; 344 tp->tp_trunk = tr; 345 346 /* Save port link layer address */ 347 bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN); 348 349 if (SLIST_EMPTY(&tr->tr_ports)) { 350 tr->tr_primary = tp; 351 tp->tp_flags |= TRUNK_PORT_MASTER; 352 trunk_lladdr(&tr->tr_ac, tp->tp_lladdr); 353 } 354 355 /* Insert into the list of ports */ 356 SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries); 357 tr->tr_count++; 358 359 /* Update link layer address for this port */ 360 trunk_port_lladdr(tp, 361 ((struct arpcom *)(tr->tr_primary->tp_if))->ac_enaddr); 362 363 /* Update trunk capabilities */ 364 tr->tr_capabilities = trunk_capabilities(tr); 365 366 /* Add multicast addresses to this port */ 367 trunk_ether_cmdmulti(tp, SIOCADDMULTI); 368 369 /* Register callback for physical link state changes */ 370 tp->lh_cookie = hook_establish(ifp->if_linkstatehooks, 1, 371 trunk_port_state, tp); 372 373 /* Register callback if parent wants to unregister */ 374 tp->dh_cookie = hook_establish(ifp->if_detachhooks, 0, 375 trunk_port_ifdetach, tp); 376 377 if (tr->tr_port_create != NULL) 378 error = (*tr->tr_port_create)(tp); 379 380 /* Change input handler of the physical interface. */ 381 if_ih_insert(ifp, trunk_input, tp); 382 383 return (error); 384 } 385 386 int 387 trunk_port_checkstacking(struct trunk_softc *tr) 388 { 389 struct trunk_softc *tr_ptr; 390 struct trunk_port *tp; 391 int m = 0; 392 393 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 394 if (tp->tp_flags & TRUNK_PORT_STACK) { 395 tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc; 396 m = MAX(m, trunk_port_checkstacking(tr_ptr)); 397 } 398 } 399 400 return (m + 1); 401 } 402 403 int 404 trunk_port_destroy(struct trunk_port *tp) 405 { 406 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 407 struct trunk_port *tp_ptr; 408 struct ifnet *ifp = tp->tp_if; 409 410 /* Restore previous input handler. */ 411 if_ih_remove(ifp, trunk_input, tp); 412 413 /* Remove multicast addresses from this port */ 414 trunk_ether_cmdmulti(tp, SIOCDELMULTI); 415 416 /* Port has to be down */ 417 if (ifp->if_flags & IFF_UP) 418 if_down(ifp); 419 420 ifpromisc(ifp, 0); 421 422 if (tr->tr_port_destroy != NULL) 423 (*tr->tr_port_destroy)(tp); 424 425 /* Restore interface type. */ 426 ifp->if_type = tp->tp_iftype; 427 428 ifp->if_ioctl = tp->tp_ioctl; 429 ifp->if_output = tp->tp_output; 430 431 hook_disestablish(ifp->if_linkstatehooks, tp->lh_cookie); 432 hook_disestablish(ifp->if_detachhooks, tp->dh_cookie); 433 434 /* Finally, remove the port from the trunk */ 435 SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries); 436 tr->tr_count--; 437 438 /* Update the primary interface */ 439 if (tp == tr->tr_primary) { 440 u_int8_t lladdr[ETHER_ADDR_LEN]; 441 442 if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) { 443 bzero(&lladdr, ETHER_ADDR_LEN); 444 } else { 445 bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr, 446 lladdr, ETHER_ADDR_LEN); 447 tp_ptr->tp_flags = TRUNK_PORT_MASTER; 448 } 449 trunk_lladdr(&tr->tr_ac, lladdr); 450 tr->tr_primary = tp_ptr; 451 452 /* Update link layer address for each port */ 453 SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries) 454 trunk_port_lladdr(tp_ptr, lladdr); 455 } 456 457 /* Reset the port lladdr */ 458 trunk_port_lladdr(tp, tp->tp_lladdr); 459 460 free(tp, M_DEVBUF, sizeof *tp); 461 462 /* Update trunk capabilities */ 463 tr->tr_capabilities = trunk_capabilities(tr); 464 465 return (0); 466 } 467 468 int 469 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 470 { 471 struct trunk_reqport *rp = (struct trunk_reqport *)data; 472 struct trunk_softc *tr; 473 struct trunk_port *tp = NULL; 474 int error = 0; 475 476 /* Should be checked by the caller */ 477 if (ifp->if_type != IFT_IEEE8023ADLAG || 478 (tp = trunk_port_get(NULL, ifp)) == NULL || 479 (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) { 480 error = EINVAL; 481 goto fallback; 482 } 483 484 switch (cmd) { 485 case SIOCGTRUNKPORT: 486 if (rp->rp_portname[0] == '\0' || 487 ifunit(rp->rp_portname) != ifp) { 488 error = EINVAL; 489 break; 490 } 491 492 /* Search in all trunks if the global flag is set */ 493 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 494 NULL : tr, ifp)) == NULL) { 495 error = ENOENT; 496 break; 497 } 498 499 trunk_port2req(tp, rp); 500 break; 501 case SIOCSIFMTU: 502 /* Do not allow the MTU to be changed once joined */ 503 error = EINVAL; 504 break; 505 default: 506 error = ENOTTY; 507 goto fallback; 508 } 509 510 return (error); 511 512 fallback: 513 if (tp != NULL) 514 error = (*tp->tp_ioctl)(ifp, cmd, data); 515 516 return (error); 517 } 518 519 int 520 trunk_port_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 521 struct rtentry *rt) 522 { 523 /* restrict transmission on trunk members to bpf only */ 524 if (ifp->if_type == IFT_IEEE8023ADLAG && 525 (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) { 526 m_freem(m); 527 return (EBUSY); 528 } 529 530 return (ether_output(ifp, m, dst, rt)); 531 } 532 533 void 534 trunk_port_ifdetach(void *arg) 535 { 536 struct trunk_port *tp = (struct trunk_port *)arg; 537 538 trunk_port_destroy(tp); 539 } 540 541 struct trunk_port * 542 trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp) 543 { 544 struct trunk_port *tp; 545 struct trunk_softc *tr_ptr; 546 547 if (tr != NULL) { 548 /* Search port in specified trunk */ 549 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 550 if (tp->tp_if == ifp) 551 return (tp); 552 } 553 } else { 554 /* Search all trunks for the selected port */ 555 SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) { 556 SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) { 557 if (tp->tp_if == ifp) 558 return (tp); 559 } 560 } 561 } 562 563 return (NULL); 564 } 565 566 void 567 trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp) 568 { 569 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 570 571 strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname)); 572 strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname)); 573 rp->rp_prio = tp->tp_prio; 574 if (tr->tr_portreq != NULL) 575 (*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc); 576 577 /* Add protocol specific flags */ 578 switch (tr->tr_proto) { 579 case TRUNK_PROTO_FAILOVER: 580 rp->rp_flags = tp->tp_flags; 581 if (tp == trunk_link_active(tr, tr->tr_primary)) 582 rp->rp_flags |= TRUNK_PORT_ACTIVE; 583 break; 584 585 case TRUNK_PROTO_ROUNDROBIN: 586 case TRUNK_PROTO_LOADBALANCE: 587 case TRUNK_PROTO_BROADCAST: 588 rp->rp_flags = tp->tp_flags; 589 if (TRUNK_PORTACTIVE(tp)) 590 rp->rp_flags |= TRUNK_PORT_ACTIVE; 591 break; 592 593 case TRUNK_PROTO_LACP: 594 /* LACP has a different definition of active */ 595 rp->rp_flags = lacp_port_status(tp); 596 break; 597 default: 598 break; 599 } 600 } 601 602 int 603 trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 604 { 605 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 606 struct trunk_reqall *ra = (struct trunk_reqall *)data; 607 struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf; 608 struct trunk_opts *tro = (struct trunk_opts *)data; 609 struct ifreq *ifr = (struct ifreq *)data; 610 struct lacp_softc *lsc; 611 struct trunk_port *tp; 612 struct lacp_port *lp; 613 struct ifnet *tpif; 614 int i, error = 0; 615 616 bzero(&rpbuf, sizeof(rpbuf)); 617 618 switch (cmd) { 619 case SIOCGTRUNK: 620 ra->ra_proto = tr->tr_proto; 621 if (tr->tr_req != NULL) 622 (*tr->tr_req)(tr, (caddr_t)&ra->ra_psc); 623 ra->ra_ports = i = 0; 624 tp = SLIST_FIRST(&tr->tr_ports); 625 while (tp && ra->ra_size >= 626 i + sizeof(struct trunk_reqport)) { 627 trunk_port2req(tp, &rpbuf); 628 error = copyout(&rpbuf, (caddr_t)ra->ra_port + i, 629 sizeof(struct trunk_reqport)); 630 if (error) 631 break; 632 i += sizeof(struct trunk_reqport); 633 ra->ra_ports++; 634 tp = SLIST_NEXT(tp, tp_entries); 635 } 636 break; 637 case SIOCSTRUNK: 638 if ((error = suser(curproc)) != 0) { 639 error = EPERM; 640 break; 641 } 642 if (ra->ra_proto >= TRUNK_PROTO_MAX) { 643 error = EPROTONOSUPPORT; 644 break; 645 } 646 /* 647 * Serialize modifications to the trunk and trunk 648 * ports via the ifih SRP: detaching trunk_input 649 * from the trunk port will require all currently 650 * running trunk_input's on this port to finish 651 * granting us an exclusive access to it. 652 */ 653 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 654 if_ih_remove(tp->tp_if, trunk_input, tp); 655 if (tr->tr_proto != TRUNK_PROTO_NONE) 656 error = tr->tr_detach(tr); 657 if (error != 0) 658 break; 659 for (i = 0; i < nitems(trunk_protos); i++) { 660 if (trunk_protos[i].ti_proto == ra->ra_proto) { 661 if (tr->tr_ifflags & IFF_DEBUG) 662 printf("%s: using proto %u\n", 663 tr->tr_ifname, 664 trunk_protos[i].ti_proto); 665 tr->tr_proto = trunk_protos[i].ti_proto; 666 if (tr->tr_proto != TRUNK_PROTO_NONE) 667 error = trunk_protos[i].ti_attach(tr); 668 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 669 if_ih_insert(tp->tp_if, 670 trunk_input, tp); 671 /* Update trunk capabilities */ 672 tr->tr_capabilities = trunk_capabilities(tr); 673 goto out; 674 } 675 } 676 error = EPROTONOSUPPORT; 677 break; 678 case SIOCGTRUNKOPTS: 679 /* Only LACP trunks have options atm */ 680 if (tro->to_proto != TRUNK_PROTO_LACP) { 681 error = EPROTONOSUPPORT; 682 break; 683 } 684 lsc = LACP_SOFTC(tr); 685 tro->to_lacpopts.lacp_mode = lsc->lsc_mode; 686 tro->to_lacpopts.lacp_timeout = lsc->lsc_timeout; 687 tro->to_lacpopts.lacp_prio = lsc->lsc_sys_prio; 688 tro->to_lacpopts.lacp_portprio = lsc->lsc_port_prio; 689 tro->to_lacpopts.lacp_ifqprio = lsc->lsc_ifq_prio; 690 break; 691 case SIOCSTRUNKOPTS: 692 if ((error = suser(curproc)) != 0) { 693 error = EPERM; 694 break; 695 } 696 /* Only LACP trunks have options atm */ 697 if (tro->to_proto != TRUNK_PROTO_LACP) { 698 error = EPROTONOSUPPORT; 699 break; 700 } 701 lsc = LACP_SOFTC(tr); 702 switch(tro->to_opts) { 703 case TRUNK_OPT_LACP_MODE: 704 /* 705 * Ensure mode changes occur immediately 706 * on all ports 707 */ 708 lsc->lsc_mode = tro->to_lacpopts.lacp_mode; 709 if (lsc->lsc_mode == 0) { 710 LIST_FOREACH(lp, &lsc->lsc_ports, 711 lp_next) 712 lp->lp_state &= 713 ~LACP_STATE_ACTIVITY; 714 } else { 715 LIST_FOREACH(lp, &lsc->lsc_ports, 716 lp_next) 717 lp->lp_state |= 718 LACP_STATE_ACTIVITY; 719 } 720 break; 721 case TRUNK_OPT_LACP_TIMEOUT: 722 /* 723 * Ensure timeout changes occur immediately 724 * on all ports 725 */ 726 lsc->lsc_timeout = 727 tro->to_lacpopts.lacp_timeout; 728 if (lsc->lsc_timeout == 0) { 729 LIST_FOREACH(lp, &lsc->lsc_ports, 730 lp_next) 731 lp->lp_state &= 732 ~LACP_STATE_TIMEOUT; 733 } else { 734 LIST_FOREACH(lp, &lsc->lsc_ports, 735 lp_next) 736 lp->lp_state |= 737 LACP_STATE_TIMEOUT; 738 } 739 break; 740 case TRUNK_OPT_LACP_SYS_PRIO: 741 if (tro->to_lacpopts.lacp_prio == 0) { 742 error = EINVAL; 743 break; 744 } 745 lsc->lsc_sys_prio = tro->to_lacpopts.lacp_prio; 746 break; 747 case TRUNK_OPT_LACP_PORT_PRIO: 748 if (tro->to_lacpopts.lacp_portprio == 0) { 749 error = EINVAL; 750 break; 751 } 752 lsc->lsc_port_prio = 753 tro->to_lacpopts.lacp_portprio; 754 break; 755 case TRUNK_OPT_LACP_IFQ_PRIO: 756 if (tro->to_lacpopts.lacp_ifqprio > 757 IFQ_MAXPRIO) { 758 error = EINVAL; 759 break; 760 } 761 lsc->lsc_ifq_prio = 762 tro->to_lacpopts.lacp_ifqprio; 763 break; 764 } 765 break; 766 case SIOCGTRUNKPORT: 767 if (rp->rp_portname[0] == '\0' || 768 (tpif = ifunit(rp->rp_portname)) == NULL) { 769 error = EINVAL; 770 break; 771 } 772 773 /* Search in all trunks if the global flag is set */ 774 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 775 NULL : tr, tpif)) == NULL) { 776 error = ENOENT; 777 break; 778 } 779 780 trunk_port2req(tp, rp); 781 break; 782 case SIOCSTRUNKPORT: 783 if ((error = suser(curproc)) != 0) { 784 error = EPERM; 785 break; 786 } 787 if (rp->rp_portname[0] == '\0' || 788 (tpif = ifunit(rp->rp_portname)) == NULL) { 789 error = EINVAL; 790 break; 791 } 792 error = trunk_port_create(tr, tpif); 793 break; 794 case SIOCSTRUNKDELPORT: 795 if ((error = suser(curproc)) != 0) { 796 error = EPERM; 797 break; 798 } 799 if (rp->rp_portname[0] == '\0' || 800 (tpif = ifunit(rp->rp_portname)) == NULL) { 801 error = EINVAL; 802 break; 803 } 804 805 /* Search in all trunks if the global flag is set */ 806 if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ? 807 NULL : tr, tpif)) == NULL) { 808 error = ENOENT; 809 break; 810 } 811 812 error = trunk_port_destroy(tp); 813 break; 814 case SIOCSIFADDR: 815 ifp->if_flags |= IFF_UP; 816 /* FALLTHROUGH */ 817 case SIOCSIFFLAGS: 818 error = ENETRESET; 819 break; 820 case SIOCADDMULTI: 821 error = trunk_ether_addmulti(tr, ifr); 822 break; 823 case SIOCDELMULTI: 824 error = trunk_ether_delmulti(tr, ifr); 825 break; 826 case SIOCSIFMEDIA: 827 case SIOCGIFMEDIA: 828 error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd); 829 break; 830 case SIOCSIFLLADDR: 831 /* Update the port lladdrs as well */ 832 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) 833 trunk_port_lladdr(tp, ifr->ifr_addr.sa_data); 834 error = ENETRESET; 835 break; 836 default: 837 error = ether_ioctl(ifp, &tr->tr_ac, cmd, data); 838 } 839 840 if (error == ENETRESET) { 841 if (ifp->if_flags & IFF_UP) { 842 if ((ifp->if_flags & IFF_RUNNING) == 0) 843 trunk_init(ifp); 844 } else { 845 if (ifp->if_flags & IFF_RUNNING) 846 trunk_stop(ifp); 847 } 848 error = 0; 849 } 850 851 out: 852 return (error); 853 } 854 855 int 856 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr) 857 { 858 struct trunk_mc *mc; 859 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 860 int error; 861 862 /* Ignore ENETRESET error code */ 863 if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET) 864 return (error); 865 866 if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) { 867 error = ENOMEM; 868 goto failed; 869 } 870 871 ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 872 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm); 873 bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len); 874 SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries); 875 876 if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI, 877 (caddr_t)ifr)) != 0) { 878 trunk_ether_delmulti(tr, ifr); 879 return (error); 880 } 881 882 return (error); 883 884 failed: 885 ether_delmulti(ifr, &tr->tr_ac); 886 887 return (error); 888 } 889 890 int 891 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr) 892 { 893 struct ether_multi *enm; 894 struct trunk_mc *mc; 895 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 896 int error; 897 898 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 899 return (error); 900 ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm); 901 if (enm == NULL) 902 return (EINVAL); 903 904 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) 905 if (mc->mc_enm == enm) 906 break; 907 908 /* We won't delete entries we didn't add */ 909 if (mc == NULL) 910 return (EINVAL); 911 912 if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET) 913 return (error); 914 915 /* We no longer use this multicast address. Tell parent so. */ 916 error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 917 if (error == 0) { 918 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 919 free(mc, M_DEVBUF, sizeof(*mc)); 920 } else { 921 /* XXX At least one port failed to remove the address */ 922 if (tr->tr_ifflags & IFF_DEBUG) { 923 printf("%s: failed to remove multicast address " 924 "on all ports (%d)\n", tr->tr_ifname, error); 925 } 926 (void)ether_addmulti(ifr, &tr->tr_ac); 927 } 928 929 return (0); 930 } 931 932 void 933 trunk_ether_purgemulti(struct trunk_softc *tr) 934 { 935 struct trunk_mc *mc; 936 struct trunk_ifreq ifs; 937 struct ifreq *ifr = &ifs.ifreq.ifreq; 938 939 while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) { 940 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 941 942 /* Try to remove multicast address on all ports */ 943 trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr); 944 945 SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries); 946 free(mc, M_DEVBUF, sizeof(*mc)); 947 } 948 } 949 950 int 951 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd) 952 { 953 struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk; 954 struct trunk_mc *mc; 955 struct trunk_ifreq ifs; 956 struct ifreq *ifr = &ifs.ifreq.ifreq; 957 int ret, error = 0; 958 959 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 960 SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) { 961 bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len); 962 963 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) { 964 if (tr->tr_ifflags & IFF_DEBUG) { 965 printf("%s: ioctl %lu failed on %s: %d\n", 966 tr->tr_ifname, cmd, tp->tp_ifname, ret); 967 } 968 /* Store last known error and continue */ 969 error = ret; 970 } 971 } 972 973 return (error); 974 } 975 976 int 977 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data) 978 { 979 struct ifreq *ifr = (struct ifreq *)data; 980 struct trunk_port *tp; 981 int ret, error = 0; 982 983 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 984 bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ); 985 if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) { 986 if (tr->tr_ifflags & IFF_DEBUG) { 987 printf("%s: ioctl %lu failed on %s: %d\n", 988 tr->tr_ifname, cmd, tp->tp_ifname, ret); 989 } 990 /* Store last known error and continue */ 991 error = ret; 992 } 993 } 994 995 return (error); 996 } 997 998 void 999 trunk_start(struct ifnet *ifp) 1000 { 1001 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1002 struct mbuf *m; 1003 int error; 1004 1005 for (;;) { 1006 IFQ_DEQUEUE(&ifp->if_snd, m); 1007 if (m == NULL) 1008 break; 1009 1010 #if NBPFILTER > 0 1011 if (ifp->if_bpf) 1012 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1013 #endif 1014 1015 if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) { 1016 error = (*tr->tr_start)(tr, m); 1017 if (error != 0) 1018 ifp->if_oerrors++; 1019 } else { 1020 m_freem(m); 1021 if (tr->tr_proto != TRUNK_PROTO_NONE) 1022 ifp->if_oerrors++; 1023 } 1024 } 1025 } 1026 1027 u_int32_t 1028 trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key) 1029 { 1030 u_int16_t etype, ether_vtag; 1031 u_int32_t p = 0; 1032 u_int16_t *vlan, vlanbuf[2]; 1033 int off; 1034 struct ether_header *eh; 1035 struct ip *ip, ipbuf; 1036 #ifdef INET6 1037 u_int32_t flow; 1038 struct ip6_hdr *ip6, ip6buf; 1039 #endif 1040 SIPHASH_CTX ctx; 1041 1042 if (m->m_pkthdr.ph_flowid & M_FLOWID_VALID) 1043 return (m->m_pkthdr.ph_flowid & M_FLOWID_MASK); 1044 1045 SipHash24_Init(&ctx, key); 1046 off = sizeof(*eh); 1047 if (m->m_len < off) 1048 goto done; 1049 eh = mtod(m, struct ether_header *); 1050 etype = ntohs(eh->ether_type); 1051 SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN); 1052 SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN); 1053 1054 /* Special handling for encapsulating VLAN frames */ 1055 if (m->m_flags & M_VLANTAG) { 1056 ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 1057 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1058 } else if (etype == ETHERTYPE_VLAN) { 1059 if ((vlan = (u_int16_t *) 1060 trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL) 1061 return (p); 1062 ether_vtag = EVL_VLANOFTAG(*vlan); 1063 SipHash24_Update(&ctx, ðer_vtag, sizeof(ether_vtag)); 1064 etype = ntohs(vlan[1]); 1065 off += EVL_ENCAPLEN; 1066 } 1067 1068 switch (etype) { 1069 case ETHERTYPE_IP: 1070 if ((ip = (struct ip *) 1071 trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL) 1072 return (p); 1073 SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr)); 1074 SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr)); 1075 break; 1076 #ifdef INET6 1077 case ETHERTYPE_IPV6: 1078 if ((ip6 = (struct ip6_hdr *) 1079 trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL) 1080 return (p); 1081 SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr)); 1082 SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr)); 1083 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 1084 SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */ 1085 break; 1086 #endif 1087 } 1088 1089 done: 1090 return SipHash24_End(&ctx); 1091 } 1092 1093 void 1094 trunk_init(struct ifnet *ifp) 1095 { 1096 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1097 1098 ifp->if_flags |= IFF_RUNNING; 1099 1100 if (tr->tr_init != NULL) 1101 (*tr->tr_init)(tr); 1102 } 1103 1104 void 1105 trunk_stop(struct ifnet *ifp) 1106 { 1107 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1108 1109 ifp->if_flags &= ~IFF_RUNNING; 1110 1111 if (tr->tr_stop != NULL) 1112 (*tr->tr_stop)(tr); 1113 } 1114 1115 int 1116 trunk_input(struct ifnet *ifp, struct mbuf *m, void *cookie) 1117 { 1118 struct trunk_softc *tr; 1119 struct trunk_port *tp; 1120 struct ifnet *trifp = NULL; 1121 struct ether_header *eh; 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 if_vinput(trifp, m); 1166 return (1); 1167 1168 bad: 1169 if (trifp != NULL) 1170 trifp->if_ierrors++; 1171 m_freem(m); 1172 return (1); 1173 } 1174 1175 int 1176 trunk_media_change(struct ifnet *ifp) 1177 { 1178 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1179 1180 if (tr->tr_ifflags & IFF_DEBUG) 1181 printf("%s\n", __func__); 1182 1183 /* Ignore */ 1184 return (0); 1185 } 1186 1187 void 1188 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr) 1189 { 1190 struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; 1191 struct trunk_port *tp; 1192 1193 imr->ifm_status = IFM_AVALID; 1194 imr->ifm_active = IFM_ETHER | IFM_AUTO; 1195 1196 SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) { 1197 if (TRUNK_PORTACTIVE(tp)) 1198 imr->ifm_status |= IFM_ACTIVE; 1199 } 1200 } 1201 1202 void 1203 trunk_port_state(void *arg) 1204 { 1205 struct trunk_port *tp = (struct trunk_port *)arg; 1206 struct trunk_softc *tr = NULL; 1207 1208 if (tp != NULL) 1209 tr = (struct trunk_softc *)tp->tp_trunk; 1210 if (tr == NULL) 1211 return; 1212 if (tr->tr_linkstate != NULL) 1213 (*tr->tr_linkstate)(tp); 1214 trunk_link_active(tr, tp); 1215 rtm_ifchg(&tr->tr_ac.ac_if); 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