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