TCP Timestamps (option TSOPT) is a crucial, yet often misunderstood, mechanism that enables two key functionalities: Protection Against Wrapped Sequence numbers (PAWS) and Round-Trip Time (RTT) measurement.

Let’s see it in action. Imagine two hosts, 192.168.1.100 and 192.168.1.200, establishing a connection.

# On 192.168.1.100, initiating the connection
tcpdump -i eth0 'tcp port 12345 and host 192.168.1.200' -vvv

# On 192.168.1.200, accepting the connection
tcpdump -i eth0 'tcp port 12345 and host 192.168.1.100' -vvv

When the SYN packet flies from 192.168.1.100 to 192.168.1.200, you’ll see something like this in the tcpdump output:

[SYN] Seq=0 Win=29200 Len=0 MSS=1460 WS=256 TSval=12345678 TSecr=0

Notice TSval=12345678 and TSecr=0. TSval is the sender’s current timestamp. TSecr is 0 because it’s the initial SYN.

The SYN-ACK from 192.168.1.200 will look like this:

[SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 WS=256 TSval=98765432 TSecr=12345678

Here, TSval=98765432 is 192.168.1.200’s timestamp, and crucially, TSecr=12345678 echoes the timestamp from the original SYN. This is how the connection agrees to use the Timestamp option.

Now, consider a data packet from 192.168.1.100:

[ACK] Seq=1 Ack=1 Win=29200 Len=0 TSval=12345700 TSecr=98765432

The TSval has increased (reflecting passage of time), and TSecr=98765432 is the timestamp 192.168.1.200 sent in its last packet.

The Timestamp option, defined in RFC 1323, carries two 32-bit values: TSval (Timestamp value) and TSecr (Timestamp echo reply). TSval is generated by the sender and increments monotonically over time. TSecr is populated with the TSval received from the peer in the previous packet. This echo mechanism is key to both PAWS and RTT measurement.

The primary problem the Timestamp option solves is the "wrapped sequence number" issue. Before timestamps, TCP relied solely on sequence numbers and RTT estimates to detect duplicate or out-of-order packets. However, with high bandwidth and low latency links, sequence numbers could wrap around (from 2^32 - 1 back to 0) faster than a packet could traverse the network. This meant a delayed, old packet could arrive with a sequence number that looked valid for a new packet. PAWS, using the monotonically increasing timestamps, provides an additional, more reliable check. If an incoming packet’s timestamp is older than the last valid packet received from that sender, it’s discarded as a duplicate, even if its sequence number appears valid. This is particularly important for long-lived connections or those with very high throughput.

The RTT measurement is also significantly improved. Instead of just measuring the time between sending a segment and receiving its ACK, TCP can use the TSecr field. When host A sends a packet with TSval=X, and host B receives it and later sends an ACK with TSecr=X, host A can calculate the RTT by subtracting X from its current time. This is more precise because it directly correlates the sender’s timestamp with the receiver’s acknowledgement timestamp, minimizing clock skew issues that can affect simpler RTT calculations. This refined RTT measurement is then used by TCP’s congestion control algorithms (like Cubic or Reno) to adjust sending rates.

You can observe the presence and values of the Timestamp option using tcpdump with the -tt flag for absolute timestamps or -ttt for relative timestamps between packets, and by inspecting the packet data for the TSOPT field. On Linux systems, you can often see if the option is enabled globally or per-socket using sysctl net.ipv4.tcp_timestamps. Setting net.ipv4.tcp_timestamps = 1 enables it, while 0 disables it.

The timestamp value is not a wall-clock time; it’s an arbitrary counter that increments at a rate determined by the sender’s operating system, typically in units of milliseconds or microseconds. The crucial aspect is its monotonicity and the correlation between sender and receiver timestamps. The rate itself isn’t standardized; what matters is that it increases consistently on the sender side and is faithfully echoed back. This means that even if 192.168.1.100’s counter increments at 1000 units/sec and 192.168.1.200’s at 500 units/sec, the RTT calculation and PAWS mechanism still function correctly because the difference in timestamps directly relates to the elapsed time.

The RTT measurement is calculated as: RTT = Current_Time - TSecr. The sender’s TSval is the value it puts into the packet. The receiver gets this TSval, stores it as TSecr in its outgoing packets, and increments its own TSval. When the ACK with TSecr comes back to the original sender, the sender uses its current time and the received TSecr to calculate RTT. For example, if host A sends a packet with TSval=1000 at time T1, and host B receives it and sends an ACK with TSecr=1000 at time T2, host A can compute RTT = T2 - 1000 (where T2 is host A’s current clock time when it receives the ACK).

A common point of confusion is that the TSval in an incoming packet is not directly used for RTT calculation. Instead, it’s the TSecr in an outgoing packet that carries the echo of a past TSval. The value of TSval in the received packet is used to update the local TSecr for the next packet that local host sends. This interplay ensures that the RTT calculation is based on the time elapsed between the sender’s timestamp generation and the receiver’s acknowledgement of that specific timestamp.

When net.ipv4.tcp_timestamps is set to 2 on Linux, it enables timestamps but also enables SACK (Selective Acknowledgement) and window scaling. This is often the default and recommended setting as these options work together to improve TCP performance, especially on high-latency, high-bandwidth networks. PAWS is automatically enabled when tcp_timestamps is enabled.

If you disable TCP Timestamps globally (sysctl net.ipv4.tcp_timestamps = 0) and have clients that require it (e.g., many modern operating systems), you might start seeing connections fail to establish or exhibit erratic behavior, often manifesting as very slow transfers or dropped connections due to PAWS-related rejections of seemingly valid packets.

The next thing you’ll likely encounter after mastering TCP Timestamps is the complexities of Selective Acknowledgements (SACK), which work in tandem with timestamps to optimize data recovery.

Want structured learning?

Take the full Tcp course →