Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 19 May 2012 18:33:29 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r235659 - stable/7/sys/netinet
Message-ID:  <201205191833.q4JIXTiJ038527@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205191833.q4JIXTiJ038527>