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.
  */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to