1/* $OpenBSD: if_trunk.c,v 1.30 2007/01/31 06:20:19 reyk Exp $ */ 2 3/* 4 * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2007 Andrew Thompson <thompsa@FreeBSD.org> 6 * Copyright (c) 2014 Marcelo Araujo <araujo@FreeBSD.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any --- 5 unchanged lines hidden (view full) --- 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include <sys/cdefs.h> |
22__FBSDID("$FreeBSD: head/sys/net/if_lagg.c 290239 2015-11-01 19:59:04Z melifaro $"); |
23 24#include "opt_inet.h" 25#include "opt_inet6.h" 26 27#include <sys/param.h> 28#include <sys/kernel.h> 29#include <sys/malloc.h> 30#include <sys/mbuf.h> --- 64 unchanged lines hidden (view full) --- 95static int lagg_clone_create(struct if_clone *, int, caddr_t); 96static void lagg_clone_destroy(struct ifnet *); 97static VNET_DEFINE(struct if_clone *, lagg_cloner); 98#define V_lagg_cloner VNET(lagg_cloner) 99static const char laggname[] = "lagg"; 100 101static void lagg_lladdr(struct lagg_softc *, uint8_t *); 102static void lagg_capabilities(struct lagg_softc *); |
103static void lagg_port_lladdr(struct lagg_port *, uint8_t *, lagg_llqtype); |
104static void lagg_port_setlladdr(void *, int); 105static int lagg_port_create(struct lagg_softc *, struct ifnet *); 106static int lagg_port_destroy(struct lagg_port *, int); 107static struct mbuf *lagg_input(struct ifnet *, struct mbuf *); 108static void lagg_linkstate(struct lagg_softc *); 109static void lagg_port_state(struct ifnet *, int); 110static int lagg_port_ioctl(struct ifnet *, u_long, caddr_t); 111static int lagg_port_output(struct ifnet *, struct mbuf *, --- 426 unchanged lines hidden (view full) --- 538 EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 539 EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 540 541 /* Shutdown and remove lagg ports */ 542 while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) 543 lagg_port_destroy(lp, 1); 544 /* Unhook the aggregation protocol */ 545 lagg_proto_detach(sc); |
546 LAGG_UNLOCK_ASSERT(sc); |
547 548 ifmedia_removeall(&sc->sc_media); 549 ether_ifdetach(ifp); 550 if_free(ifp); 551 552 LAGG_LIST_LOCK(); 553 SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); 554 LAGG_LIST_UNLOCK(); 555 556 taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task); 557 LAGG_LOCK_DESTROY(sc); 558 free(sc, M_DEVBUF); 559} 560 |
561/* 562 * Set link-layer address on the lagg interface itself. 563 * 564 * Set noinline to be dtrace-friendly 565 */ 566static __noinline void |
567lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr) 568{ 569 struct ifnet *ifp = sc->sc_ifp; 570 struct lagg_port lp; 571 572 if (memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0) 573 return; 574 575 LAGG_WLOCK_ASSERT(sc); 576 /* 577 * Set the link layer address on the lagg interface. 578 * lagg_proto_lladdr() notifies the MAC change to 579 * the aggregation protocol. iflladdr_event handler which 580 * may trigger gratuitous ARPs for INET will be handled in 581 * a taskqueue. 582 */ 583 bcopy(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN); 584 lagg_proto_lladdr(sc); 585 |
586 /* 587 * Send notification request for lagg interface 588 * itself. Note that new lladdr is already set. 589 */ |
590 bzero(&lp, sizeof(lp)); 591 lp.lp_ifp = sc->sc_ifp; 592 lp.lp_softc = sc; 593 |
594 /* Do not request lladdr change */ 595 lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT); |
596} 597 598static void 599lagg_capabilities(struct lagg_softc *sc) 600{ 601 struct lagg_port *lp; 602 int cap = ~0, ena = ~0; 603 u_long hwa = ~0UL; --- 24 unchanged lines hidden (view full) --- 628 getmicrotime(&sc->sc_ifp->if_lastchange); 629 630 if (sc->sc_ifflags & IFF_DEBUG) 631 if_printf(sc->sc_ifp, 632 "capabilities 0x%08x enabled 0x%08x\n", cap, ena); 633 } 634} 635 |
636/* 637 * Enqueue interface lladdr notification. 638 * If request is already queued, it is updated. 639 * If setting lladdr is also desired, @do_change has to be set to 1. 640 * 641 * Set noinline to be dtrace-friendly 642 */ 643static __noinline void 644lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr, lagg_llqtype llq_type) |
645{ 646 struct lagg_softc *sc = lp->lp_softc; 647 struct ifnet *ifp = lp->lp_ifp; 648 struct lagg_llq *llq; |
649 650 LAGG_WLOCK_ASSERT(sc); 651 |
652 /* 653 * Do not enqueue requests where lladdr is the same for 654 * "physical" interfaces (e.g. ports in lagg) 655 */ 656 if (llq_type == LAGG_LLQTYPE_PHYS && 657 memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0) |
658 return; 659 660 /* Check to make sure its not already queued to be changed */ 661 SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { |
662 if (llq->llq_ifp == ifp) { 663 /* Update lladdr, it may have changed */ 664 bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); 665 return; |
666 } 667 } 668 |
669 llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT | M_ZERO); 670 if (llq == NULL) /* XXX what to do */ 671 return; |
672 |
673 llq->llq_ifp = ifp; |
674 llq->llq_type = llq_type; |
675 bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); |
676 /* XXX: We should insert to tail */ 677 SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries); |
678 |
679 taskqueue_enqueue(taskqueue_swi, &sc->sc_lladdr_task); 680} 681 682/* 683 * Set the interface MAC address from a taskqueue to avoid a LOR. |
684 * 685 * Set noinline to be dtrace-friendly |
686 */ |
687static __noinline void |
688lagg_port_setlladdr(void *arg, int pending) 689{ 690 struct lagg_softc *sc = (struct lagg_softc *)arg; 691 struct lagg_llq *llq, *head; 692 struct ifnet *ifp; 693 int error; 694 695 /* Grab a local reference of the queue and remove it from the softc */ --- 5 unchanged lines hidden (view full) --- 701 /* 702 * Traverse the queue and set the lladdr on each ifp. It is safe to do 703 * unlocked as we have the only reference to it. 704 */ 705 for (llq = head; llq != NULL; llq = head) { 706 ifp = llq->llq_ifp; 707 708 CURVNET_SET(ifp->if_vnet); |
709 error = 0; 710 711 /* 712 * Set the link layer address on the laggport interface. 713 * Note that if_setlladdr() or iflladdr_event handler 714 * may result in arp transmission / lltable updates. 715 */ 716 if (llq->llq_type == LAGG_LLQTYPE_PHYS) |
717 error = if_setlladdr(ifp, llq->llq_lladdr, 718 ETHER_ADDR_LEN); |
719 if (error) 720 printf("%s: setlladdr failed on %s\n", __func__, 721 ifp->if_xname); 722 else |
723 EVENTHANDLER_INVOKE(iflladdr_event, ifp); 724 CURVNET_RESTORE(); 725 head = SLIST_NEXT(llq, llq_entries); 726 free(llq, M_DEVBUF); 727 } 728} 729 730static int --- 15 unchanged lines hidden (view full) --- 746 /* Port is already in the current lagg? */ 747 lp = (struct lagg_port *)ifp->if_lagg; 748 if (lp->lp_softc == sc) 749 return (EEXIST); 750 return (EBUSY); 751 } 752 753 /* XXX Disallow non-ethernet interfaces (this should be any of 802) */ |
754 if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN) |
755 return (EPROTONOSUPPORT); 756 757 /* Allow the first Ethernet member to define the MTU */ 758 if (SLIST_EMPTY(&sc->sc_ports)) 759 sc->sc_ifp->if_mtu = ifp->if_mtu; 760 else if (sc->sc_ifp->if_mtu != ifp->if_mtu) { 761 if_printf(sc->sc_ifp, "invalid MTU for %s\n", 762 ifp->if_xname); --- 37 unchanged lines hidden (view full) --- 800 lp->lp_ifp = ifp; 801 lp->lp_softc = sc; 802 803 /* Save port link layer address */ 804 bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); 805 806 if (SLIST_EMPTY(&sc->sc_ports)) { 807 sc->sc_primary = lp; |
808 /* First port in lagg. Update/notify lagg lladdress */ |
809 lagg_lladdr(sc, IF_LLADDR(ifp)); 810 } else { |
811 812 /* 813 * Update link layer address for this port and 814 * send notifications to other subsystems. 815 */ 816 lagg_port_lladdr(lp, IF_LLADDR(sc->sc_ifp), LAGG_LLQTYPE_PHYS); |
817 } 818 819 /* 820 * Insert into the list of ports. 821 * Keep ports sorted by if_index. It is handy, when configuration 822 * is predictable and `ifconfig laggN create ...` command 823 * will lead to the same result each time. 824 */ --- 69 unchanged lines hidden (view full) --- 894 895 /* 896 * Remove multicast addresses and interface flags from this port and 897 * reset the MAC address, skip if the interface is being detached. 898 */ 899 if (!lp->lp_detaching) { 900 lagg_ether_cmdmulti(lp, 0); 901 lagg_setflags(lp, 0); |
902 lagg_port_lladdr(lp, lp->lp_lladdr, LAGG_LLQTYPE_PHYS); |
903 } 904 905 /* Restore interface */ 906 ifp->if_type = lp->lp_iftype; 907 ifp->if_ioctl = lp->lp_ioctl; 908 ifp->if_output = lp->lp_output; 909 ifp->if_lagg = NULL; 910 --- 15 unchanged lines hidden (view full) --- 926 if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) { 927 bzero(&lladdr, ETHER_ADDR_LEN); 928 } else { 929 bcopy(lp0->lp_lladdr, 930 lladdr, ETHER_ADDR_LEN); 931 } 932 lagg_lladdr(sc, lladdr); 933 |
934 /* Mark lp0 as new primary */ 935 sc->sc_primary = lp0; 936 |
937 /* |
938 * Enqueue lladdr update/notification for each port 939 * (new primary needs update as well, to switch from 940 * old lladdr to its 'real' one). |
941 */ 942 SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) |
943 lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS); |
944 } 945 946 /* Remove any pending lladdr changes from the queue */ 947 if (lp->lp_detaching) { 948 SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { 949 if (llq->llq_ifp == ifp) { 950 SLIST_REMOVE(&sc->sc_llq_head, llq, lagg_llq, 951 llq_entries); --- 215 unchanged lines hidden (view full) --- 1167 } 1168 1169} 1170 1171static void 1172lagg_init(void *xsc) 1173{ 1174 struct lagg_softc *sc = (struct lagg_softc *)xsc; |
1175 struct ifnet *ifp = sc->sc_ifp; |
1176 struct lagg_port *lp; |
1177 1178 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1179 return; 1180 1181 LAGG_WLOCK(sc); 1182 1183 ifp->if_drv_flags |= IFF_DRV_RUNNING; |
1184 1185 /* 1186 * Update the port lladdrs if needed. 1187 * This might be if_setlladdr() notification 1188 * that lladdr has been changed. 1189 */ |
1190 SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) |
1191 lagg_port_lladdr(lp, IF_LLADDR(ifp), LAGG_LLQTYPE_PHYS); |
1192 1193 lagg_proto_init(sc); 1194 1195 LAGG_WUNLOCK(sc); 1196} 1197 1198static void 1199lagg_stop(struct lagg_softc *sc) --- 67 unchanged lines hidden (view full) --- 1267 break; 1268 if (ra->ra_proto < 1 || ra->ra_proto >= LAGG_PROTO_MAX) { 1269 error = EPROTONOSUPPORT; 1270 break; 1271 } 1272 1273 LAGG_WLOCK(sc); 1274 lagg_proto_detach(sc); |
1275 LAGG_UNLOCK_ASSERT(sc); |
1276 lagg_proto_attach(sc, ra->ra_proto); 1277 break; 1278 case SIOCGLAGGOPTS: 1279 ro->ro_opts = sc->sc_opts; 1280 if (sc->sc_proto == LAGG_PROTO_LACP) { 1281 struct lacp_softc *lsc; 1282 1283 lsc = (struct lacp_softc *)sc->sc_psc; --- 941 unchanged lines hidden --- |