On Thu, Jan 17, 2019 at 03:21:58PM -0700, Theo de Raadt wrote:
> - if (la_hold_total < LA_HOLD_TOTAL && la_hold_total < nmbclust / 64) {
> + if (la_hold_total < nmbclust / 64) {
>
> I have disagreed with claudio about this aspect of the diff.
>
> The refresh attempt is the crucial problem to fix, because of what it has
> done to tcp with slowstart etc.
>
> If refresh works, we may not need to increase the hold mbufs count at all.
>
> Secondly, I don't like how this is coupled to the MD nmbclust value.
> Some architectures have that very large, others very small, for other
> reasons. Bringing it into play here isn't right.
Updated diff that changes this limit back to LA_HOLD_TOTAL (100) but
removes the la_hold_total < nmbclust / 64 check.
--
:wq Claudio
Index: if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.237
diff -u -p -r1.237 if_ether.c
--- if_ether.c 30 Nov 2018 09:27:56 -0000 1.237
+++ if_ether.c 17 Jan 2019 22:59:59 -0000
@@ -67,8 +67,9 @@
struct llinfo_arp {
LIST_ENTRY(llinfo_arp) la_list;
struct rtentry *la_rt; /* backpointer to rtentry */
- long la_asked; /* last time we QUERIED */
struct mbuf_list la_ml; /* packet hold queue */
+ time_t la_refreshed; /* when was refresh sent */
+ int la_asked; /* number of queries sent */
};
#define LA_HOLD_QUEUE 10
#define LA_HOLD_TOTAL 100
@@ -119,7 +120,7 @@ arptimer(void *arg)
LIST_FOREACH_SAFE(la, &arp_list, la_list, nla) {
struct rtentry *rt = la->la_rt;
- if (rt->rt_expire && rt->rt_expire <= time_uptime)
+ if (rt->rt_expire && rt->rt_expire < time_uptime)
arptfree(rt); /* timer has expired; clear */
}
NET_UNLOCK();
@@ -130,7 +131,6 @@ arp_rtrequest(struct ifnet *ifp, int req
{
struct sockaddr *gate = rt->rt_gateway;
struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
- struct ifaddr *ifa;
if (!arpinit_done) {
static struct timeout arptimer_to;
@@ -140,7 +140,7 @@ arp_rtrequest(struct ifnet *ifp, int req
IPL_SOFTNET, 0, "arp", NULL);
timeout_set_proc(&arptimer_to, arptimer, &arptimer_to);
- timeout_add_sec(&arptimer_to, 1);
+ timeout_add_sec(&arptimer_to, arpt_prune);
}
if (ISSET(rt->rt_flags, RTF_GATEWAY|RTF_BROADCAST|RTF_MULTICAST))
@@ -149,17 +149,12 @@ arp_rtrequest(struct ifnet *ifp, int req
switch (req) {
case RTM_ADD:
- if (rt->rt_flags & RTF_CLONING ||
- ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la)) {
- /*
- * Give this route an expiration time, even though
- * it's a "permanent" route, so that routes cloned
- * from it do not need their expiration time set.
- */
- rt->rt_expire = time_uptime;
- if ((rt->rt_flags & RTF_CLONING) != 0)
- break;
+ if (rt->rt_flags & RTF_CLONING) {
+ rt->rt_expire = 0;
+ break;
}
+ if ((rt->rt_flags & RTF_LOCAL) && !la)
+ rt->rt_expire = 0;
/*
* Announce a new entry if requested or warn the user
* if another station has this IP address.
@@ -179,7 +174,7 @@ arp_rtrequest(struct ifnet *ifp, int req
}
satosdl(gate)->sdl_type = ifp->if_type;
satosdl(gate)->sdl_index = ifp->if_index;
- if (la != 0)
+ if (la != NULL)
break; /* This happens on a route change */
/*
* Case 2: This route may come from cloning, or a manual route
@@ -195,18 +190,9 @@ arp_rtrequest(struct ifnet *ifp, int req
ml_init(&la->la_ml);
la->la_rt = rt;
rt->rt_flags |= RTF_LLINFO;
+ if ((rt->rt_flags & RTF_LOCAL) == 0)
+ rt->rt_expire = time_uptime;
LIST_INSERT_HEAD(&arp_list, la, la_list);
-
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
- if ((ifa->ifa_addr->sa_family == AF_INET) &&
- ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
- satosin(rt_key(rt))->sin_addr.s_addr)
- break;
- }
- if (ifa) {
- KASSERT(ifa == rt->rt_ifa);
- rt->rt_expire = 0;
- }
break;
case RTM_DELETE:
@@ -314,7 +300,7 @@ arpresolve(struct ifnet *ifp, struct rte
struct sockaddr *dst, u_char *desten)
{
struct arpcom *ac = (struct arpcom *)ifp;
- struct llinfo_arp *la = NULL;
+ struct llinfo_arp *la;
struct sockaddr_dl *sdl;
struct rtentry *rt = NULL;
char addr[INET_ADDRSTRLEN];
@@ -331,7 +317,7 @@ arpresolve(struct ifnet *ifp, struct rte
rt = rt_getll(rt0);
if (ISSET(rt->rt_flags, RTF_REJECT) &&
- (rt->rt_expire == 0 || time_uptime < rt->rt_expire)) {
+ (rt->rt_expire == 0 || rt->rt_expire > time_uptime )) {
m_freem(m);
return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
}
@@ -352,6 +338,9 @@ arpresolve(struct ifnet *ifp, struct rte
goto bad;
}
+ la = (struct llinfo_arp *)rt->rt_llinfo;
+ KASSERT(la != NULL);
+
/*
* Check the address family and length is valid, the address
* is resolved; otherwise, try to resolve.
@@ -359,6 +348,17 @@ arpresolve(struct ifnet *ifp, struct rte
if ((rt->rt_expire == 0 || rt->rt_expire > time_uptime) &&
sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
memcpy(desten, LLADDR(sdl), sdl->sdl_alen);
+
+ /* refresh ARP entry when timeout gets close */
+ if (rt->rt_expire != 0 &&
+ rt->rt_expire - arpt_keep / 8 < time_uptime &&
+ la->la_refreshed + 30 < time_uptime) {
+ la->la_refreshed = time_uptime;
+ arprequest(ifp,
+ &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr,
+ &satosin(dst)->sin_addr.s_addr,
+ ac->ac_enaddr);
+ }
return (0);
}
@@ -370,9 +370,7 @@ arpresolve(struct ifnet *ifp, struct rte
* response yet. Insert mbuf in hold queue if below limit
* if above the limit free the queue without queuing the new packet.
*/
- la = (struct llinfo_arp *)rt->rt_llinfo;
- KASSERT(la != NULL);
- if (la_hold_total < LA_HOLD_TOTAL && la_hold_total < nmbclust / 64) {
+ if (la_hold_total < LA_HOLD_TOTAL) {
struct mbuf *mh;
if (ml_len(&la->la_ml) >= LA_HOLD_QUEUE) {
@@ -411,6 +409,7 @@ arpresolve(struct ifnet *ifp, struct rte
rt->rt_flags |= RTF_REJECT;
rt->rt_expire += arpt_down;
la->la_asked = 0;
+ la->la_refreshed = 0;
la_hold_total -= ml_purge(&la->la_ml);
}
}
@@ -668,6 +667,7 @@ arpcache(struct ifnet *ifp, struct ether
}
la->la_asked = 0;
+ la->la_refreshed = 0;
while ((len = ml_len(&la->la_ml)) != 0) {
struct mbuf *mh;