svn commit: r273210 - head/sys/net

Hiroki Sato hrs at FreeBSD.org
Fri Oct 17 09:08:45 UTC 2014


Author: hrs
Date: Fri Oct 17 09:08:44 2014
New Revision: 273210
URL: https://svnweb.freebsd.org/changeset/base/273210

Log:
  - Fix lladdr configuration which could prevent LACP mode from working.
  - Fix LORs when a laggport interface has an IPv6 LLA.
  
  PR:	194321

Modified:
  head/sys/net/if_lagg.c

Modified: head/sys/net/if_lagg.c
==============================================================================
--- head/sys/net/if_lagg.c	Fri Oct 17 07:58:51 2014	(r273209)
+++ head/sys/net/if_lagg.c	Fri Oct 17 09:08:44 2014	(r273210)
@@ -569,9 +569,22 @@ 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);
+	/*
+	 * Set the link layer address on the lagg interface.
+	 * lagg_proto_lladdr() notifies the MAC change to
+	 * the aggregation protocol.  iflladdr_event handler which
+	 * may trigger gratuitous ARPs for INET will be handled in
+	 * a taskqueue.
+	 */
+	bcopy(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+	lagg_proto_lladdr(sc);
 
 	bzero(&lp, sizeof(lp));
 	lp.lp_ifp = sc->sc_ifp;
@@ -625,11 +638,13 @@ lagg_port_lladdr(struct lagg_port *lp, u
 	struct ifnet *ifp = lp->lp_ifp;
 	struct lagg_llq *llq;
 	int pending = 0;
+	int primary;
 
 	LAGG_WLOCK_ASSERT(sc);
 
-	if (lp->lp_detaching ||
-	    memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0)
+	primary = (sc->sc_primary->lp_ifp == ifp) ? 1 : 0;
+	if (primary == 0 && (lp->lp_detaching ||
+	    memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0))
 		return;
 
 	/* Check to make sure its not already queued to be changed */
@@ -648,7 +663,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;
+	llq->llq_primary = primary;
 	bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
 
 	if (!pending)
@@ -692,23 +707,8 @@ lagg_port_setlladdr(void *arg, int pendi
 			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);
-			}
-		}
+		} else
+			EVENTHANDLER_INVOKE(iflladdr_event, ifp);
 		CURVNET_RESTORE();
 		head = SLIST_NEXT(llq, llq_entries);
 		free(llq, M_DEVBUF);
@@ -742,34 +742,6 @@ lagg_port_create(struct lagg_softc *sc, 
 	if (ifp->if_type != IFT_ETHER)
 		return (EPROTONOSUPPORT);
 
-#ifdef INET6
-	/*
-	 * The member interface should not have inet6 address because
-	 * two interfaces with a valid link-local scope zone must not be
-	 * merged in any form.  This restriction is needed to
-	 * prevent violation of link-local scope zone.  Attempts to
-	 * add a member interface which has inet6 addresses triggers
-	 * removal of all inet6 addresses on the member interface.
-	 */
-	SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
-		if (in6ifa_llaonifp(lp->lp_ifp)) {
-			in6_ifdetach(lp->lp_ifp);
-			if_printf(sc->sc_ifp,
-			    "IPv6 addresses on %s have been removed "
-			    "before adding it as a member to prevent "
-			    "IPv6 address scope violation.\n",
-			    lp->lp_ifp->if_xname);
-		}
-	}
-	if (in6ifa_llaonifp(ifp)) {
-		in6_ifdetach(ifp);
-		if_printf(sc->sc_ifp,
-		    "IPv6 addresses on %s have been removed "
-		    "before adding it as a member to prevent "
-		    "IPv6 address scope violation.\n",
-		    ifp->if_xname);
-	}
-#endif
 	/* Allow the first Ethernet member to define the MTU */
 	if (SLIST_EMPTY(&sc->sc_ports))
 		sc->sc_ifp->if_mtu = ifp->if_mtu;
@@ -1414,6 +1386,26 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd
 			error = EINVAL;
 			break;
 		}
+#ifdef INET6
+		/*
+		 * A laggport interface should not have inet6 address
+		 * because two interfaces with a valid link-local
+		 * scope zone must not be merged in any form.  This
+		 * restriction is needed to prevent violation of
+		 * link-local scope zone.  Attempts to add a laggport
+		 * interface which has inet6 addresses triggers
+		 * removal of all inet6 addresses on the member
+		 * interface.
+		 */
+		if (in6ifa_llaonifp(tpif)) {
+			in6_ifdetach(tpif);
+				if_printf(sc->sc_ifp,
+				    "IPv6 addresses on %s have been removed "
+				    "before adding it as a member to prevent "
+				    "IPv6 address scope violation.\n",
+				    tpif->if_xname);
+		}
+#endif
 		LAGG_WLOCK(sc);
 		error = lagg_port_create(sc, tpif);
 		LAGG_WUNLOCK(sc);


More information about the svn-src-all mailing list