From nobody@FreeBSD.org  Thu Jan 15 19:23:54 2004
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 8DA0116A4CE
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 15 Jan 2004 19:23:54 -0800 (PST)
Received: from www.freebsd.org (www.freebsd.org [216.136.204.117])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 7806643D53
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 15 Jan 2004 19:23:52 -0800 (PST)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.12.10/8.12.10) with ESMTP id i0G3NqdL092051
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 15 Jan 2004 19:23:52 -0800 (PST)
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.12.10/8.12.10/Submit) id i0G3NqKS092050;
	Thu, 15 Jan 2004 19:23:52 -0800 (PST)
	(envelope-from nobody)
Message-Id: <200401160323.i0G3NqKS092050@www.freebsd.org>
Date: Thu, 15 Jan 2004 19:23:52 -0800 (PST)
From: Tom Pavel <pavel@alum.mit.edu>
To: freebsd-gnats-submit@FreeBSD.org
Subject: RFC1323 timestamps with HZ > 1000
X-Send-Pr-Version: www-2.0

>Number:         61404
>Category:       kern
>Synopsis:       RFC1323 timestamps with HZ > 1000
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bz
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 15 19:30:17 PST 2004
>Closed-Date:    Sat May 19 18:38:50 UTC 2012
>Last-Modified:  Sat May 19 18:40:05 UTC 2012
>Originator:     Tom Pavel
>Release:        4.6
>Organization:
Network Physics
>Environment:
FreeBSD transam2.networkphysics.com NP-1000-20031121 FreeBSD NP-1000-20031121 #1: Fri Nov 21 10:50:55 PST 2003     pavel@focus30.fractal.networkphysics.com:/u1/builds/3.0.3/FreeBSD/sys/compile/NP1000UNI-MONITOR  i386
>Description:

See discussion in: 
http://docs.freebsd.org/cgi/mid.cgi?200401142204.i0EM4JQX087048

>How-To-Repeat:
      
>Fix:
      
Index: tcp_input.c
===================================================================
RCS file: /u1/Repo/FreeBSD/sys/netinet/tcp_input.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- tcp_input.c	2 Apr 2002 23:27:33 -0000	1.41
+++ tcp_input.c	3 Apr 2002 22:24:24 -0000	1.42
@@ -1185,7 +1185,7 @@
 		 */
 		if ((to.to_flag & TOF_TS) != 0 &&
 		   SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
-			tp->ts_recent_age = ticks;
+			GETCURTS(tp->ts_recent_age);
 			tp->ts_recent = to.to_tsval;
 		}
 
@@ -1228,9 +1228,12 @@
                          && ((!(sack_check(tp))) ||
 			     to.to_tsecr)
 #endif
-			    )
-			    tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
-			else {
+			    ) {
+			    u_long cur_ts, rtt_ticks;
+			    GETCURTS(cur_ts);
+			    rtt_ticks = TSTMPTOTICK (cur_ts - to.to_tsecr);
+			    tcp_xmit_timer(tp, rtt_ticks  + 1);
+			} else {
 #ifdef LTSTMP
 			    tcp_xmit_timer(tp, tp->t_rtttime);
 #else
@@ -1941,9 +1944,11 @@
 	 */
 	if ((to.to_flag & TOF_TS) != 0 && tp->ts_recent &&
 	    TSTMP_LT(to.to_tsval, tp->ts_recent)) {
+	    	u_long cur_ts;
 
 		/* Check to see if ts_recent is over 24 days old.  */
-		if ((int)(ticks - tp->ts_recent_age) > TCP_PAWS_IDLE) {
+		GETCURTS(cur_ts);
+		if ((int)(cur_ts - tp->ts_recent_age) > TCP_PAWS_IDLE) {
 			/*
 			 * Invalidate ts_recent.  If this segment updates
 			 * ts_recent, the age will be reset later and ts_recent
@@ -2120,7 +2125,7 @@
 	 */
 	if ((to.to_flag & TOF_TS) != 0 &&
 	    SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
-		tp->ts_recent_age = ticks;
+	    	GETCURTS(tp->ts_recent_age);
 		tp->ts_recent = to.to_tsval;
 	}
 
@@ -2754,9 +2759,12 @@
               /* bug fix from Mark Allman  */
 		&& ((!sack_check(tp)) || to.to_tsecr)
 #endif
-		    )
-			tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
-		else {
+		    ) {
+		    	u_long cur_ts, rtt_ticks;
+			GETCURTS(cur_ts);
+			rtt_ticks = TSTMPTOTICK (cur_ts - to.to_tsecr);
+			tcp_xmit_timer(tp, rtt_ticks  + 1);
+		} else {
 
 #ifdef LTSTMP    /* use local timestamp */
 		tcp_xmit_timer(tp, tp->t_rtttime);
@@ -3293,7 +3301,7 @@
 			if (th->th_flags & TH_SYN) {
 				tp->t_flags |= TF_RCVD_TSTMP;
 				tp->ts_recent = to->to_tsval;
-				tp->ts_recent_age = ticks;
+				GETCURTS(tp->ts_recent_age);
 			}
 			break;
 
Index: tcp_output.c
===================================================================
RCS file: /u1/Repo/FreeBSD/sys/netinet/tcp_output.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- tcp_output.c	3 Apr 2002 01:55:20 -0000	1.32
+++ tcp_output.c	3 Apr 2002 22:24:24 -0000	1.33
@@ -616,7 +616,8 @@
 
  		/* Form timestamp option as shown in appendix A of RFC 1323. */
  		*lp++ = htonl(TCPOPT_TSTAMP_HDR);
- 		*lp++ = htonl(ticks);
+		GETCURTS(*lp);
+ 		*lp++ = htonl(*lp);
  		*lp   = htonl(tp->ts_recent);
  		optlen += TCPOLEN_TSTAMP_APPA;
  	}
Index: tcp_seq.h
===================================================================
RCS file: /u1/Repo/FreeBSD/sys/netinet/tcp_seq.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- tcp_seq.h	16 Jul 2001 18:18:44 -0000	1.2
+++ tcp_seq.h	3 Apr 2002 22:24:24 -0000	1.3
@@ -88,8 +88,19 @@
 	    (tp)->iss
 #endif
 
-#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * hz)
-					/* timestamp wrap-around time */
+/* clock macros for RFC1323 timestamps */
+#define TSTMP_UNITS	(10)	/* in ms (RFC1323 says 1-1000 ms) */
+#define GETCURTS(ts)							\
+	do {								\
+    		struct timeval tv;					\
+		getmicrouptime(&tv);					\
+		(ts) = (u_long)tv.tv_sec * 1000 + tv.tv_usec / 1000;	\
+		(ts) /= TSTMP_UNITS;					\
+	} while (0) 
+#define TSTMPTOTICK(ts) (((int64_t)(ts))*hz*TSTMP_UNITS/1000)
+
+#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * 1000/TSTMP_UNITS)
+                       /* timestamp wrap-around time (24 days in 10ms units) */
 
 #ifdef _KERNEL
 extern tcp_cc	tcp_ccgen;		/* global connection count */
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org"

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->andre 
Responsible-Changed-By: andre 
Responsible-Changed-When: Sat Jan 17 08:15:07 PST 2004 
Responsible-Changed-Why:  
Take over. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=61404 
Responsible-Changed-From-To: andre->silby 
Responsible-Changed-By: kmacy 
Responsible-Changed-When: Thu Nov 15 23:11:01 UTC 2007 
Responsible-Changed-Why:  

silby is currently active 

http://www.freebsd.org/cgi/query-pr.cgi?pr=61404 

From: "Bjoern A. Zeeb" <bz@FreeBSD.org>
To: bug-followup@FreeBSD.org, pavel@alum.mit.edu
Cc:  
Subject: Re: kern/61404: RFC1323 timestamps with HZ > 1000
Date: Tue, 22 Nov 2011 12:56:05 +0000 (UTC)

 Hi,
 
 the issue still exists and I have updated the patch a bit.  Could you
 please give it a try (or review) and let me know.
 
 /bz
 
 
 
 !
 ! http://people.freebsd.org/~bz/20110623-01-pr61404-2.diff
 !
 ! Update patch from PR61404:
 ! - Adjust to more modern TCP stack.
 ! - Use an inline function rather than a macro.
 ! - Try to automatically adjust TSTMP_UNIT, keeping it at
 !   1ms for hz<=1000 but going up to then as hz goes up, e.g.
 !   10ms for hz=10000.  Odd values of hz will give odd results
 !   but I'd expect that to be a general statement for the entire
 !   kernel.
 ! - This should only change the timestamps we send and get looped
 !   back but not actually timers.
 ! - Using getmicrouptime() as getmicrotime() may make a huge jump
 !   around the time we started to do an nfsroot mount breaking
 !   PAWS on the remote system as our timestamps move forward more
 !   than 24.8 days in a second without having been idle for that
 !   long.
 ! - Testbooted with hz=100, hz=1000 and hz=4000.
 !
 ! This needs very careful review.
 !
 ! PR:		kern/61404
 ! Sponsored by:	Sandvine Incorporated
 !
 Index: sys/netinet/tcp_input.c
 ===================================================================
 --- sys/netinet/tcp_input.c	(revision 223592)
 +++ sys/netinet/tcp_input.c	(working copy)
 @@ -1518,7 +1518,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th,
   	 */
   	if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) {
   		to.to_tsecr -= tp->ts_offset;
 -		if (TSTMP_GT(to.to_tsecr, ticks))
 +		if (TSTMP_GT(to.to_tsecr, tstmp_getticks()))
   			to.to_tsecr = 0;
   	}
 
 @@ -1543,7 +1543,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th,
   		if (to.to_flags & TOF_TS) {
   			tp->t_flags |= TF_RCVD_TSTMP;
   			tp->ts_recent = to.to_tsval;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tstmp_getticks();
   		}
   		if (to.to_flags & TOF_MSS)
   			tcp_mss(tp, to.to_mss);
 @@ -1587,7 +1587,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th,
   		 */
   		if ((to.to_flags & TOF_TS) != 0 &&
   		    SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tstmp_getticks();
   			tp->ts_recent = to.to_tsval;
   		}
 
 @@ -1625,11 +1625,13 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th,
   				 */
   				if ((to.to_flags & TOF_TS) != 0 &&
   				    to.to_tsecr) {
 -					if (!tp->t_rttlow ||
 -					    tp->t_rttlow > ticks - to.to_tsecr)
 -						tp->t_rttlow = ticks - to.to_tsecr;
 +					u_int t;
 +
 +					t = tstmp_getticks() - to.to_tsecr;
 +					if (!tp->t_rttlow || tp->t_rttlow > t)
 +						tp->t_rttlow = t;
   					tcp_xmit_timer(tp,
 -					    ticks - to.to_tsecr + 1);
 +					    TSTMP_TO_TICKS(t) + 1);
   				} else if (tp->t_rtttime &&
   				    SEQ_GT(th->th_ack, tp->t_rtseq)) {
   					if (!tp->t_rttlow ||
 @@ -2097,7 +2099,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th,
   	    TSTMP_LT(to.to_tsval, tp->ts_recent)) {
 
   		/* Check to see if ts_recent is over 24 days old.  */
 -		if (ticks - tp->ts_recent_age > TCP_PAWS_IDLE) {
 +		if (tstmp_getticks() - tp->ts_recent_age > TCP_PAWS_IDLE) {
   			/*
   			 * Invalidate ts_recent.  If this segment updates
   			 * ts_recent, the age will be reset later and ts_recent
 @@ -2256,7 +2258,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th,
   	    SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
   	    SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
   		((thflags & (TH_SYN|TH_FIN)) != 0))) {
 -		tp->ts_recent_age = ticks;
 +		tp->ts_recent_age = tstmp_getticks();
   		tp->ts_recent = to.to_tsval;
   	}
 
 @@ -2570,11 +2572,13 @@ process_ACK:
   		 * timestamps of 0 or we could calculate a
   		 * huge RTT and blow up the retransmit timer.
   		 */
 -		if ((to.to_flags & TOF_TS) != 0 &&
 -		    to.to_tsecr) {
 -			if (!tp->t_rttlow || tp->t_rttlow > ticks - to.to_tsecr)
 -				tp->t_rttlow = ticks - to.to_tsecr;
 -			tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
 +		if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) {
 +			u_int t;
 +
 +			t = tstmp_getticks() - to.to_tsecr;
 +			if (!tp->t_rttlow || tp->t_rttlow > t)
 +				tp->t_rttlow = t;
 +			tcp_xmit_timer(tp, TSTMP_TO_TICKS(t) + 1);
   		} else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
   			if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime)
   				tp->t_rttlow = ticks - tp->t_rtttime;
 Index: sys/netinet/tcp_output.c
 ===================================================================
 --- sys/netinet/tcp_output.c	(revision 223592)
 +++ sys/netinet/tcp_output.c	(working copy)
 @@ -689,13 +689,13 @@ send:
   		/* Timestamps. */
   		if ((tp->t_flags & TF_RCVD_TSTMP) ||
   		    ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) {
 -			to.to_tsval = ticks + tp->ts_offset;
 +			to.to_tsval = tstmp_getticks() + tp->ts_offset;
   			to.to_tsecr = tp->ts_recent;
   			to.to_flags |= TOF_TS;
   			/* Set receive buffer autosizing timestamp. */
   			if (tp->rfbuf_ts == 0 &&
   			    (so->so_rcv.sb_flags & SB_AUTOSIZE))
 -				tp->rfbuf_ts = ticks;
 +				tp->rfbuf_ts = tstmp_getticks();
   		}
   		/* Selective ACK's. */
   		if (tp->t_flags & TF_SACK_PERMIT) {
 Index: sys/netinet/tcp_syncache.c
 ===================================================================
 --- sys/netinet/tcp_syncache.c	(revision 223592)
 +++ sys/netinet/tcp_syncache.c	(working copy)
 @@ -818,7 +818,7 @@ syncache_socket(struct syncache *sc, struct socket
   		if (sc->sc_flags & SCF_TIMESTAMP) {
   			tp->t_flags |= TF_REQ_TSTMP|TF_RCVD_TSTMP;
   			tp->ts_recent = sc->sc_tsreflect;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tstmp_getticks();
   			tp->ts_offset = sc->sc_tsoff;
   		}
   #ifdef TCP_SIGNATURE
 @@ -1217,7 +1217,7 @@ _syncache_add(struct in_conninfo *inc, struct tcpo
   		 */
   		if (to->to_flags & TOF_TS) {
   			sc->sc_tsreflect = to->to_tsval;
 -			sc->sc_ts = ticks;
 +			sc->sc_ts = tstmp_getticks();
   			sc->sc_flags |= SCF_TIMESTAMP;
   		}
   		if (to->to_flags & TOF_SCALE) {
 @@ -1658,7 +1658,7 @@ syncookie_generate(struct syncache_head *sch, stru
   		data |= md5_buffer[2] << 10;		/* more digest bits */
   		data ^= md5_buffer[3];
   		sc->sc_ts = data;
 -		sc->sc_tsoff = data - ticks;		/* after XOR */
 +		sc->sc_tsoff = data - tstmp_getticks();		/* after XOR */
   	}
 
   	TCPSTAT_INC(tcps_sc_sendcookie);
 @@ -1743,7 +1743,7 @@ syncookie_lookup(struct in_conninfo *inc, struct s
   		sc->sc_flags |= SCF_TIMESTAMP;
   		sc->sc_tsreflect = to->to_tsval;
   		sc->sc_ts = to->to_tsecr;
 -		sc->sc_tsoff = to->to_tsecr - ticks;
 +		sc->sc_tsoff = to->to_tsecr - tstmp_getticks();
   		sc->sc_flags |= (data & 0x1) ? SCF_SIGNATURE : 0;
   		sc->sc_flags |= ((data >> 1) & 0x1) ? SCF_SACK : 0;
   		sc->sc_requested_s_scale = min((data >> 2) & 0xf,
 Index: sys/netinet/tcp_seq.h
 ===================================================================
 --- sys/netinet/tcp_seq.h	(revision 223592)
 +++ sys/netinet/tcp_seq.h	(working copy)
 @@ -62,7 +62,33 @@
   	(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
   	    (tp)->snd_recover = (tp)->iss
 
 -#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * hz)
 -					/* timestamp wrap-around time */
 +#ifdef _KERNEL
 +/*
 + * Clock macros for RFC 1323 timestamps.
 + */
 +/* TSTMP_UNIT in ms, should be 1ms < x < 1000ms according to RFC 1323. */
 +#define	TSTMP_UNIT		max(1, (hz / 1000))
 +#define	TSTMP_TO_TICKS(_t)	((_t) * hz * TSTMP_UNIT / 1000)
 
 +static __inline u_int
 +tstmp_getticks(void)
 +{
 +	struct timeval tv;
 +	u_long ms;
 +
 +	/*
 +	 * getmicrouptime() should be good enough for TSTMP_UNIT.
 +	 * Do not use getmicrotime() here as it might break nfsroot/tcp.
 +	 */
 +	getmicrouptime(&tv);
 +	ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 +	ms /= TSTMP_UNIT;
 +
 +	return (ms);
 +}
 +
 +/* Timestamp wrap-around time, 24 days for TSTMP_UNIT = 1ms. */
 +#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * 1000 / TSTMP_UNIT)
 +#endif /* _KERNEL */
 +
   #endif /* _NETINET_TCP_SEQ_H_ */
 Index: sys/netinet/tcp_timewait.c
 ===================================================================
 --- sys/netinet/tcp_timewait.c	(revision 223592)
 +++ sys/netinet/tcp_timewait.c	(working copy)
 @@ -558,7 +558,7 @@ tcp_twrespond(struct tcptw *tw, int flags)
   	 */
   	if (tw->t_recent && flags == TH_ACK) {
   		to.to_flags |= TOF_TS;
 -		to.to_tsval = ticks + tw->ts_offset;
 +		to.to_tsval = tstmp_getticks() + tw->ts_offset;
   		to.to_tsecr = tw->t_recent;
   	}
   	optlen = tcp_addoptions(&to, (u_char *)(th + 1));
Responsible-Changed-From-To: silby->bz 
Responsible-Changed-By: bz 
Responsible-Changed-When: Wed Feb 15 15:23:54 UTC 2012 
Responsible-Changed-Why:  
OMG, I got near TCP timers ... again. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=61404 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/61404: commit references a PR
Date: Wed, 15 Feb 2012 16:10:21 +0000 (UTC)

 Author: bz
 Date: Wed Feb 15 16:09:56 2012
 New Revision: 231767
 URL: http://svn.freebsd.org/changeset/base/231767
 
 Log:
   Fix PAWS (Protect Against Wrapped Sequence numbers) in cases when
   hz >> 1000 and thus getting outside the timestamp clock frequenceny of
   1ms < x < 1s per tick as mandated by RFC1323, leading to connection
   resets on idle connections.
   
   Always use a granularity of 1ms using getmicrouptime() making all but
   relevant callouts independent of hz.
   
   Use getmicrouptime(), not getmicrotime() as the latter may make a jump
   possibly breaking TCP nfsroot mounts having our timestamps move forward
   for more than 24.8 days in a second without having been idle for that
   long.
   
   PR:		kern/61404
   Reviewed by:	jhb, mav, rrs
   Discussed with:	silby, lstewart
   Sponsored by:	Sandvine Incorporated (originally in 2011)
   MFC after:	6 weeks
 
 Modified:
   head/sys/netinet/tcp_input.c
   head/sys/netinet/tcp_output.c
   head/sys/netinet/tcp_seq.h
   head/sys/netinet/tcp_syncache.c
   head/sys/netinet/tcp_timewait.c
 
 Modified: head/sys/netinet/tcp_input.c
 ==============================================================================
 --- head/sys/netinet/tcp_input.c	Wed Feb 15 15:54:57 2012	(r231766)
 +++ head/sys/netinet/tcp_input.c	Wed Feb 15 16:09:56 2012	(r231767)
 @@ -1493,7 +1493,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	 */
  	if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) {
  		to.to_tsecr -= tp->ts_offset;
 -		if (TSTMP_GT(to.to_tsecr, ticks))
 +		if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks()))
  			to.to_tsecr = 0;
  	}
  
 @@ -1518,7 +1518,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		if (to.to_flags & TOF_TS) {
  			tp->t_flags |= TF_RCVD_TSTMP;
  			tp->ts_recent = to.to_tsval;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  		}
  		if (to.to_flags & TOF_MSS)
  			tcp_mss(tp, to.to_mss);
 @@ -1562,7 +1562,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		 */
  		if ((to.to_flags & TOF_TS) != 0 &&
  		    SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_recent = to.to_tsval;
  		}
  
 @@ -1600,11 +1600,13 @@ tcp_do_segment(struct mbuf *m, struct tc
  				 */
  				if ((to.to_flags & TOF_TS) != 0 &&
  				    to.to_tsecr) {
 -					if (!tp->t_rttlow ||
 -					    tp->t_rttlow > ticks - to.to_tsecr)
 -						tp->t_rttlow = ticks - to.to_tsecr;
 +					u_int t;
 +
 +					t = tcp_ts_getticks() - to.to_tsecr;
 +					if (!tp->t_rttlow || tp->t_rttlow > t)
 +						tp->t_rttlow = t;
  					tcp_xmit_timer(tp,
 -					    ticks - to.to_tsecr + 1);
 +					    TCP_TS_TO_TICKS(t) + 1);
  				} else if (tp->t_rtttime &&
  				    SEQ_GT(th->th_ack, tp->t_rtseq)) {
  					if (!tp->t_rttlow ||
 @@ -2070,7 +2072,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    TSTMP_LT(to.to_tsval, tp->ts_recent)) {
  
  		/* Check to see if ts_recent is over 24 days old.  */
 -		if (ticks - tp->ts_recent_age > TCP_PAWS_IDLE) {
 +		if (tcp_ts_getticks() - tp->ts_recent_age > TCP_PAWS_IDLE) {
  			/*
  			 * Invalidate ts_recent.  If this segment updates
  			 * ts_recent, the age will be reset later and ts_recent
 @@ -2229,7 +2231,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
  	    SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
  		((thflags & (TH_SYN|TH_FIN)) != 0))) {
 -		tp->ts_recent_age = ticks;
 +		tp->ts_recent_age = tcp_ts_getticks();
  		tp->ts_recent = to.to_tsval;
  	}
  
 @@ -2543,11 +2545,13 @@ process_ACK:
  		 * timestamps of 0 or we could calculate a
  		 * huge RTT and blow up the retransmit timer.
  		 */
 -		if ((to.to_flags & TOF_TS) != 0 &&
 -		    to.to_tsecr) {
 -			if (!tp->t_rttlow || tp->t_rttlow > ticks - to.to_tsecr)
 -				tp->t_rttlow = ticks - to.to_tsecr;
 -			tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
 +		if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) {
 +			u_int t;
 +
 +			t = tcp_ts_getticks() - to.to_tsecr;
 +			if (!tp->t_rttlow || tp->t_rttlow > t)
 +				tp->t_rttlow = t;
 +			tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1);
  		} else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
  			if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime)
  				tp->t_rttlow = ticks - tp->t_rtttime;
 
 Modified: head/sys/netinet/tcp_output.c
 ==============================================================================
 --- head/sys/netinet/tcp_output.c	Wed Feb 15 15:54:57 2012	(r231766)
 +++ head/sys/netinet/tcp_output.c	Wed Feb 15 16:09:56 2012	(r231767)
 @@ -680,13 +680,13 @@ send:
  		/* Timestamps. */
  		if ((tp->t_flags & TF_RCVD_TSTMP) ||
  		    ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) {
 -			to.to_tsval = ticks + tp->ts_offset;
 +			to.to_tsval = tcp_ts_getticks() + tp->ts_offset;
  			to.to_tsecr = tp->ts_recent;
  			to.to_flags |= TOF_TS;
  			/* Set receive buffer autosizing timestamp. */
  			if (tp->rfbuf_ts == 0 &&
  			    (so->so_rcv.sb_flags & SB_AUTOSIZE))
 -				tp->rfbuf_ts = ticks;
 +				tp->rfbuf_ts = tcp_ts_getticks();
  		}
  		/* Selective ACK's. */
  		if (tp->t_flags & TF_SACK_PERMIT) {
 
 Modified: head/sys/netinet/tcp_seq.h
 ==============================================================================
 --- head/sys/netinet/tcp_seq.h	Wed Feb 15 15:54:57 2012	(r231766)
 +++ head/sys/netinet/tcp_seq.h	Wed Feb 15 16:09:56 2012	(r231767)
 @@ -62,7 +62,34 @@
  	(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
  	    (tp)->snd_recover = (tp)->iss
  
 -#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * hz)
 -					/* timestamp wrap-around time */
 +#ifdef _KERNEL
 +/*
 + * Clock macros for RFC 1323 timestamps.
 + */
 +#define	TCP_TS_TO_TICKS(_t)	((_t) * hz / 1000)
 +
 +/* Timestamp wrap-around time, 24 days. */
 +#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * 1000)
 +
 +/*
 + * tcp_ts_getticks() in ms, should be 1ms < x < 1000ms according to RFC 1323.
 + * We always use 1ms granularity independent of hz.
 + */
 +static __inline u_int
 +tcp_ts_getticks(void)
 +{
 +	struct timeval tv;
 +	u_long ms;
 +
 +	/*
 +	 * getmicrouptime() should be good enough for any 1-1000ms granularity.
 +	 * Do not use getmicrotime() here as it might break nfsroot/tcp.
 +	 */
 +	getmicrouptime(&tv);
 +	ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 +
 +	return (ms);
 +}
 +#endif /* _KERNEL */
  
  #endif /* _NETINET_TCP_SEQ_H_ */
 
 Modified: head/sys/netinet/tcp_syncache.c
 ==============================================================================
 --- head/sys/netinet/tcp_syncache.c	Wed Feb 15 15:54:57 2012	(r231766)
 +++ head/sys/netinet/tcp_syncache.c	Wed Feb 15 16:09:56 2012	(r231767)
 @@ -819,7 +819,7 @@ syncache_socket(struct syncache *sc, str
  		if (sc->sc_flags & SCF_TIMESTAMP) {
  			tp->t_flags |= TF_REQ_TSTMP|TF_RCVD_TSTMP;
  			tp->ts_recent = sc->sc_tsreflect;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_offset = sc->sc_tsoff;
  		}
  #ifdef TCP_SIGNATURE
 @@ -1226,7 +1226,7 @@ _syncache_add(struct in_conninfo *inc, s
  		 */
  		if (to->to_flags & TOF_TS) {
  			sc->sc_tsreflect = to->to_tsval;
 -			sc->sc_ts = ticks;
 +			sc->sc_ts = tcp_ts_getticks();
  			sc->sc_flags |= SCF_TIMESTAMP;
  		}
  		if (to->to_flags & TOF_SCALE) {
 @@ -1667,7 +1667,7 @@ syncookie_generate(struct syncache_head 
  		data |= md5_buffer[2] << 10;		/* more digest bits */
  		data ^= md5_buffer[3];
  		sc->sc_ts = data;
 -		sc->sc_tsoff = data - ticks;		/* after XOR */
 +		sc->sc_tsoff = data - tcp_ts_getticks();	/* after XOR */
  	}
  
  	TCPSTAT_INC(tcps_sc_sendcookie);
 @@ -1752,7 +1752,7 @@ syncookie_lookup(struct in_conninfo *inc
  		sc->sc_flags |= SCF_TIMESTAMP;
  		sc->sc_tsreflect = to->to_tsval;
  		sc->sc_ts = to->to_tsecr;
 -		sc->sc_tsoff = to->to_tsecr - ticks;
 +		sc->sc_tsoff = to->to_tsecr - tcp_ts_getticks();
  		sc->sc_flags |= (data & 0x1) ? SCF_SIGNATURE : 0;
  		sc->sc_flags |= ((data >> 1) & 0x1) ? SCF_SACK : 0;
  		sc->sc_requested_s_scale = min((data >> 2) & 0xf,
 
 Modified: head/sys/netinet/tcp_timewait.c
 ==============================================================================
 --- head/sys/netinet/tcp_timewait.c	Wed Feb 15 15:54:57 2012	(r231766)
 +++ head/sys/netinet/tcp_timewait.c	Wed Feb 15 16:09:56 2012	(r231767)
 @@ -558,7 +558,7 @@ tcp_twrespond(struct tcptw *tw, int flag
  	 */
  	if (tw->t_recent && flags == TH_ACK) {
  		to.to_flags |= TOF_TS;
 -		to.to_tsval = ticks + tw->ts_offset;
 +		to.to_tsval = tcp_ts_getticks() + tw->ts_offset;
  		to.to_tsecr = tw->t_recent;
  	}
  	optlen = tcp_addoptions(&to, (u_char *)(th + 1));
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: bz 
State-Changed-When: Wed Feb 15 16:58:40 UTC 2012 
State-Changed-Why:  
A change was finally committed to HEAD and will be merged 
in a couple of weeks. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=61404 
State-Changed-From-To: patched->closed 
State-Changed-By: bz 
State-Changed-When: Sat May 19 18:38:21 UTC 2012 
State-Changed-Why:  
Changes were merged to stable/[987].  Thanks a lot for reporting 
(and sorry it took us a while to fix). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=61404 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/61404: commit references a PR
Date: Sat, 19 May 2012 18:32:41 +0000 (UTC)

 Author: bz
 Date: Sat May 19 18:32:31 2012
 New Revision: 235657
 URL: http://svn.freebsd.org/changeset/base/235657
 
 Log:
   MFC r231767:
   
    Fix PAWS (Protect Against Wrapped Sequence numbers) in cases when
    hz >> 1000 and thus getting outside the timestamp clock frequenceny of
    1ms < x < 1s per tick as mandated by RFC1323, leading to connection
    resets on idle connections.
   
    Always use a granularity of 1ms using getmicrouptime() making all but
    relevant callouts independent of hz.
   
    Use getmicrouptime(), not getmicrotime() as the latter may make a jump
    possibly breaking TCP nfsroot mounts having our timestamps move forward
    for more than 24.8 days in a second without having been idle for that
    long.
   
   PR:		kern/61404
 
 Modified:
   stable/9/sys/netinet/tcp_input.c
   stable/9/sys/netinet/tcp_output.c
   stable/9/sys/netinet/tcp_seq.h
   stable/9/sys/netinet/tcp_syncache.c
   stable/9/sys/netinet/tcp_timewait.c
 Directory Properties:
   stable/9/sys/   (props changed)
 
 Modified: stable/9/sys/netinet/tcp_input.c
 ==============================================================================
 --- stable/9/sys/netinet/tcp_input.c	Sat May 19 18:16:49 2012	(r235656)
 +++ stable/9/sys/netinet/tcp_input.c	Sat May 19 18:32:31 2012	(r235657)
 @@ -1524,7 +1524,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	 */
  	if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) {
  		to.to_tsecr -= tp->ts_offset;
 -		if (TSTMP_GT(to.to_tsecr, ticks))
 +		if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks()))
  			to.to_tsecr = 0;
  	}
  
 @@ -1549,7 +1549,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		if (to.to_flags & TOF_TS) {
  			tp->t_flags |= TF_RCVD_TSTMP;
  			tp->ts_recent = to.to_tsval;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  		}
  		if (to.to_flags & TOF_MSS)
  			tcp_mss(tp, to.to_mss);
 @@ -1593,7 +1593,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		 */
  		if ((to.to_flags & TOF_TS) != 0 &&
  		    SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_recent = to.to_tsval;
  		}
  
 @@ -1631,11 +1631,13 @@ tcp_do_segment(struct mbuf *m, struct tc
  				 */
  				if ((to.to_flags & TOF_TS) != 0 &&
  				    to.to_tsecr) {
 -					if (!tp->t_rttlow ||
 -					    tp->t_rttlow > ticks - to.to_tsecr)
 -						tp->t_rttlow = ticks - to.to_tsecr;
 +					u_int t;
 +
 +					t = tcp_ts_getticks() - to.to_tsecr;
 +					if (!tp->t_rttlow || tp->t_rttlow > t)
 +						tp->t_rttlow = t;
  					tcp_xmit_timer(tp,
 -					    ticks - to.to_tsecr + 1);
 +					    TCP_TS_TO_TICKS(t) + 1);
  				} else if (tp->t_rtttime &&
  				    SEQ_GT(th->th_ack, tp->t_rtseq)) {
  					if (!tp->t_rttlow ||
 @@ -2101,7 +2103,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    TSTMP_LT(to.to_tsval, tp->ts_recent)) {
  
  		/* Check to see if ts_recent is over 24 days old.  */
 -		if (ticks - tp->ts_recent_age > TCP_PAWS_IDLE) {
 +		if (tcp_ts_getticks() - tp->ts_recent_age > TCP_PAWS_IDLE) {
  			/*
  			 * Invalidate ts_recent.  If this segment updates
  			 * ts_recent, the age will be reset later and ts_recent
 @@ -2260,7 +2262,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
  	    SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
  		((thflags & (TH_SYN|TH_FIN)) != 0))) {
 -		tp->ts_recent_age = ticks;
 +		tp->ts_recent_age = tcp_ts_getticks();
  		tp->ts_recent = to.to_tsval;
  	}
  
 @@ -2574,11 +2576,13 @@ process_ACK:
  		 * timestamps of 0 or we could calculate a
  		 * huge RTT and blow up the retransmit timer.
  		 */
 -		if ((to.to_flags & TOF_TS) != 0 &&
 -		    to.to_tsecr) {
 -			if (!tp->t_rttlow || tp->t_rttlow > ticks - to.to_tsecr)
 -				tp->t_rttlow = ticks - to.to_tsecr;
 -			tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
 +		if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) {
 +			u_int t;
 +
 +			t = tcp_ts_getticks() - to.to_tsecr;
 +			if (!tp->t_rttlow || tp->t_rttlow > t)
 +				tp->t_rttlow = t;
 +			tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1);
  		} else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
  			if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime)
  				tp->t_rttlow = ticks - tp->t_rtttime;
 
 Modified: stable/9/sys/netinet/tcp_output.c
 ==============================================================================
 --- stable/9/sys/netinet/tcp_output.c	Sat May 19 18:16:49 2012	(r235656)
 +++ stable/9/sys/netinet/tcp_output.c	Sat May 19 18:32:31 2012	(r235657)
 @@ -685,13 +685,13 @@ send:
  		/* Timestamps. */
  		if ((tp->t_flags & TF_RCVD_TSTMP) ||
  		    ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) {
 -			to.to_tsval = ticks + tp->ts_offset;
 +			to.to_tsval = tcp_ts_getticks() + tp->ts_offset;
  			to.to_tsecr = tp->ts_recent;
  			to.to_flags |= TOF_TS;
  			/* Set receive buffer autosizing timestamp. */
  			if (tp->rfbuf_ts == 0 &&
  			    (so->so_rcv.sb_flags & SB_AUTOSIZE))
 -				tp->rfbuf_ts = ticks;
 +				tp->rfbuf_ts = tcp_ts_getticks();
  		}
  		/* Selective ACK's. */
  		if (tp->t_flags & TF_SACK_PERMIT) {
 
 Modified: stable/9/sys/netinet/tcp_seq.h
 ==============================================================================
 --- stable/9/sys/netinet/tcp_seq.h	Sat May 19 18:16:49 2012	(r235656)
 +++ stable/9/sys/netinet/tcp_seq.h	Sat May 19 18:32:31 2012	(r235657)
 @@ -62,7 +62,34 @@
  	(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
  	    (tp)->snd_recover = (tp)->iss
  
 -#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * hz)
 -					/* timestamp wrap-around time */
 +#ifdef _KERNEL
 +/*
 + * Clock macros for RFC 1323 timestamps.
 + */
 +#define	TCP_TS_TO_TICKS(_t)	((_t) * hz / 1000)
 +
 +/* Timestamp wrap-around time, 24 days. */
 +#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * 1000)
 +
 +/*
 + * tcp_ts_getticks() in ms, should be 1ms < x < 1000ms according to RFC 1323.
 + * We always use 1ms granularity independent of hz.
 + */
 +static __inline u_int
 +tcp_ts_getticks(void)
 +{
 +	struct timeval tv;
 +	u_long ms;
 +
 +	/*
 +	 * getmicrouptime() should be good enough for any 1-1000ms granularity.
 +	 * Do not use getmicrotime() here as it might break nfsroot/tcp.
 +	 */
 +	getmicrouptime(&tv);
 +	ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 +
 +	return (ms);
 +}
 +#endif /* _KERNEL */
  
  #endif /* _NETINET_TCP_SEQ_H_ */
 
 Modified: stable/9/sys/netinet/tcp_syncache.c
 ==============================================================================
 --- stable/9/sys/netinet/tcp_syncache.c	Sat May 19 18:16:49 2012	(r235656)
 +++ stable/9/sys/netinet/tcp_syncache.c	Sat May 19 18:32:31 2012	(r235657)
 @@ -818,7 +818,7 @@ syncache_socket(struct syncache *sc, str
  		if (sc->sc_flags & SCF_TIMESTAMP) {
  			tp->t_flags |= TF_REQ_TSTMP|TF_RCVD_TSTMP;
  			tp->ts_recent = sc->sc_tsreflect;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_offset = sc->sc_tsoff;
  		}
  #ifdef TCP_SIGNATURE
 @@ -1225,7 +1225,7 @@ _syncache_add(struct in_conninfo *inc, s
  		 */
  		if (to->to_flags & TOF_TS) {
  			sc->sc_tsreflect = to->to_tsval;
 -			sc->sc_ts = ticks;
 +			sc->sc_ts = tcp_ts_getticks();
  			sc->sc_flags |= SCF_TIMESTAMP;
  		}
  		if (to->to_flags & TOF_SCALE) {
 @@ -1666,7 +1666,7 @@ syncookie_generate(struct syncache_head 
  		data |= md5_buffer[2] << 10;		/* more digest bits */
  		data ^= md5_buffer[3];
  		sc->sc_ts = data;
 -		sc->sc_tsoff = data - ticks;		/* after XOR */
 +		sc->sc_tsoff = data - tcp_ts_getticks();	/* after XOR */
  	}
  
  	TCPSTAT_INC(tcps_sc_sendcookie);
 @@ -1751,7 +1751,7 @@ syncookie_lookup(struct in_conninfo *inc
  		sc->sc_flags |= SCF_TIMESTAMP;
  		sc->sc_tsreflect = to->to_tsval;
  		sc->sc_ts = to->to_tsecr;
 -		sc->sc_tsoff = to->to_tsecr - ticks;
 +		sc->sc_tsoff = to->to_tsecr - tcp_ts_getticks();
  		sc->sc_flags |= (data & 0x1) ? SCF_SIGNATURE : 0;
  		sc->sc_flags |= ((data >> 1) & 0x1) ? SCF_SACK : 0;
  		sc->sc_requested_s_scale = min((data >> 2) & 0xf,
 
 Modified: stable/9/sys/netinet/tcp_timewait.c
 ==============================================================================
 --- stable/9/sys/netinet/tcp_timewait.c	Sat May 19 18:16:49 2012	(r235656)
 +++ stable/9/sys/netinet/tcp_timewait.c	Sat May 19 18:32:31 2012	(r235657)
 @@ -558,7 +558,7 @@ tcp_twrespond(struct tcptw *tw, int flag
  	 */
  	if (tw->t_recent && flags == TH_ACK) {
  		to.to_flags |= TOF_TS;
 -		to.to_tsval = ticks + tw->ts_offset;
 +		to.to_tsval = tcp_ts_getticks() + tw->ts_offset;
  		to.to_tsecr = tw->t_recent;
  	}
  	optlen = tcp_addoptions(&to, (u_char *)(th + 1));
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/61404: commit references a PR
Date: Sat, 19 May 2012 18:33:28 +0000 (UTC)

 Author: bz
 Date: Sat May 19 18:33:08 2012
 New Revision: 235658
 URL: http://svn.freebsd.org/changeset/base/235658
 
 Log:
   MFC r231767:
   
    Fix PAWS (Protect Against Wrapped Sequence numbers) in cases when
    hz >> 1000 and thus getting outside the timestamp clock frequenceny of
    1ms < x < 1s per tick as mandated by RFC1323, leading to connection
    resets on idle connections.
   
    Always use a granularity of 1ms using getmicrouptime() making all but
    relevant callouts independent of hz.
   
    Use getmicrouptime(), not getmicrotime() as the latter may make a jump
    possibly breaking TCP nfsroot mounts having our timestamps move forward
    for more than 24.8 days in a second without having been idle for that
    long.
   
   PR:		kern/61404
 
 Modified:
   stable/8/sys/netinet/tcp_input.c
   stable/8/sys/netinet/tcp_output.c
   stable/8/sys/netinet/tcp_seq.h
   stable/8/sys/netinet/tcp_syncache.c
   stable/8/sys/netinet/tcp_timewait.c
 Directory Properties:
   stable/8/sys/   (props changed)
 
 Modified: stable/8/sys/netinet/tcp_input.c
 ==============================================================================
 --- stable/8/sys/netinet/tcp_input.c	Sat May 19 18:32:31 2012	(r235657)
 +++ stable/8/sys/netinet/tcp_input.c	Sat May 19 18:33:08 2012	(r235658)
 @@ -1463,7 +1463,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	 */
  	if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) {
  		to.to_tsecr -= tp->ts_offset;
 -		if (TSTMP_GT(to.to_tsecr, ticks))
 +		if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks()))
  			to.to_tsecr = 0;
  	}
  
 @@ -1488,7 +1488,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		if (to.to_flags & TOF_TS) {
  			tp->t_flags |= TF_RCVD_TSTMP;
  			tp->ts_recent = to.to_tsval;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  		}
  		if (to.to_flags & TOF_MSS)
  			tcp_mss(tp, to.to_mss);
 @@ -1532,7 +1532,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		 */
  		if ((to.to_flags & TOF_TS) != 0 &&
  		    SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_recent = to.to_tsval;
  		}
  
 @@ -1575,11 +1575,13 @@ tcp_do_segment(struct mbuf *m, struct tc
  				 */
  				if ((to.to_flags & TOF_TS) != 0 &&
  				    to.to_tsecr) {
 -					if (!tp->t_rttlow ||
 -					    tp->t_rttlow > ticks - to.to_tsecr)
 -						tp->t_rttlow = ticks - to.to_tsecr;
 +					u_int t;
 +
 +					t = tcp_ts_getticks() - to.to_tsecr;
 +					if (!tp->t_rttlow || tp->t_rttlow > t)
 +						tp->t_rttlow = t;
  					tcp_xmit_timer(tp,
 -					    ticks - to.to_tsecr + 1);
 +					    TCP_TS_TO_TICKS(t) + 1);
  				} else if (tp->t_rtttime &&
  				    SEQ_GT(th->th_ack, tp->t_rtseq)) {
  					if (!tp->t_rttlow ||
 @@ -2050,7 +2052,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    TSTMP_LT(to.to_tsval, tp->ts_recent)) {
  
  		/* Check to see if ts_recent is over 24 days old.  */
 -		if (ticks - tp->ts_recent_age > TCP_PAWS_IDLE) {
 +		if (tcp_ts_getticks() - tp->ts_recent_age > TCP_PAWS_IDLE) {
  			/*
  			 * Invalidate ts_recent.  If this segment updates
  			 * ts_recent, the age will be reset later and ts_recent
 @@ -2209,7 +2211,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
  	    SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
  		((thflags & (TH_SYN|TH_FIN)) != 0))) {
 -		tp->ts_recent_age = ticks;
 +		tp->ts_recent_age = tcp_ts_getticks();
  		tp->ts_recent = to.to_tsval;
  	}
  
 @@ -2526,11 +2528,13 @@ process_ACK:
  		 * timestamps of 0 or we could calculate a
  		 * huge RTT and blow up the retransmit timer.
  		 */
 -		if ((to.to_flags & TOF_TS) != 0 &&
 -		    to.to_tsecr) {
 -			if (!tp->t_rttlow || tp->t_rttlow > ticks - to.to_tsecr)
 -				tp->t_rttlow = ticks - to.to_tsecr;
 -			tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
 +		if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) {
 +			u_int t;
 +
 +			t = tcp_ts_getticks() - to.to_tsecr;
 +			if (!tp->t_rttlow || tp->t_rttlow > t)
 +				tp->t_rttlow = t;
 +			tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1);
  		} else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
  			if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime)
  				tp->t_rttlow = ticks - tp->t_rtttime;
 
 Modified: stable/8/sys/netinet/tcp_output.c
 ==============================================================================
 --- stable/8/sys/netinet/tcp_output.c	Sat May 19 18:32:31 2012	(r235657)
 +++ stable/8/sys/netinet/tcp_output.c	Sat May 19 18:33:08 2012	(r235658)
 @@ -702,13 +702,13 @@ send:
  		/* Timestamps. */
  		if ((tp->t_flags & TF_RCVD_TSTMP) ||
  		    ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) {
 -			to.to_tsval = ticks + tp->ts_offset;
 +			to.to_tsval = tcp_ts_getticks() + tp->ts_offset;
  			to.to_tsecr = tp->ts_recent;
  			to.to_flags |= TOF_TS;
  			/* Set receive buffer autosizing timestamp. */
  			if (tp->rfbuf_ts == 0 &&
  			    (so->so_rcv.sb_flags & SB_AUTOSIZE))
 -				tp->rfbuf_ts = ticks;
 +				tp->rfbuf_ts = tcp_ts_getticks();
  		}
  		/* Selective ACK's. */
  		if (tp->t_flags & TF_SACK_PERMIT) {
 
 Modified: stable/8/sys/netinet/tcp_seq.h
 ==============================================================================
 --- stable/8/sys/netinet/tcp_seq.h	Sat May 19 18:32:31 2012	(r235657)
 +++ stable/8/sys/netinet/tcp_seq.h	Sat May 19 18:33:08 2012	(r235658)
 @@ -62,7 +62,34 @@
  	(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
  	    (tp)->snd_recover = (tp)->iss
  
 -#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * hz)
 -					/* timestamp wrap-around time */
 +#ifdef _KERNEL
 +/*
 + * Clock macros for RFC 1323 timestamps.
 + */
 +#define	TCP_TS_TO_TICKS(_t)	((_t) * hz / 1000)
 +
 +/* Timestamp wrap-around time, 24 days. */
 +#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * 1000)
 +
 +/*
 + * tcp_ts_getticks() in ms, should be 1ms < x < 1000ms according to RFC 1323.
 + * We always use 1ms granularity independent of hz.
 + */
 +static __inline u_int
 +tcp_ts_getticks(void)
 +{
 +	struct timeval tv;
 +	u_long ms;
 +
 +	/*
 +	 * getmicrouptime() should be good enough for any 1-1000ms granularity.
 +	 * Do not use getmicrotime() here as it might break nfsroot/tcp.
 +	 */
 +	getmicrouptime(&tv);
 +	ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 +
 +	return (ms);
 +}
 +#endif /* _KERNEL */
  
  #endif /* _NETINET_TCP_SEQ_H_ */
 
 Modified: stable/8/sys/netinet/tcp_syncache.c
 ==============================================================================
 --- stable/8/sys/netinet/tcp_syncache.c	Sat May 19 18:32:31 2012	(r235657)
 +++ stable/8/sys/netinet/tcp_syncache.c	Sat May 19 18:33:08 2012	(r235658)
 @@ -801,7 +801,7 @@ syncache_socket(struct syncache *sc, str
  		if (sc->sc_flags & SCF_TIMESTAMP) {
  			tp->t_flags |= TF_REQ_TSTMP|TF_RCVD_TSTMP;
  			tp->ts_recent = sc->sc_tsreflect;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_offset = sc->sc_tsoff;
  		}
  #ifdef TCP_SIGNATURE
 @@ -1196,7 +1196,7 @@ _syncache_add(struct in_conninfo *inc, s
  		 */
  		if (to->to_flags & TOF_TS) {
  			sc->sc_tsreflect = to->to_tsval;
 -			sc->sc_ts = ticks;
 +			sc->sc_ts = tcp_ts_getticks();
  			sc->sc_flags |= SCF_TIMESTAMP;
  		}
  		if (to->to_flags & TOF_SCALE) {
 @@ -1627,7 +1627,7 @@ syncookie_generate(struct syncache_head 
  		data |= md5_buffer[2] << 10;		/* more digest bits */
  		data ^= md5_buffer[3];
  		sc->sc_ts = data;
 -		sc->sc_tsoff = data - ticks;		/* after XOR */
 +		sc->sc_tsoff = data - tcp_ts_getticks();	/* after XOR */
  	}
  
  	TCPSTAT_INC(tcps_sc_sendcookie);
 @@ -1712,7 +1712,7 @@ syncookie_lookup(struct in_conninfo *inc
  		sc->sc_flags |= SCF_TIMESTAMP;
  		sc->sc_tsreflect = to->to_tsval;
  		sc->sc_ts = to->to_tsecr;
 -		sc->sc_tsoff = to->to_tsecr - ticks;
 +		sc->sc_tsoff = to->to_tsecr - tcp_ts_getticks();
  		sc->sc_flags |= (data & 0x1) ? SCF_SIGNATURE : 0;
  		sc->sc_flags |= ((data >> 1) & 0x1) ? SCF_SACK : 0;
  		sc->sc_requested_s_scale = min((data >> 2) & 0xf,
 
 Modified: stable/8/sys/netinet/tcp_timewait.c
 ==============================================================================
 --- stable/8/sys/netinet/tcp_timewait.c	Sat May 19 18:32:31 2012	(r235657)
 +++ stable/8/sys/netinet/tcp_timewait.c	Sat May 19 18:33:08 2012	(r235658)
 @@ -535,7 +535,7 @@ tcp_twrespond(struct tcptw *tw, int flag
  	 */
  	if (tw->t_recent && flags == TH_ACK) {
  		to.to_flags |= TOF_TS;
 -		to.to_tsval = ticks + tw->ts_offset;
 +		to.to_tsval = tcp_ts_getticks() + tw->ts_offset;
  		to.to_tsecr = tw->t_recent;
  	}
  	optlen = tcp_addoptions(&to, (u_char *)(th + 1));
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/61404: commit references a PR
Date: Sat, 19 May 2012 18:33:37 +0000 (UTC)

 Author: bz
 Date: Sat May 19 18:33:28 2012
 New Revision: 235659
 URL: http://svn.freebsd.org/changeset/base/235659
 
 Log:
   MFC r231767:
   
    Fix PAWS (Protect Against Wrapped Sequence numbers) in cases when
    hz >> 1000 and thus getting outside the timestamp clock frequenceny of
    1ms < x < 1s per tick as mandated by RFC1323, leading to connection
    resets on idle connections.
   
    Always use a granularity of 1ms using getmicrouptime() making all but
    relevant callouts independent of hz.
   
    Use getmicrouptime(), not getmicrotime() as the latter may make a jump
    possibly breaking TCP nfsroot mounts having our timestamps move forward
    for more than 24.8 days in a second without having been idle for that
    long.
   
   PR:		kern/61404
 
 Modified:
   stable/7/sys/netinet/tcp_input.c
   stable/7/sys/netinet/tcp_output.c
   stable/7/sys/netinet/tcp_seq.h
   stable/7/sys/netinet/tcp_syncache.c
   stable/7/sys/netinet/tcp_timewait.c
 Directory Properties:
   stable/7/sys/   (props changed)
 
 Modified: stable/7/sys/netinet/tcp_input.c
 ==============================================================================
 --- stable/7/sys/netinet/tcp_input.c	Sat May 19 18:33:08 2012	(r235658)
 +++ stable/7/sys/netinet/tcp_input.c	Sat May 19 18:33:28 2012	(r235659)
 @@ -933,7 +933,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	 */
  	if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) {
  		to.to_tsecr -= tp->ts_offset;
 -		if (TSTMP_GT(to.to_tsecr, ticks))
 +		if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks()))
  			to.to_tsecr = 0;
  	}
  
 @@ -958,7 +958,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		if (to.to_flags & TOF_TS) {
  			tp->t_flags |= TF_RCVD_TSTMP;
  			tp->ts_recent = to.to_tsval;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  		}
  		if (to.to_flags & TOF_MSS)
  			tcp_mss(tp, to.to_mss);
 @@ -1002,7 +1002,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  		 */
  		if ((to.to_flags & TOF_TS) != 0 &&
  		    SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_recent = to.to_tsval;
  		}
  
 @@ -1054,11 +1054,13 @@ tcp_do_segment(struct mbuf *m, struct tc
  				 */
  				if ((to.to_flags & TOF_TS) != 0 &&
  				    to.to_tsecr) {
 -					if (!tp->t_rttlow ||
 -					    tp->t_rttlow > ticks - to.to_tsecr)
 -						tp->t_rttlow = ticks - to.to_tsecr;
 +					u_int t;
 +
 +					t = tcp_ts_getticks() - to.to_tsecr;
 +					if (!tp->t_rttlow || tp->t_rttlow > t)
 +						tp->t_rttlow = t;
  					tcp_xmit_timer(tp,
 -					    ticks - to.to_tsecr + 1);
 +					    TCP_TS_TO_TICKS(t) + 1);
  				} else if (tp->t_rtttime &&
  				    SEQ_GT(th->th_ack, tp->t_rtseq)) {
  					if (!tp->t_rttlow ||
 @@ -1499,7 +1501,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    TSTMP_LT(to.to_tsval, tp->ts_recent)) {
  
  		/* Check to see if ts_recent is over 24 days old.  */
 -		if ((int)(ticks - tp->ts_recent_age) > TCP_PAWS_IDLE) {
 +		if (tcp_ts_getticks() - tp->ts_recent_age > TCP_PAWS_IDLE) {
  			/*
  			 * Invalidate ts_recent.  If this segment updates
  			 * ts_recent, the age will be reset later and ts_recent
 @@ -1652,7 +1654,7 @@ tcp_do_segment(struct mbuf *m, struct tc
  	    SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
  	    SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
  		((thflags & (TH_SYN|TH_FIN)) != 0))) {
 -		tp->ts_recent_age = ticks;
 +		tp->ts_recent_age = tcp_ts_getticks();
  		tp->ts_recent = to.to_tsval;
  	}
  
 @@ -1994,11 +1996,13 @@ process_ACK:
  		 * timestamps of 0 or we could calculate a
  		 * huge RTT and blow up the retransmit timer.
  		 */
 -		if ((to.to_flags & TOF_TS) != 0 &&
 -		    to.to_tsecr) {
 -			if (!tp->t_rttlow || tp->t_rttlow > ticks - to.to_tsecr)
 -				tp->t_rttlow = ticks - to.to_tsecr;
 -			tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
 +		if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) {
 +			u_int t;
 +
 +			t = tcp_ts_getticks() - to.to_tsecr;
 +			if (!tp->t_rttlow || tp->t_rttlow > t)
 +				tp->t_rttlow = t;
 +			tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1);
  		} else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
  			if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime)
  				tp->t_rttlow = ticks - tp->t_rtttime;
 
 Modified: stable/7/sys/netinet/tcp_output.c
 ==============================================================================
 --- stable/7/sys/netinet/tcp_output.c	Sat May 19 18:33:08 2012	(r235658)
 +++ stable/7/sys/netinet/tcp_output.c	Sat May 19 18:33:28 2012	(r235659)
 @@ -685,13 +685,13 @@ send:
  		/* Timestamps. */
  		if ((tp->t_flags & TF_RCVD_TSTMP) ||
  		    ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) {
 -			to.to_tsval = ticks + tp->ts_offset;
 +			to.to_tsval = tcp_ts_getticks() + tp->ts_offset;
  			to.to_tsecr = tp->ts_recent;
  			to.to_flags |= TOF_TS;
  			/* Set receive buffer autosizing timestamp. */
  			if (tp->rfbuf_ts == 0 &&
  			    (so->so_rcv.sb_flags & SB_AUTOSIZE))
 -				tp->rfbuf_ts = ticks;
 +				tp->rfbuf_ts = tcp_ts_getticks();
  		}
  		/* Selective ACK's. */
  		if (tp->t_flags & TF_SACK_PERMIT) {
 
 Modified: stable/7/sys/netinet/tcp_seq.h
 ==============================================================================
 --- stable/7/sys/netinet/tcp_seq.h	Sat May 19 18:33:08 2012	(r235658)
 +++ stable/7/sys/netinet/tcp_seq.h	Sat May 19 18:33:28 2012	(r235659)
 @@ -62,7 +62,34 @@
  	(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
  	    (tp)->snd_recover = (tp)->iss
  
 -#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * hz)
 -					/* timestamp wrap-around time */
 +#ifdef _KERNEL
 +/*
 + * Clock macros for RFC 1323 timestamps.
 + */
 +#define	TCP_TS_TO_TICKS(_t)	((_t) * hz / 1000)
 +
 +/* Timestamp wrap-around time, 24 days. */
 +#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * 1000)
 +
 +/*
 + * tcp_ts_getticks() in ms, should be 1ms < x < 1000ms according to RFC 1323.
 + * We always use 1ms granularity independent of hz.
 + */
 +static __inline u_int
 +tcp_ts_getticks(void)
 +{
 +	struct timeval tv;
 +	u_long ms;
 +
 +	/*
 +	 * getmicrouptime() should be good enough for any 1-1000ms granularity.
 +	 * Do not use getmicrotime() here as it might break nfsroot/tcp.
 +	 */
 +	getmicrouptime(&tv);
 +	ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 +
 +	return (ms);
 +}
 +#endif /* _KERNEL */
  
  #endif /* _NETINET_TCP_SEQ_H_ */
 
 Modified: stable/7/sys/netinet/tcp_syncache.c
 ==============================================================================
 --- stable/7/sys/netinet/tcp_syncache.c	Sat May 19 18:33:08 2012	(r235658)
 +++ stable/7/sys/netinet/tcp_syncache.c	Sat May 19 18:33:28 2012	(r235659)
 @@ -821,7 +821,7 @@ syncache_socket(struct syncache *sc, str
  		if (sc->sc_flags & SCF_TIMESTAMP) {
  			tp->t_flags |= TF_REQ_TSTMP|TF_RCVD_TSTMP;
  			tp->ts_recent = sc->sc_tsreflect;
 -			tp->ts_recent_age = ticks;
 +			tp->ts_recent_age = tcp_ts_getticks();
  			tp->ts_offset = sc->sc_tsoff;
  		}
  #ifdef TCP_SIGNATURE
 @@ -1224,7 +1224,7 @@ _syncache_add(struct in_conninfo *inc, s
  		 */
  		if (to->to_flags & TOF_TS) {
  			sc->sc_tsreflect = to->to_tsval;
 -			sc->sc_ts = ticks;
 +			sc->sc_ts = tcp_ts_getticks();
  			sc->sc_flags |= SCF_TIMESTAMP;
  		}
  		if (to->to_flags & TOF_SCALE) {
 @@ -1640,7 +1640,7 @@ syncookie_generate(struct syncache_head 
  		data |= md5_buffer[2] << 10;		/* more digest bits */
  		data ^= md5_buffer[3];
  		sc->sc_ts = data;
 -		sc->sc_tsoff = data - ticks;		/* after XOR */
 +		sc->sc_tsoff = data - tcp_ts_getticks();	/* after XOR */
  	}
  
  	tcpstat.tcps_sc_sendcookie++;
 @@ -1725,7 +1725,7 @@ syncookie_lookup(struct in_conninfo *inc
  		sc->sc_flags |= SCF_TIMESTAMP;
  		sc->sc_tsreflect = to->to_tsval;
  		sc->sc_ts = to->to_tsecr;
 -		sc->sc_tsoff = to->to_tsecr - ticks;
 +		sc->sc_tsoff = to->to_tsecr - tcp_ts_getticks();
  		sc->sc_flags |= (data & 0x1) ? SCF_SIGNATURE : 0;
  		sc->sc_flags |= ((data >> 1) & 0x1) ? SCF_SACK : 0;
  		sc->sc_requested_s_scale = min((data >> 2) & 0xf,
 
 Modified: stable/7/sys/netinet/tcp_timewait.c
 ==============================================================================
 --- stable/7/sys/netinet/tcp_timewait.c	Sat May 19 18:33:08 2012	(r235658)
 +++ stable/7/sys/netinet/tcp_timewait.c	Sat May 19 18:33:28 2012	(r235659)
 @@ -517,7 +517,7 @@ tcp_twrespond(struct tcptw *tw, int flag
  	 */
  	if (tw->t_recent && flags == TH_ACK) {
  		to.to_flags |= TOF_TS;
 -		to.to_tsval = ticks + tw->ts_offset;
 +		to.to_tsval = tcp_ts_getticks() + tw->ts_offset;
  		to.to_tsecr = tw->t_recent;
  	}
  	optlen = tcp_addoptions(&to, (u_char *)(th + 1));
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
 >>>>> On Wed, 14 Jan 2004, Richard Wendland <richard@starburst.demon.co.uk> wri
 tes:
 
 > > device polling(8) really does help _alot_ for packet floods/storms.
 > > for device polling to work properly (imho) you would need to set HZ 
 > > to 1000.
 > > I dont recommend any higher HZ on a PIII.
 > 
 > Incidentally, setting HZ > 1000 would cause FreeBSD TCP to not comply
 > with RFC1323, as it would make the TCP timestamp option clock tick faster
 > than 1ms.  RFC1323 4.2.2 specifies the clock rate to be in the range
 > 1 ms to 1 sec per tick.
 > 
 > Really the TCP timestamp option clock should be divorced from HZ before
 > too long, as a time will come when people will want HZ > 1000.
 > 
 > Actually a bit faster tick-rate is unlikely to run into much trouble in
 > practice, but it will cause the PAWS algorithm to stop a long running
 > TCP connection, see 4.2.3 of RFC1323.
 > 
 > 	Richard
 
 
 The PAWS thing is real.  Idle SSH or telnet connections can easily get
 hosed by wraparound if you crank up HZ too much.  We encountered this
 at Network Physics.
 
 I had been meaning to submit a PR about this (and probably several
 others as well) for quite a while now, but I always got distracted by
 some other urgent matter...  However, given the prod, I was able to
 dig up the fix we used for this particular problem.  Pretty sure these
 diffs will not apply cleanly, even to -stable, but no doubt the gist
 of the idea should be clear enough.  Hopefully, this can save someone
 some work on getting a fix into the tree.
 
 Tom Pavel
 
 Network Physics
 pavel@networkphysics.com / pavel@alum.mit.edu 

Is this still an issue? I see no indication of corresponding changes in the tree. 
