Subject: Re: ARP problems.
To: None <tech-net@netbsd.org>
From: None <ragge@ludd.luth.se>
List: tech-net
Date: 04/22/2004 17:17:41
On Friday 19 March 2004 20:02, ragge@ludd.luth.se wrote:
> The ARP implementation in NetBSD will delete an existing ARP
> entry after arpt_keep seconds (20 minutes), regardless whether
> there are traffic on the interface or not, and do a new ARP
> request if a new packet is sent out for that route.

Ok, here's patches for in_arp.c.  When there is (less than)
arpt_refresh seconds left before entry timeout and the entry
have been used during the expire period, send out an arp 
request for the host again.  This prevents deletion of active
routing entries.

I also added sysctls to be able to tune the arp timeouts.

-- Ragge

Index: if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.96
diff -c -r1.96 if_arp.c
*** if_arp.c	22 Apr 2004 01:01:40 -0000	1.96
--- if_arp.c	22 Apr 2004 15:09:18 -0000
***************
*** 98,103 ****
--- 98,104 ----
  #include <sys/proc.h>
  #include <sys/protosw.h>
  #include <sys/domain.h>
+ #include <sys/sysctl.h>
  
  #include <net/ethertypes.h>
  #include <net/if.h>
***************
*** 137,143 ****
--- 138,146 ----
  int	arpt_prune = (5*60*1);	/* walk list every 5 minutes */
  int	arpt_keep = (20*60);	/* once resolved, good for 20 more minutes */
  int	arpt_down = 20;		/* once declared down, don't send for 20 secs */
+ int	arpt_refresh = (5*60);	/* time left before refreshing */
  #define	rt_expire rt_rmx.rmx_expire
+ #define	rt_pksent rt_rmx.rmx_pksent
  
  extern	struct domain arpdomain;
  
***************
*** 356,362 ****
  		struct rtentry *rt = la->la_rt;
  
  		nla = LIST_NEXT(la, la_list);
! 		if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
  			arptfree(la); /* timer has expired; clear */
  	}
  
--- 359,377 ----
  		struct rtentry *rt = la->la_rt;
  
  		nla = LIST_NEXT(la, la_list);
! 		if (rt->rt_expire == 0)
! 			continue;
! 		if ((rt->rt_expire - time.tv_sec) < arpt_refresh &&
! 		    rt->rt_pksent > (time.tv_sec - arpt_keep)) {
! 			/*
! 			 * If the entry has been used during since last
! 			 * refresh, try to renew it before deleting.
! 			 */
! 			arprequest(rt->rt_ifp,
! 			    &SIN(rt->rt_ifa->ifa_addr)->sin_addr,
! 			    &SIN(rt_key(rt))->sin_addr,
! 			    LLADDR(rt->rt_ifp->if_sadl));
! 		} else if (rt->rt_expire <= time.tv_sec)
  			arptfree(la); /* timer has expired; clear */
  	}
  
***************
*** 698,703 ****
--- 713,719 ----
  	    sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
  		bcopy(LLADDR(sdl), desten,
  		    min(sdl->sdl_alen, ifp->if_addrlen));
+ 		rt->rt_pksent = time.tv_sec; /* Time for last pkt sent */
  		return 1;
  	}
  	/*
***************
*** 1490,1493 ****
--- 1506,1555 ----
  	return;
  }
  #endif
+ 
+ SYSCTL_SETUP(sysctl_net_inet_arp_setup, "sysctl net.inet.arp subtree setup")
+ {
+ 	struct sysctlnode *node;
+ 
+ 	sysctl_createv(clog, 0, NULL, NULL,
+ 			CTLFLAG_PERMANENT,
+ 			CTLTYPE_NODE, "net", NULL,
+ 			NULL, 0, NULL, 0,
+ 			CTL_NET, CTL_EOL);
+ 	sysctl_createv(clog, 0, NULL, NULL,
+ 			CTLFLAG_PERMANENT,
+ 			CTLTYPE_NODE, "inet", NULL,
+ 			NULL, 0, NULL, 0,
+ 			CTL_NET, PF_INET, CTL_EOL);
+ 	sysctl_createv(clog, 0, NULL, &node,
+ 			CTLFLAG_PERMANENT,
+ 			CTLTYPE_NODE, "arp", NULL,
+ 			NULL, 0, NULL, 0,
+ 			CTL_NET, PF_INET, CTL_CREATE, CTL_EOL);
+ 
+ 	sysctl_createv(clog, 0, NULL, NULL,
+ 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ 			CTLTYPE_INT, "prune", NULL,
+ 			NULL, 0, &arpt_prune, 0,
+ 			CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
+ 
+ 	sysctl_createv(clog, 0, NULL, NULL,
+ 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ 			CTLTYPE_INT, "keep", NULL,
+ 			NULL, 0, &arpt_keep, 0,
+ 			CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
+ 
+ 	sysctl_createv(clog, 0, NULL, NULL,
+ 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ 			CTLTYPE_INT, "down", NULL,
+ 			NULL, 0, &arpt_down, 0,
+ 			CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
+ 
+ 	sysctl_createv(clog, 0, NULL, NULL,
+ 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ 			CTLTYPE_INT, "refresh", NULL,
+ 			NULL, 0, &arpt_refresh, 0,
+ 			CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
+ }
+ 
  #endif /* INET */