Index: sys/net/if_lagg.c =================================================================== --- sys/net/if_lagg.c (revision 311787) +++ sys/net/if_lagg.c (working copy) @@ -98,10 +100,9 @@ #define V_lagg_cloner VNET(lagg_cloner) static const char laggname[] = "lagg"; -static void lagg_lladdr(struct lagg_softc *, uint8_t *); +static void lagg_lladdr(struct lagg_softc *, uint8_t *, bool); static void lagg_capabilities(struct lagg_softc *); static void lagg_port_lladdr(struct lagg_port *, uint8_t *, lagg_llqtype); -static void lagg_port_setlladdr(void *, int); static int lagg_port_create(struct lagg_softc *, struct ifnet *); static int lagg_port_destroy(struct lagg_port *, int); static struct mbuf *lagg_input(struct ifnet *, struct mbuf *); @@ -487,7 +488,6 @@ LAGG_LOCK_INIT(sc); SLIST_INIT(&sc->sc_ports); - TASK_INIT(&sc->sc_lladdr_task, 0, lagg_port_setlladdr, sc); /* Initialise pseudo media types */ ifmedia_init(&sc->sc_media, 0, lagg_media_change, @@ -553,7 +553,6 @@ SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); LAGG_LIST_UNLOCK(); - taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task); LAGG_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } @@ -564,7 +563,7 @@ * Set noinline to be dtrace-friendly */ static __noinline void -lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr) +lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr, bool detaching) { struct ifnet *ifp = sc->sc_ifp; struct lagg_port lp; @@ -590,6 +589,7 @@ bzero(&lp, sizeof(lp)); lp.lp_ifp = sc->sc_ifp; lp.lp_softc = sc; + lp.lp_detaching = detaching; /* Do not request lladdr change */ lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT); @@ -645,7 +645,7 @@ { struct lagg_softc *sc = lp->lp_softc; struct ifnet *ifp = lp->lp_ifp; - struct lagg_llq *llq; + int error = 0; LAGG_WLOCK_ASSERT(sc); @@ -653,75 +653,22 @@ * Do not enqueue requests where lladdr is the same for * "physical" interfaces (e.g. ports in lagg) */ - if (llq_type == LAGG_LLQTYPE_PHYS && - memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0) + if (lp->lp_detaching || (llq_type == LAGG_LLQTYPE_PHYS && + memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0)) return; - /* Check to make sure its not already queued to be changed */ - SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { - if (llq->llq_ifp == ifp) { - /* Update lladdr, it may have changed */ - bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); - return; - } - } - - llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT | M_ZERO); - if (llq == NULL) /* XXX what to do */ - return; - - llq->llq_ifp = ifp; - llq->llq_type = llq_type; - bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); - /* XXX: We should insert to tail */ - SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries); - - taskqueue_enqueue(taskqueue_swi, &sc->sc_lladdr_task); + /* Set the link layer address */ + CURVNET_SET(ifp->if_vnet); + if (llq_type == LAGG_LLQTYPE_PHYS) + error = if_setlladdr(ifp, lladdr, ETHER_ADDR_LEN); + else + EVENTHANDLER_INVOKE(iflladdr_event, ifp); + CURVNET_RESTORE(); + if (error) + if_printf(sc->sc_ifp, "%s: setlladdr failed on %s\n", __func__, + ifp->if_xname); } -/* - * Set the interface MAC address from a taskqueue to avoid a LOR. - * - * Set noinline to be dtrace-friendly - */ -static __noinline void -lagg_port_setlladdr(void *arg, int pending) -{ - struct lagg_softc *sc = (struct lagg_softc *)arg; - struct lagg_llq *llq, *head; - struct ifnet *ifp; - - /* Grab a local reference of the queue and remove it from the softc */ - LAGG_WLOCK(sc); - head = SLIST_FIRST(&sc->sc_llq_head); - SLIST_FIRST(&sc->sc_llq_head) = NULL; - LAGG_WUNLOCK(sc); - - /* - * Traverse the queue and set the lladdr on each ifp. It is safe to do - * unlocked as we have the only reference to it. - */ - for (llq = head; llq != NULL; llq = head) { - ifp = llq->llq_ifp; - - CURVNET_SET(ifp->if_vnet); - - /* - * Set the link layer address on the laggport interface. - * Note that if_setlladdr() or iflladdr_event handler - * may result in arp transmission / lltable updates. - */ - if (llq->llq_type == LAGG_LLQTYPE_PHYS) - if_setlladdr(ifp, llq->llq_lladdr, - ETHER_ADDR_LEN); - else - EVENTHANDLER_INVOKE(iflladdr_event, ifp); - CURVNET_RESTORE(); - head = SLIST_NEXT(llq, llq_entries); - free(llq, M_DEVBUF); - } -} - static int lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) { @@ -801,7 +748,7 @@ if (SLIST_EMPTY(&sc->sc_ports)) { sc->sc_primary = lp; /* First port in lagg. Update/notify lagg lladdress */ - lagg_lladdr(sc, IF_LLADDR(ifp)); + lagg_lladdr(sc, IF_LLADDR(ifp), false); } else { /* @@ -877,7 +824,6 @@ { struct lagg_softc *sc = lp->lp_softc; struct lagg_port *lp_ptr, *lp0; - struct lagg_llq *llq; struct ifnet *ifp = lp->lp_ifp; uint64_t *pval, vdiff; int i; @@ -924,7 +870,7 @@ bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN); } - lagg_lladdr(sc, lladdr); + lagg_lladdr(sc, lladdr, true); /* Mark lp0 as new primary */ sc->sc_primary = lp0; @@ -938,18 +884,6 @@ lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS); } - /* Remove any pending lladdr changes from the queue */ - if (lp->lp_detaching) { - SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { - if (llq->llq_ifp == ifp) { - SLIST_REMOVE(&sc->sc_llq_head, llq, lagg_llq, - llq_entries); - free(llq, M_DEVBUF); - break; /* Only appears once */ - } - } - } - if (lp->lp_ifflags) if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); @@ -1472,6 +1406,8 @@ "before adding it as a member to prevent " "IPv6 address scope violation.\n", tpif->if_xname); + } else { + if_printf(sc->sc_ifp, "No IPv6 link-local address found on %s\n", tpif->if_xname); } #endif LAGG_WLOCK(sc); Index: sys/net/if_lagg.h =================================================================== --- sys/net/if_lagg.h (revision 311787) +++ sys/net/if_lagg.h (working copy) @@ -207,14 +207,6 @@ LAGG_LLQTYPE_VIRT, /* Task related to lagg interface itself */ } lagg_llqtype; -/* List of interfaces to have the MAC address modified */ -struct lagg_llq { - struct ifnet *llq_ifp; - uint8_t llq_lladdr[ETHER_ADDR_LEN]; - lagg_llqtype llq_type; - SLIST_ENTRY(lagg_llq) llq_entries; -}; - struct lagg_counters { uint64_t val[IFCOUNTERS]; }; @@ -236,9 +228,6 @@ SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */ SLIST_ENTRY(lagg_softc) sc_entries; - struct task sc_lladdr_task; - SLIST_HEAD(__llqhd, lagg_llq) sc_llq_head; /* interfaces to program - the lladdr on */ eventhandler_tag vlan_attach; eventhandler_tag vlan_detach; struct callout sc_callout; Index: sys/netinet6/in6.c =================================================================== --- sys/netinet6/in6.c (revision 311787) +++ sys/netinet6/in6.c (working copy) @@ -1493,6 +1493,8 @@ return ((struct in6_ifaddr *)ifa); } +SDT_PROVIDER_DEFINE(in6); +SDT_PROBE_DEFINE2(in6, kernel, in6ifa_llaonifp, addr, "struct ifnet*", "struct sockaddr*"); /* * Find a link-local scoped address on ifp and return it if any. */ @@ -1502,10 +1504,11 @@ struct sockaddr_in6 *sin6; struct ifaddr *ifa; - if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) - return (NULL); +/* if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)*/ +/* return (NULL);*/ IF_ADDR_RLOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + SDT_PROBE2(in6, kernel, in6ifa_llaonifp, addr, ifp, ifa->ifa_addr); if (ifa->ifa_addr->sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;