svn commit: r235659 - stable/7/sys/netinet
Bjoern A. Zeeb
bz at FreeBSD.org
Sat May 19 18:33:29 UTC 2012
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));
More information about the svn-src-stable-7
mailing list