- Move L2 addr configuration for the primary port to a taskqueue. This fixes

LOR of softc rmlock in iflladdr_event handlers.

- Call if_delmulti_ifma() after LACP_UNLOCK().  This fixes another LOR.

- Fix a panic in lacp_transit_expire().

- Fix a panic in lagg_input() upon shutting down a port.
This commit is contained in:
Hiroki Sato 2014-10-05 02:34:21 +00:00
parent 25108069ec
commit 6d47816791
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=272547
3 changed files with 45 additions and 16 deletions

View File

@ -579,12 +579,13 @@ lacp_port_destroy(struct lagg_port *lgp)
lacp_disable_distributing(lp);
lacp_unselect(lp);
LIST_REMOVE(lp, lp_next);
LACP_UNLOCK(lsc);
/* The address may have already been removed by if_purgemaddrs() */
if (!lgp->lp_detaching)
if_delmulti_ifma(lp->lp_ifma);
LIST_REMOVE(lp, lp_next);
LACP_UNLOCK(lsc);
free(lp, M_DEVBUF);
}
@ -745,7 +746,9 @@ lacp_transit_expire(void *vp)
LACP_LOCK_ASSERT(lsc);
CURVNET_SET(lsc->lsc_softc->sc_ifp->if_vnet);
LACP_TRACE(NULL);
CURVNET_RESTORE();
lsc->lsc_suppress_distributing = FALSE;
}

View File

@ -569,15 +569,15 @@ lagg_clone_destroy(struct ifnet *ifp)
static void
lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr)
{
struct ifnet *ifp = sc->sc_ifp;
struct lagg_port lp;
if (memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0)
return;
LAGG_WLOCK_ASSERT(sc);
bcopy(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
/* Let the protocol know the MAC has changed */
lagg_proto_lladdr(sc);
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
bzero(&lp, sizeof(lp));
lp.lp_ifp = sc->sc_ifp;
lp.lp_softc = sc;
lagg_port_lladdr(&lp, lladdr);
}
static void
@ -648,6 +648,7 @@ lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr)
/* Update the lladdr even if pending, it may have changed */
llq->llq_ifp = ifp;
llq->llq_primary = (sc->sc_primary->lp_ifp == ifp) ? 1 : 0;
bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
if (!pending)
@ -680,14 +681,35 @@ lagg_port_setlladdr(void *arg, int pending)
for (llq = head; llq != NULL; llq = head) {
ifp = llq->llq_ifp;
/* Set the link layer address */
CURVNET_SET(ifp->if_vnet);
error = if_setlladdr(ifp, llq->llq_lladdr, ETHER_ADDR_LEN);
if (llq->llq_primary == 0) {
/*
* Set the link layer address on the laggport interface.
* if_setlladdr() triggers gratuitous ARPs for INET.
*/
error = if_setlladdr(ifp, llq->llq_lladdr,
ETHER_ADDR_LEN);
if (error)
printf("%s: setlladdr failed on %s\n", __func__,
ifp->if_xname);
} else {
/*
* Set the link layer address on the lagg interface.
* lagg_proto_lladdr() notifies the MAC change to
* the aggregation protocol. iflladdr_event handler
* may trigger gratuitous ARPs for INET.
*/
if (memcmp(llq->llq_lladdr, IF_LLADDR(ifp),
ETHER_ADDR_LEN) != 0) {
bcopy(llq->llq_lladdr, IF_LLADDR(ifp),
ETHER_ADDR_LEN);
LAGG_WLOCK(sc);
lagg_proto_lladdr(sc);
LAGG_WUNLOCK(sc);
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
}
}
CURVNET_RESTORE();
if (error)
printf("%s: setlladdr failed on %s\n", __func__,
ifp->if_xname);
head = SLIST_NEXT(llq, llq_entries);
free(llq, M_DEVBUF);
}
@ -1639,7 +1661,7 @@ lagg_input(struct ifnet *ifp, struct mbuf *m)
ETHER_BPF_MTAP(scifp, m);
m = lagg_proto_input(sc, lp, m);
m = (lp->lp_detaching == 0) ? lagg_proto_input(sc, lp, m) : NULL;
if (m != NULL) {
if (scifp->if_flags & IFF_MONITOR) {

View File

@ -159,6 +159,9 @@ struct lagg_reqopts {
#define SIOCGLAGGOPTS _IOWR('i', 152, struct lagg_reqopts)
#define SIOCSLAGGOPTS _IOW('i', 153, struct lagg_reqopts)
#define LAGG_OPT_BITS "\020\001USE_FLOWID\005LACP_STRICT" \
"\006LACP_TXTEST\007LACP_RXTEST"
#ifdef _KERNEL
/*
@ -203,6 +206,7 @@ struct lagg_mc {
struct lagg_llq {
struct ifnet *llq_ifp;
uint8_t llq_lladdr[ETHER_ADDR_LEN];
uint8_t llq_primary;
SLIST_ENTRY(lagg_llq) llq_entries;
};