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
This commit is contained in:
parent
cbebdcf01c
commit
bc522110e3
@ -309,57 +309,37 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
|
||||
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 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
|
||||
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 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
|
||||
} 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,14 +428,87 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user