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