svn commit: r286825 - head/sys/netinet

Alexander V. Chernikov melifaro at FreeBSD.org
Sun Aug 16 12:23:59 UTC 2015


Author: melifaro
Date: Sun Aug 16 12:23:58 2015
New Revision: 286825
URL: https://svnweb.freebsd.org/changeset/base/286825

Log:
  Split arpresolve() into fast/slow path.
  
  This change isolates the most common case (e.g. successful lookup)
    from more complicates scenarios. It also (tries to) make code
    more simple by avoiding retry: cycle.
  
  The actual goal is to prepare code to the upcoming change that will
    allow LL address retrieval without acquiring LLE lock at all.
  
  Reviewed by:		ae
  Differential Revision:	https://reviews.freebsd.org/D3383

Modified:
  head/sys/netinet/if_ether.c

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c	Sun Aug 16 12:09:55 2015	(r286824)
+++ head/sys/netinet/if_ether.c	Sun Aug 16 12:23:58 2015	(r286825)
@@ -309,57 +309,37 @@ arprequest(struct ifnet *ifp, const stru
 }
 
 /*
- * Resolve an IP address into an ethernet address.
- * On input:
- *    ifp is the interface we use
- *    is_gw != if @dst represents gateway to some destination
- *    m is the mbuf. May be NULL if we don't have a packet.
- *    dst is the next hop,
- *    desten is where we want the address.
- *    flags returns lle entry flags.
+ * Resolve an IP address into an ethernet address - heavy version.
+ * Used internally by arpresolve().
+ * We have already checked than  we can't use existing lle without
+ * modification so we have to acquire LLE_EXCLUSIVE lle lock.
  *
  * On success, desten and flags are filled in and the function returns 0;
  * If the packet must be held pending resolution, we return EWOULDBLOCK
  * On other errors, we return the corresponding error code.
  * Note that m_freem() handles NULL.
  */
-int
-arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
+static int
+arpresolve_full(struct ifnet *ifp, int is_gw, int create, struct mbuf *m,
 	const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
 {
-	struct llentry *la = 0;
-	u_int flags = 0;
+	struct llentry *la = NULL;
 	struct mbuf *curr = NULL;
 	struct mbuf *next = NULL;
-	int create, error, renew;
+	int error, renew;
 
 	if (pflags != NULL)
 		*pflags = 0;
 
-	create = 0;
-	if (m != NULL) {
-		if (m->m_flags & M_BCAST) {
-			/* broadcast */
-			(void)memcpy(desten,
-			    ifp->if_broadcastaddr, ifp->if_addrlen);
-			return (0);
-		}
-		if (m->m_flags & M_MCAST) {
-			/* multicast */
-			ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
-			return (0);
-		}
+	if (create == 0) {
+		IF_AFDATA_RLOCK(ifp);
+		la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst);
+		IF_AFDATA_RUNLOCK(ifp);
 	}
-retry:
-	IF_AFDATA_RLOCK(ifp);
-	la = lla_lookup(LLTABLE(ifp), flags, dst);
-	IF_AFDATA_RUNLOCK(ifp);
-	if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0)
-	    && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) {
+	if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
 		create = 1;
-		flags |= LLE_EXCLUSIVE;
 		IF_AFDATA_WLOCK(ifp);
-		la = lla_create(LLTABLE(ifp), flags, dst);
+		la = lla_create(LLTABLE(ifp), 0, dst);
 		IF_AFDATA_WUNLOCK(ifp);
 	}
 	if (la == NULL) {
@@ -389,10 +369,7 @@ retry:
 		if (pflags != NULL)
 			*pflags = la->la_flags;
 
-		if (flags & LLE_EXCLUSIVE)
-			LLE_WUNLOCK(la);
-		else
-			LLE_RUNLOCK(la);
+		LLE_WUNLOCK(la);
 
 		if (renew == 1)
 			arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
@@ -400,20 +377,7 @@ retry:
 		return (0);
 	}
 
-	if (la->la_flags & LLE_STATIC) {   /* should not happen! */
-		log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n",
-		    inet_ntoa(SIN(dst)->sin_addr));
-		m_freem(m);
-		error = EINVAL;
-		goto done;
-	}
-
 	renew = (la->la_asked == 0 || la->la_expire != time_uptime);
-	if ((renew || m != NULL) && (flags & LLE_EXCLUSIVE) == 0) {
-		flags |= LLE_EXCLUSIVE;
-		LLE_RUNLOCK(la);
-		goto retry;
-	}
 	/*
 	 * There is an arptab entry, but no ethernet address
 	 * response yet.  Add the mbuf to the list, dropping
@@ -438,11 +402,6 @@ retry:
 		} else
 			la->la_hold = m;
 		la->la_numheld++;
-		if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
-			flags &= ~LLE_EXCLUSIVE;
-			LLE_DOWNGRADE(la);
-		}
-
 	}
 	/*
 	 * Return EWOULDBLOCK if we have tried less than arp_maxtries. It
@@ -469,15 +428,88 @@ retry:
 		arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
 		return (error);
 	}
-done:
-	if (flags & LLE_EXCLUSIVE)
-		LLE_WUNLOCK(la);
-	else
-		LLE_RUNLOCK(la);
+
+	LLE_WUNLOCK(la);
 	return (error);
 }
 
 /*
+ * Resolve an IP address into an ethernet address.
+ * On input:
+ *    ifp is the interface we use
+ *    is_gw != 0 if @dst represents gateway to some destination
+ *    m is the mbuf. May be NULL if we don't have a packet.
+ *    dst is the next hop,
+ *    desten is the storage to put LL address.
+ *    flags returns lle entry flags.
+ *
+ * On success, desten and flags are filled in and the function returns 0;
+ * If the packet must be held pending resolution, we return EWOULDBLOCK
+ * On other errors, we return the corresponding error code.
+ * Note that m_freem() handles NULL.
+ */
+int
+arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
+	const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
+{
+	struct llentry *la = 0;
+	int renew;
+
+	if (pflags != NULL)
+		*pflags = 0;
+
+	if (m != NULL) {
+		if (m->m_flags & M_BCAST) {
+			/* broadcast */
+			(void)memcpy(desten,
+			    ifp->if_broadcastaddr, ifp->if_addrlen);
+			return (0);
+		}
+		if (m->m_flags & M_MCAST) {
+			/* multicast */
+			ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
+			return (0);
+		}
+	}
+
+	IF_AFDATA_RLOCK(ifp);
+	la = lla_lookup(LLTABLE(ifp), 0, dst);
+	IF_AFDATA_RUNLOCK(ifp);
+
+	if (la == NULL)
+		return (arpresolve_full(ifp, is_gw, 1, m, dst, desten, pflags));
+
+	if ((la->la_flags & LLE_VALID) &&
+	    ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) {
+		bcopy(&la->ll_addr, desten, ifp->if_addrlen);
+		renew = 0;
+		/*
+		 * If entry has an expiry time and it is approaching,
+		 * see if we need to send an ARP request within this
+		 * arpt_down interval.
+		 */
+		if (!(la->la_flags & LLE_STATIC) &&
+		    time_uptime + la->la_preempt > la->la_expire) {
+			renew = 1;
+			la->la_preempt--;
+		}
+
+		if (pflags != NULL)
+			*pflags = la->la_flags;
+
+		LLE_RUNLOCK(la);
+
+		if (renew == 1)
+			arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
+
+		return (0);
+	}
+	LLE_RUNLOCK(la);
+
+	return (arpresolve_full(ifp, is_gw, 0, m, dst, desten, pflags));
+}
+
+/*
  * Common length and type checks are done here,
  * then the protocol-specific routine is called.
  */


More information about the svn-src-head mailing list