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