From owner-svn-src-projects@FreeBSD.ORG Sat Nov 15 20:02:23 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id AE9E2846; Sat, 15 Nov 2014 20:02:23 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9B99D9D; Sat, 15 Nov 2014 20:02:23 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sAFK2NSG002236; Sat, 15 Nov 2014 20:02:23 GMT (envelope-from melifaro@FreeBSD.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sAFK2NKR002235; Sat, 15 Nov 2014 20:02:23 GMT (envelope-from melifaro@FreeBSD.org) Message-Id: <201411152002.sAFK2NKR002235@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: melifaro set sender to melifaro@FreeBSD.org using -f From: "Alexander V. Chernikov" Date: Sat, 15 Nov 2014 20:02:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r274554 - projects/routing/sys/netinet X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 15 Nov 2014 20:02:23 -0000 Author: melifaro Date: Sat Nov 15 20:02:22 2014 New Revision: 274554 URL: https://svnweb.freebsd.org/changeset/base/274554 Log: Move "slow path" handling from arpresolve() to newly-created arpresolve_slow(). Modified: projects/routing/sys/netinet/if_ether.c Modified: projects/routing/sys/netinet/if_ether.c ============================================================================== --- projects/routing/sys/netinet/if_ether.c Sat Nov 15 18:54:07 2014 (r274553) +++ projects/routing/sys/netinet/if_ether.c Sat Nov 15 20:02:22 2014 (r274554) @@ -130,6 +130,8 @@ static void arptimer(void *); #ifdef INET static void in_arpinput(struct mbuf *); #endif +static int arpresolve_slow(struct ifnet *, int is_gw, struct mbuf *, + const struct sockaddr *, u_char *, struct llentry **); static const struct netisr_handler arp_nh = { .nh_name = "arp", @@ -368,13 +370,10 @@ int arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, const struct sockaddr *dst, u_char *desten, struct llentry **lle) { - struct llentry *la = 0; - u_int flags = 0; - struct mbuf *curr = NULL; - struct mbuf *next = NULL; - int create, error, renew; + struct llentry *la = NULL; + int is_gw; + uint16_t la_flags; - create = 0; *lle = NULL; if (m != NULL) { if (m->m_flags & M_BCAST) { @@ -389,16 +388,61 @@ arpresolve(struct ifnet *ifp, struct rte return (0); } } -retry: + + IF_AFDATA_RLOCK(ifp); + la = lla_lookup(LLTABLE(ifp), 0, dst); + IF_AFDATA_RUNLOCK(ifp); + la_flags = la != NULL ? la->la_flags : 0; + + /* Return to slow path if entry is not found or invalid/expired */ + if (la == NULL || (la_flags & LLE_VALID) == 0 || + ((la_flags & LLE_STATIC) == 0 && la->la_expire <= time_uptime)) { + is_gw = (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY)) ? 1 : 0; + if (la != NULL) + LLE_RUNLOCK(la); + return (arpresolve_slow(ifp, is_gw, m, dst, desten, lle)); + } + + + /* Entry found, let's copy lle info */ + bcopy(&la->ll_addr, desten, ifp->if_addrlen); + + /* + * 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) { + arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL); + la->la_preempt--; + } + + /* XXX: Possible use-after-free */ + *lle = la; + LLE_RUNLOCK(la); + return (0); +} + +static int +arpresolve_slow(struct ifnet *ifp, int is_gw, struct mbuf *m, + const struct sockaddr *dst, u_char *desten, struct llentry **lle) +{ + struct llentry *la = 0; + struct mbuf *curr = NULL; + struct mbuf *next = NULL; + int create, error, renew; + + create = 0; + *lle = NULL; + IF_AFDATA_RLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), flags, dst); + la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, 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) { @@ -438,11 +482,6 @@ retry: } 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 @@ -467,11 +506,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 @@ -482,8 +516,7 @@ retry: if (la->la_asked < V_arp_maxtries) error = EWOULDBLOCK; /* First request. */ else - error = rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) ? - EHOSTUNREACH : EHOSTDOWN; + error = (is_gw != 0) ? EHOSTUNREACH : EHOSTDOWN; if (renew) { int canceled; @@ -500,10 +533,7 @@ retry: return (error); } done: - if (flags & LLE_EXCLUSIVE) - LLE_WUNLOCK(la); - else - LLE_RUNLOCK(la); + LLE_WUNLOCK(la); return (error); }