Subject: ppsratecheck(9)
To: None <tech-kern@netbsd.org>
From: None <itojun@iijlab.net>
List: tech-kern
Date: 07/06/2000 22:35:53
	kjc (of ALTQ) suggested me that:
	- ratelimit(9) makes sense only for large intervals, due to limited
	  timer resolution in BSDs (hz)
	- using ratelimit(9), with small interval, for icmp6/icmp does not
	  make sense
	- if we implement something for icmp6/icmp/tcp-rst limitation,
	  it should better be packet-per-sec limitation

	so, here's ppsratecheck(9).  it basically try to limit some
	event (like icmp6 error transmission) to happen less than X
	occurrences-per-second.
	you may have different idea about function names or argument types,
	i'm not good at naming things:-)

itojun


Index: kern/kern_time.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_time.c,v
retrieving revision 1.48
diff -c -r1.48 kern_time.c
*** kern_time.c	2000/06/27 17:41:31	1.48
--- kern_time.c	2000/07/06 13:31:17
***************
*** 663,665 ****
--- 663,703 ----
  
  	return (rv);
  }
+ 
+ /*
+  * ppsratecheck(): packets (or events) per second limitation.
+  */
+ int
+ ppsratecheck(lasttime, curpps, maxpps)
+ 	struct timeval *lasttime;
+ 	int *curpps;
+ 	int maxpps;	/* maximum pps allowed */
+ {
+ 	struct timeval delta;
+ 	int s, rv;
+ 
+ 	s = splclock(); 
+ 	timersub(&mono_time, lasttime, &delta);
+ 
+ 	/*
+ 	 * check for 0,0 is so that the message will be seen at least once.
+ 	 * if more than one second have passed since the last update of
+ 	 * lasttime, start over.
+ 	 */
+ 	if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
+ 	    delta.tv_sec > 0) {
+ 		*lasttime = mono_time;
+ 		*curpps = 0;
+ 		rv = 1;
+ 	} else if (*curpps < maxpps)
+ 		rv = 1;
+ 	else
+ 		rv = 0;
+ 	/* be careful about wrap-around */
+ 	if (*curpps + 1 > *curpps)
+ 		*curpps = *curpps + 1;
+ 
+ 	splx(s);
+ 
+ 	return (rv);
+ }
Index: sys/time.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/time.h,v
retrieving revision 1.29
diff -c -r1.29 time.h
*** time.h	2000/02/03 23:04:45	1.29
--- time.h	2000/07/06 13:31:17
***************
*** 164,169 ****
--- 164,170 ----
  void	microtime __P((struct timeval *tv));
  int	settime __P((struct timeval *));
  int	ratecheck __P((struct timeval *, const struct timeval *));
+ int	ppsratecheck __P((struct timeval *, int *, int));
  #else /* !_KERNEL */
  
  #ifndef _STANDALONE
Index: netinet6/icmp6.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/icmp6.c,v
retrieving revision 1.35
diff -c -r1.35 icmp6.c
*** icmp6.c	2000/07/06 12:36:18	1.35
--- icmp6.c	2000/07/06 13:31:18
***************
*** 115,120 ****
--- 115,121 ----
  static struct timeval icmp6errratelim_last;
  extern int icmp6errppslim;
  static int icmp6errpps_count = 0;
+ static struct timeval icmp6errppslim_last;
  extern int icmp6_nodeinfo;
  static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
  extern int pmtu_expire;
***************
*** 1962,1969 ****
--- 1963,1972 ----
  
  	mld6_fasttimeo();
  
+ #if 0
  	/* reset ICMPv6 pps limit */
  	icmp6errpps_count = 0;
+ #endif
  }
  
  static const char *
***************
*** 2566,2576 ****
--- 2569,2587 ----
  	ret = 0;	/*okay to send*/
  
  	/* PPS limit */
+ #if 0
  	icmp6errpps_count++;
  	if (icmp6errppslim && icmp6errpps_count > icmp6errppslim / 5) {
  		/* The packet is subject to pps limit */
  		ret++;
  	}
+ #else
+ 	if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
+ 	    icmp6errppslim)) {
+ 		/* The packet is subject to rate limit */
+ 		ret++;
+ 	}
+ #endif
  
  	if (!ratecheck(&icmp6errratelim_last, &icmp6errratelim)) {
  		/* The packet is subject to rate limit */