Subject: Reducing error packets sent back.
To: None <tech-net@netbsd.org>
From: Darren Reed <avalon@coombs.anu.edu.au>
List: tech-net
Date: 01/21/2000 17:09:15
Should we be thinking of adding a knob to control how frequently
NetBSD sends out ICMP unreachables ?  Below I've got a patch which
I just hacked up (untested :) which provides a knob in sysctl to
control how often to actually send an ICMP error back.  I've added
a patch which uses the same knob for ICMP6 (an ICMP error is an
ICMP error, be it v4 or v6).

It should show up as:

net.inet.icmp.errrate

and defaults to 1 (send a reply back every packet).  It surplants
ICMPCTL_MTUDISC (appears to have moved to IP) with ICMPCTL_ERRRATE.

Setting it to 0 turns off sending back ICMP error replies, whereas
a positive number means every nth packet.  I've added stat to count
the number of times it skips sending a packet.

This selective sending of ICMP errors is pretty common now.
Comments ?

btw, is it worthwhile adding a similar knob to TCP to throttle the
sending back of RST's ?

Darren

*** netinet/icmp_var.h.orig	Fri Jan 21 16:41:17 2000
--- netinet/icmp_var.h	Fri Jan 21 16:47:39 2000
***************
*** 45,50 ****
--- 45,51 ----
  struct	icmpstat {
  /* statistics related to icmp packets generated */
  	u_quad_t icps_error;		/* # of calls to icmp_error */
+ 	u_quad_t icps_skip;		/* # of times we skiped sending */
  	u_quad_t icps_oldshort;		/* no error 'cuz old ip too short */
  	u_quad_t icps_oldicmp;		/* no error 'cuz old was icmp */
  	u_quad_t icps_outhist[ICMP_MAXTYPE + 1];
***************
*** 61,72 ****
   * Names for ICMP sysctl objects
   */
  #define	ICMPCTL_MASKREPL	1	/* allow replies to netmask requests */
! #define ICMPCTL_MTUDISC         2       /* allow path MTU discovery */
  #define ICMPCTL_MAXID           3
  
  #define ICMPCTL_NAMES { \
  	{ 0, 0 }, \
  	{ "maskrepl", CTLTYPE_INT }, \
  }
  
  #ifdef _KERNEL
--- 62,74 ----
   * Names for ICMP sysctl objects
   */
  #define	ICMPCTL_MASKREPL	1	/* allow replies to netmask requests */
! #define ICMPCTL_ERRRATE         2       /* flow control of ICMP error replies*/
  #define ICMPCTL_MAXID           3
  
  #define ICMPCTL_NAMES { \
  	{ 0, 0 }, \
  	{ "maskrepl", CTLTYPE_INT }, \
+ 	{ "errrate", CTLTYPE_INT }, \
  }
  
  #ifdef _KERNEL
*** netinet/ip_icmp.c.orig	Fri Jan 21 16:35:23 2000
--- netinet/ip_icmp.c	Fri Jan 21 17:02:30 2000
***************
*** 142,150 ****
--- 142,152 ----
   */
  
  int	icmpmaskrepl = 0;
+ int	icmperrrate = 1;
  #ifdef ICMPPRINTFS
  int	icmpprintfs = 0;
  #endif
+ int	icmp_error_calls = 0;
  
  #if 0
  static int	ip_next_mtu __P((int, int));
***************
*** 196,201 ****
--- 198,211 ----
  	/* Don't send error in response to a multicast or broadcast packet */
  	if (n->m_flags & (M_BCAST|M_MCAST))
  		goto freeit;
+ 	/* Flow control for sending ICMP error messages back */
+ 	icmp_error_calls++;
+ 	if (icmp_error_calls != icmperrrate) {
+ 		icmpstat.icps_skip++;
+ 		goto freeit;
+ 	}
+ 	icmp_error_calls = 0;
+ 
  	/*
  	 * First, formulate icmp message
  	 */
***************
*** 729,734 ****
--- 739,746 ----
  	switch (name[0]) {
  	case ICMPCTL_MASKREPL:
  		return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl));
+ 	case ICMPCTL_ERRRATE:
+ 		return (sysctl_int(oldp, oldlenp, newp, newlen, &icmperrrate));
  	default:
  		return (ENOPROTOOPT);
  	}
*** netinet6/icmp6.c.orig	Fri Jan 21 16:59:41 2000
--- netinet6/icmp6.c	Fri Jan 21 17:04:28 2000
***************
*** 117,122 ****
--- 117,124 ----
  extern int icmp6_nodeinfo;
  static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
  extern int pmtu_expire;
+ extern int icmp_error_calls;
+ extern int icmperrrate;
  
  static int icmp6_rip6_input __P((struct mbuf **, int));
  static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
***************
*** 280,285 ****
--- 282,295 ----
  		goto freeit;
  	}
  
+ 	/* Flow control for sending ICMP error messages back */
+ 	icmp_error_calls++;
+ 	if (icmp_error_calls != icmperrrate) {
+ 		icmp6stat.icp6s_skip++;
+ 		goto freeit;
+ 	}
+ 	icmp_error_calls = 0;
+ 
  	/*
  	 * OK, ICMP6 can be generated.
  	 */
*** netinet6/icmp6.h.orig	Fri Jan 21 17:00:13 2000
--- netinet6/icmp6.h	Fri Jan 21 17:00:53 2000
***************
*** 500,505 ****
--- 500,506 ----
  struct icmp6stat {
  /* statistics related to icmp6 packets generated */
  	u_quad_t icp6s_error;		/* # of calls to icmp6_error */
+ 	u_quad_t icp6s_skip;		/* # of times we skiped sending */
  	u_quad_t icp6s_canterror;	/* no error 'cuz old was icmp */
  	u_quad_t icp6s_toofreq;		/* no error 'cuz rate limitation */
  	u_quad_t icp6s_outhist[256];