Date: Wed, 15 Feb 2012 16:09:56 +0000 (UTC) From: "Bjoern A. Zeeb" <bz@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r231767 - head/sys/netinet Message-ID: <201202151609.q1FG9uRm069583@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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));
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202151609.q1FG9uRm069583>