svn commit: r272547 - head/sys/net

Hiroki Sato hrs at FreeBSD.org
Sun Oct 5 02:34:23 UTC 2014


Author: hrs
Date: Sun Oct  5 02:34:21 2014
New Revision: 272547
URL: https://svnweb.freebsd.org/changeset/base/272547

Log:
  - 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.

Modified:
  head/sys/net/ieee8023ad_lacp.c
  head/sys/net/if_lagg.c
  head/sys/net/if_lagg.h

Modified: head/sys/net/ieee8023ad_lacp.c
==============================================================================
--- head/sys/net/ieee8023ad_lacp.c	Sun Oct  5 02:16:53 2014	(r272546)
+++ head/sys/net/ieee8023ad_lacp.c	Sun Oct  5 02:34:21 2014	(r272547)
@@ -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;
 }

Modified: head/sys/net/if_lagg.c
==============================================================================
--- head/sys/net/if_lagg.c	Sun Oct  5 02:16:53 2014	(r272546)
+++ head/sys/net/if_lagg.c	Sun Oct  5 02:34:21 2014	(r272547)
@@ -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);
+
+	bzero(&lp, sizeof(lp));
+	lp.lp_ifp = sc->sc_ifp;
+	lp.lp_softc = 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);
+	lagg_port_lladdr(&lp, lladdr);
 }
 
 static void
@@ -648,6 +648,7 @@ lagg_port_lladdr(struct lagg_port *lp, u
 
 	/* 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 pendi
 	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 mbu
 
 	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) {

Modified: head/sys/net/if_lagg.h
==============================================================================
--- head/sys/net/if_lagg.h	Sun Oct  5 02:16:53 2014	(r272546)
+++ head/sys/net/if_lagg.h	Sun Oct  5 02:34:21 2014	(r272547)
@@ -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;
 };
 


More information about the svn-src-head mailing list