ARP request retransmitting
Gleb Smirnoff
glebius at FreeBSD.org
Mon Nov 7 11:41:57 PST 2005
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
-------------- next part --------------
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);
More information about the freebsd-arch
mailing list