Date: Mon, 7 Nov 2005 22:41:52 +0300 From: Gleb Smirnoff <glebius@FreeBSD.org> To: arch@FreeBSD.org Subject: Re: ARP request retransmitting Message-ID: <20051107194152.GF91530@cell.sick.ru> In-Reply-To: <20051107140451.GU91530@cell.sick.ru> References: <20051107140451.GU91530@cell.sick.ru>
next in thread | previous in thread | raw e-mail | index | archive | help
--YkJPYEFdoxh/AXLE Content-Type: text/plain; charset=koi8-r Content-Disposition: inline On Mon, Nov 07, 2005 at 05:04:51PM +0300, Gleb Smirnoff wrote: T> I suggest to keep sending ARP requests while there is a demand for T> this (we are trying to transmit packets to this particular IP), T> ratelimiting these requests to one per second. This will help in a T> quite common case, when some host on net is rebooting, and we are T> waiting for him to come up, and notice this only after 1 - 20 seconds T> since the time it is reachable. Here is code explaining what I am speaking about. -- Totus tuus, Glebius. GLEBIUS-RIPN GLEB-RIPE --YkJPYEFdoxh/AXLE Content-Type: text/plain; charset=koi8-r Content-Disposition: attachment; filename="arp.request.diff" Index: if_ether.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/if_ether.c,v retrieving revision 1.144 diff -u -r1.144 if_ether.c --- if_ether.c 4 Oct 2005 19:50:02 -0000 1.144 +++ if_ether.c 7 Nov 2005 19:39:10 -0000 @@ -79,14 +79,11 @@ /* timer values */ static int arpt_prune = (5*60*1); /* walk list every 5 minutes */ static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ -static int arpt_down = 20; /* once declared down, don't send for 20 sec */ SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, &arpt_prune, 0, ""); SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, &arpt_keep, 0, ""); -SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW, - &arpt_down, 0, ""); #define rt_expire rt_rmx.rmx_expire @@ -95,8 +92,7 @@ struct rtentry *la_rt; struct mbuf *la_hold; /* last packet until resolved/timeout */ u_short la_preempt; /* countdown for pre-expiry arps */ - u_short la_asked; /* #times we QUERIED following expiration */ -#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */ + u_short la_asked; /* # requests sent */ }; static LIST_HEAD(, llinfo_arp) llinfo_arp; @@ -104,13 +100,13 @@ static struct ifqueue arpintrq; static int arp_allocated; -static int arp_maxtries = 5; +static int arp_renew = 5; /* request this seconds before expiry */ static int useloopback = 1; /* use loopback interface for local traffic */ static int arp_proxyall = 0; static struct callout arp_callout; -SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, - &arp_maxtries, 0, ""); +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, renew, CTLFLAG_RW, + &arp_renew, 0, ""); SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, &useloopback, 0, ""); SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, @@ -150,7 +146,6 @@ if (rt->rt_refcnt > 1) { sdl->sdl_alen = 0; la->la_preempt = la->la_asked = 0; - rt->rt_flags &= ~RTF_REJECT; RT_UNLOCK(rt); continue; } @@ -448,8 +443,7 @@ /* * If entry has an expiry time and it is approaching, - * see if we need to send an ARP request within this - * arpt_down interval. + * send an ARP request. */ if ((rt->rt_expire != 0) && (time_uptime + la->la_preempt > rt->rt_expire)) { @@ -485,29 +479,33 @@ if (la->la_hold) m_freem(la->la_hold); la->la_hold = m; - if (rt->rt_expire) { - rt->rt_flags &= ~RTF_REJECT; - if (la->la_asked == 0 || rt->rt_expire != time_uptime) { - rt->rt_expire = time_uptime; - if (la->la_asked++ < arp_maxtries) { - struct in_addr sin = - SIN(rt->rt_ifa->ifa_addr)->sin_addr; - RT_UNLOCK(rt); - arprequest(ifp, &sin, &SIN(dst)->sin_addr, - IF_LLADDR(ifp)); - return (EWOULDBLOCK); - } else { - rt->rt_flags |= RTF_REJECT; - rt->rt_expire += arpt_down; - la->la_asked = 0; - la->la_preempt = arp_maxtries; - } + KASSERT(rt->rt_expire > 0, ("sending ARP request for static entry")); - } - } - RT_UNLOCK(rt); - return (EWOULDBLOCK); + /* + * Return EWOULDBLOCK if we are sending first request now, it + * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH + * in case we have already sent ARP requests. Retransmit the + * ARP request, but not faster than one request per second. + */ + if (la->la_asked == 0) + error = EWOULDBLOCK; /* First request. */ + else + error = (rt == rt0) ? EHOSTDOWN : EHOSTUNREACH; + + if (la->la_asked++ == 0 || rt->rt_expire != time_uptime) { + struct in_addr sin = + SIN(rt->rt_ifa->ifa_addr)->sin_addr; + + rt->rt_expire = time_uptime; + RT_UNLOCK(rt); + + arprequest(ifp, &sin, &SIN(dst)->sin_addr, + IF_LLADDR(ifp)); + } else + RT_UNLOCK(rt); + + return (error); } /* @@ -786,9 +784,8 @@ } if (rt->rt_expire) rt->rt_expire = time_uptime + arpt_keep; - rt->rt_flags &= ~RTF_REJECT; la->la_asked = 0; - la->la_preempt = arp_maxtries; + la->la_preempt = arp_renew; hold = la->la_hold; la->la_hold = NULL; RT_UNLOCK(rt); --YkJPYEFdoxh/AXLE--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20051107194152.GF91530>