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