Skip site navigation (1)Skip section navigation (2)
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>