Skip to contentSkip to conversation

TCP keepalive question

PATCH Superseded Flavio Leitner 5 participants 16 messages Apr 16, 2010 – Apr 27, 2010

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

Hi,

I'm reading the RFC 1122 and it says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

The receiving acknowledgement part seems to be ok and handled by tcp_keepalive_timer() when it does
elapsed = tcp_time_stamp - tp->rcv_tstamp;

However, if one side just receive data and reply with ACK, the keepalive probes is sent anyway - 2.6.32.9-70.fc12.i686.PAE.

Any reason to not reset keepalive timer when data is received?

Socket options used:
SO_KEEPALIVE, TCP_KEEPIDLE=40, TCP_KEEPCNT=6, TCP_KEEPINTVL=5

Traffic dump attached.

thanks!

Signature · 1 line
Flavio
#1 lore raw

PATCH 1/1 TCP: avoid to send keepalive probes if it is receiving data

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Fix this by storing the timestamp of last received data packet and checking for it when the keepalive timer expires.

---
 include/linux/tcp.h  |    1 +
 net/ipv4/tcp_input.c |    3 +++
 net/ipv4/tcp_timer.c |    8 ++++++++
 3 files changed, 12 insertions(+), 0 deletions(-)
include/linux/tcp.h +1 -0
index a778ee0..405678f 100644
@@ -314,6 +314,7 @@ struct tcp_sock {
  	u32	snd_sml;	/* Last byte of the most recently transmitted small packet */
 	u32	rcv_tstamp;	/* timestamp of last received ACK (for keepalives) */
 	u32	lsndtime;	/* timestamp of last sent data packet (for restart window) */
+	u32	lrcvtime;	/* timestamp of last received data packet (for keepalives) */
 
 	/* Data for direct copy to user */
 	struct {
net/ipv4/tcp_input.c +3 -0
index f240f57..60d2980 100644
@@ -5391,6 +5391,8 @@ no_ack:
 				__kfree_skb(skb);
 			else
 				sk->sk_data_ready(sk, 0);
+
+			tp->lrcvtime = tcp_time_stamp;
 			return 0;
 		}
 	}
@@ -5421,6 +5423,7 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+	tp->lrcvtime = tcp_time_stamp;
 	return 0;
 
 csum_error:
net/ipv4/tcp_timer.c +8 -0
index 8a0ab29..74dd804 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - tp->lrcvtime;
+	
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {
Signature · 1 line
1.6.6.1
#2 lore raw

Re: [PATCH] TCP: avoid to send keepalive probes if it is receiving data

Quoted 11 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Fix this by storing the timestamp of last received data packet and checking for it when the keepalive timer expires.

Thanks Flavio !

Shouldnt you also change do_tcp_setsockopt() TCP_KEEPIDLE for consistency ?

net/ipv4/tcp.c +4 -1
index 0f8caf6..a4048d7 100644
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+						      tcp_time_stamp - tp->rcv_tstamp,
+						      tcp_time_stamp - tp->lrcvtime);
+
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
Quoted 58 lines
---
 include/linux/tcp.h  |    1 +
 net/ipv4/tcp_input.c |    3 +++
 net/ipv4/tcp_timer.c |    8 ++++++++
 3 files changed, 12 insertions(+), 0 deletions(-)
include/linux/tcp.h +1 -0
index a778ee0..405678f 100644
@@ -314,6 +314,7 @@ struct tcp_sock {
  	u32	snd_sml;	/* Last byte of the most recently transmitted small packet */
 	u32	rcv_tstamp;	/* timestamp of last received ACK (for keepalives) */
 	u32	lsndtime;	/* timestamp of last sent data packet (for restart window) */
+	u32	lrcvtime;	/* timestamp of last received data packet (for keepalives) */
 
 	/* Data for direct copy to user */
 	struct {
net/ipv4/tcp_input.c +3 -0
index f240f57..60d2980 100644
@@ -5391,6 +5391,8 @@ no_ack:
 				__kfree_skb(skb);
 			else
 				sk->sk_data_ready(sk, 0);
+
+			tp->lrcvtime = tcp_time_stamp;
 			return 0;
 		}
 	}
@@ -5421,6 +5423,7 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+	tp->lrcvtime = tcp_time_stamp;
 	return 0;
 
 csum_error:
net/ipv4/tcp_timer.c +8 -0
index 8a0ab29..74dd804 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - tp->lrcvtime;
+	
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {
#3 lore raw

PATCH v2 1/1 TCP: avoid to send keepalive probes if it is receiving data

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Fix this by storing the timestamp of last received data packet and checking for it when the keepalive timer expires.

-v2 fix do_tcp_setsockopt() as pointed by Eric Dumazet <[email protected]>

---
 include/linux/tcp.h  |    1 +
 net/ipv4/tcp.c       |    5 ++++-
 net/ipv4/tcp_input.c |    3 +++
 net/ipv4/tcp_timer.c |    8 ++++++++
 4 files changed, 16 insertions(+), 1 deletions(-)
include/linux/tcp.h +1 -0
index a778ee0..405678f 100644
@@ -314,6 +314,7 @@ struct tcp_sock {
  	u32	snd_sml;	/* Last byte of the most recently transmitted small packet */
 	u32	rcv_tstamp;	/* timestamp of last received ACK (for keepalives) */
 	u32	lsndtime;	/* timestamp of last sent data packet (for restart window) */
+	u32	lrcvtime;	/* timestamp of last received data packet (for keepalives) */
 
 	/* Data for direct copy to user */
 	struct {
net/ipv4/tcp.c +4 -1
index 0f8caf6..a4048d7 100644
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+						      tcp_time_stamp - tp->rcv_tstamp,
+						      tcp_time_stamp - tp->lrcvtime);
+
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_input.c +3 -0
index f240f57..60d2980 100644
@@ -5391,6 +5391,8 @@ no_ack:
 				__kfree_skb(skb);
 			else
 				sk->sk_data_ready(sk, 0);
+
+			tp->lrcvtime = tcp_time_stamp;
 			return 0;
 		}
 	}
@@ -5421,6 +5423,7 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+	tp->lrcvtime = tcp_time_stamp;
 	return 0;
 
 csum_error:
net/ipv4/tcp_timer.c +8 -0
index 8a0ab29..74dd804 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - tp->lrcvtime;
+	
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {
Signature · 1 line
1.5.5.6
#4 lore raw

Re: [PATCH v2] TCP: avoid to send keepalive probes if it is receiving data

Quoted 7 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Quoted 6 lines

Fix this by storing the timestamp of last received data packet and checking for it when the keepalive timer expires.

-v2 fix do_tcp_setsockopt() as pointed by Eric Dumazet <[email protected]>

I find this patch very welcome, and we could easily use this new lrcvtime information available in diagnostic tools (ss command)

But are you sure you update it for all valid packets ?

If we receive a pure ACK, it seems you do not ...

Quoted 75 lines
---
 include/linux/tcp.h  |    1 +
 net/ipv4/tcp.c       |    5 ++++-
 net/ipv4/tcp_input.c |    3 +++
 net/ipv4/tcp_timer.c |    8 ++++++++
 4 files changed, 16 insertions(+), 1 deletions(-)
include/linux/tcp.h +1 -0
index a778ee0..405678f 100644
@@ -314,6 +314,7 @@ struct tcp_sock {
  	u32	snd_sml;	/* Last byte of the most recently transmitted small packet */
 	u32	rcv_tstamp;	/* timestamp of last received ACK (for keepalives) */
 	u32	lsndtime;	/* timestamp of last sent data packet (for restart window) */
+	u32	lrcvtime;	/* timestamp of last received data packet (for keepalives) */
 
 	/* Data for direct copy to user */
 	struct {
net/ipv4/tcp.c +4 -1
index 0f8caf6..a4048d7 100644
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+						      tcp_time_stamp - tp->rcv_tstamp,
+						      tcp_time_stamp - tp->lrcvtime);
+
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_input.c +3 -0
index f240f57..60d2980 100644
@@ -5391,6 +5391,8 @@ no_ack:
 				__kfree_skb(skb);
 			else
 				sk->sk_data_ready(sk, 0);
+
+			tp->lrcvtime = tcp_time_stamp;
 			return 0;
 		}
 	}
@@ -5421,6 +5423,7 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+	tp->lrcvtime = tcp_time_stamp;
 	return 0;
 
 csum_error:
net/ipv4/tcp_timer.c +8 -0
index 8a0ab29..74dd804 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - tp->lrcvtime;
+	
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {
#5 lore raw

Re: [PATCH v2] TCP: avoid to send keepalive probes if it is receiving data

Quoted 16 lines · Eric Dumazet
Quoted 7 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Quoted 6 lines

Fix this by storing the timestamp of last received data packet and checking for it when the keepalive timer expires.

-v2 fix do_tcp_setsockopt() as pointed by Eric Dumazet <[email protected]>

Quoted 6 lines

I find this patch very welcome, and we could easily use this new lrcvtime information available in diagnostic tools (ss command)

But are you sure you update it for all valid packets ?

If we receive a pure ACK, it seems you do not ...

I fail to see why the addition of this new variable is necessary at all, could either of you enlight me why exactly it's necessary and rcv_tstamp will not suffice?

Quoted 75 lines
Quoted 75 lines
---
 include/linux/tcp.h  |    1 +
 net/ipv4/tcp.c       |    5 ++++-
 net/ipv4/tcp_input.c |    3 +++
 net/ipv4/tcp_timer.c |    8 ++++++++
 4 files changed, 16 insertions(+), 1 deletions(-)
include/linux/tcp.h +1 -0
index a778ee0..405678f 100644
@@ -314,6 +314,7 @@ struct tcp_sock {
  	u32	snd_sml;	/* Last byte of the most recently transmitted small packet */
 	u32	rcv_tstamp;	/* timestamp of last received ACK (for keepalives) */
 	u32	lsndtime;	/* timestamp of last sent data packet (for restart window) */
+	u32	lrcvtime;	/* timestamp of last received data packet (for keepalives) */
 
 	/* Data for direct copy to user */
 	struct {
net/ipv4/tcp.c +4 -1
index 0f8caf6..a4048d7 100644
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+						      tcp_time_stamp - tp->rcv_tstamp,
+						      tcp_time_stamp - tp->lrcvtime);
+
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_input.c +3 -0
index f240f57..60d2980 100644
@@ -5391,6 +5391,8 @@ no_ack:
 				__kfree_skb(skb);
 			else
 				sk->sk_data_ready(sk, 0);
+
+			tp->lrcvtime = tcp_time_stamp;
 			return 0;
 		}
 	}
@@ -5421,6 +5423,7 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+	tp->lrcvtime = tcp_time_stamp;
 	return 0;
 
 csum_error:
net/ipv4/tcp_timer.c +8 -0
index 8a0ab29..74dd804 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - tp->lrcvtime;
+	
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {
Signature · 1 line
 i.
maintainer
#6 lore raw

Re: [PATCH v2] TCP: avoid to send keepalive probes if it is receiving data

From: "Ilpo Järvinen" <[email protected]>
Date: Sun, 18 Apr 2010 23:34:15 +0300 (EEST)

Quoted 3 lines

I fail to see why the addition of this new variable is necessary at all, could either of you enlight me why exactly it's necessary and rcv_tstamp will not suffice?

I agree, the existing rcv_tstamp should serve this purpose just fine.

#7 lore raw

Re: [PATCH v2] TCP: avoid to send keepalive probes if it is receiving data

Quoted 9 lines · David Miller

From: "Ilpo Järvinen" <[email protected]>
Date: Sun, 18 Apr 2010 23:34:15 +0300 (EEST)

Quoted 3 lines

I fail to see why the addition of this new variable is necessary at all, could either of you enlight me why exactly it's necessary and rcv_tstamp will not suffice?

I agree, the existing rcv_tstamp should serve this purpose just fine.

I thought it would break TCP_INFO/tcp_get_info(). Actually, reviewing the code again I found another variable which does exactly what is needed.

I'll post a new patch for review.

thanks,

Signature · 1 line
Flavio
#8 lore raw

PATCH v3 1/1 TCP: avoid to send keepalive probes if receiving data

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

The acknowledgement packet is reseting the keepalive timer but the data packet isn't. This patch fixes it by checking the timestamp of the last received data packet too when the keepalive timer expires.

---
 net/ipv4/tcp.c       |    5 ++++-
 net/ipv4/tcp_timer.c |    8 ++++++++
 2 files changed, 12 insertions(+), 1 deletions(-)
net/ipv4/tcp.c +4 -1
index 0f8caf6..94f605c 100644
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+				      tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+				      tcp_time_stamp - tp->rcv_tstamp);
+
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_timer.c +8 -0
index 8a0ab29..9d1bb6f 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - icsk->icsk_ack.lrcvtime;
+
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {
Signature · 1 line
1.5.5.6
#9 lore raw

Re: [PATCH v3] TCP: avoid to send keepalive probes if receiving data

Quoted 23 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

The acknowledgement packet is reseting the keepalive timer but the data packet isn't. This patch fixes it by checking the timestamp of the last received data packet too when the keepalive timer expires.

---
 net/ipv4/tcp.c       |    5 ++++-
 net/ipv4/tcp_timer.c |    8 ++++++++
 2 files changed, 12 insertions(+), 1 deletions(-)
net/ipv4/tcp.c +0 -0
index 0f8caf6..94f605c 100644

net/ipv4/tcp.c static int do_tcp_setsockopt(struct sock *sk, int level, · line 2304

Quoted 8 lines
net/ipv4/tcp.c +4 -1
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+				      tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+				      tcp_time_stamp - tp->rcv_tstamp);
+

I'd put this into a helper in include/net/tcp.h

Quoted 10 lines
net/ipv4/tcp.c +0 -0
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_timer.c +0 -0
index 8a0ab29..9d1bb6f 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;

net/ipv4/tcp_timer.c static void tcp_keepalive_timer (unsigned long data) · line 565

Quoted 10 lines
net/ipv4/tcp_timer.c +8 -0
 
+	elapsed = tcp_time_stamp - icsk->icsk_ack.lrcvtime;
+
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;

...And then use it here too for setting the elapsed and doing the test and what follows only once?

Quoted 2 lines
net/ipv4/tcp_timer.c +0 -0
 	if (elapsed >= keepalive_time_when(tp)) {
 
Signature · 1 line
 i.
maintainer
#10 lore raw

Re: [PATCH v3] TCP: avoid to send keepalive probes if receiving data

From: "Ilpo Järvinen" <[email protected]>
Date: Mon, 26 Apr 2010 12:47:13 +0300 (EEST)

Quoted 10 lines

net/ipv4/tcp.c static int do_tcp_setsockopt(struct sock *sk, int level, · line 2304

Quoted 7 lines
net/ipv4/tcp.c +4 -1
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+				      tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+				      tcp_time_stamp - tp->rcv_tstamp);
+

I'd put this into a helper in include/net/tcp.h

...

Quoted 10 lines

net/ipv4/tcp_timer.c static void tcp_keepalive_timer (unsigned long data) · line 565

Quoted 6 lines
net/ipv4/tcp_timer.c +5 -0
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;

...And then use it here too for setting the elapsed and doing the test and what follows only once?

Agreed.

#11 lore raw

PATCH v4 1/1 TCP: avoid to send keepalive probes if receiving data

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

The acknowledgement packet is reseting the keepalive timer but the data packet isn't. This patch fixes it by checking the timestamp of the last received data packet too when the keepalive timer expires.

---
 include/net/tcp.h    |    8 ++++++++
 net/ipv4/tcp.c       |    2 +-
 net/ipv4/tcp_timer.c |    4 ++--
 3 files changed, 11 insertions(+), 3 deletions(-)
include/net/tcp.h +8 -0
index 75be5a2..305810e 100644
@@ -1032,6 +1032,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
 	return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
 }
 
+static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
+{
+	const struct inet_connection_sock *icsk = &tp->inet_conn;
+
+	return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+			  tcp_time_stamp - tp->rcv_tstamp);
+}
+
 static inline int tcp_fin_time(const struct sock *sk)
 {
 	int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
net/ipv4/tcp.c +1 -1
index 0f8caf6..48a6f33 100644
@@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = keepalive_time_elapsed(tp);
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_timer.c +2 -2
index 8a0ab29..a9155f9 100644
@@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
 	struct sock *sk = (struct sock *) data;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
-	__u32 elapsed;
+	u32 elapsed;
 
 	/* Only process if socket is not in use. */
 	bh_lock_sock(sk);
@@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
-	elapsed = tcp_time_stamp - tp->rcv_tstamp;
+	elapsed = keepalive_time_elapsed(tp);
 
 	if (elapsed >= keepalive_time_when(tp)) {
 		if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
Signature · 1 line
1.5.5.6
#12 lore raw

Re: [PATCH v4] TCP: avoid to send keepalive probes if receiving data

Quoted 7 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Quoted 7 lines

The acknowledgement packet is reseting the keepalive timer but the data packet isn't. This patch fixes it by checking the timestamp of the last received data packet too when the keepalive timer expires.

---

Quoted 59 lines
 include/net/tcp.h    |    8 ++++++++
 net/ipv4/tcp.c       |    2 +-
 net/ipv4/tcp_timer.c |    4 ++--
 3 files changed, 11 insertions(+), 3 deletions(-)
include/net/tcp.h +8 -0
index 75be5a2..305810e 100644
@@ -1032,6 +1032,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
 	return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
 }
 
+static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
+{
+	const struct inet_connection_sock *icsk = &tp->inet_conn;
+
+	return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+			  tcp_time_stamp - tp->rcv_tstamp);
+}
+
 static inline int tcp_fin_time(const struct sock *sk)
 {
 	int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
net/ipv4/tcp.c +1 -1
index 0f8caf6..48a6f33 100644
@@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = keepalive_time_elapsed(tp);
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_timer.c +2 -2
index 8a0ab29..a9155f9 100644
@@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
 	struct sock *sk = (struct sock *) data;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
-	__u32 elapsed;
+	u32 elapsed;
 
 	/* Only process if socket is not in use. */
 	bh_lock_sock(sk);
@@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
-	elapsed = tcp_time_stamp - tp->rcv_tstamp;
+	elapsed = keepalive_time_elapsed(tp);
 
 	if (elapsed >= keepalive_time_when(tp)) {
 		if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
Acked-by on v4 1/1
#13 lore raw

Re: [PATCH v4] TCP: avoid to send keepalive probes if receiving data

In reply to Flavio Leitner
Quoted 65 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

The acknowledgement packet is reseting the keepalive timer but the data packet isn't. This patch fixes it by checking the timestamp of the last received data packet too when the keepalive timer expires.

---
 include/net/tcp.h    |    8 ++++++++
 net/ipv4/tcp.c       |    2 +-
 net/ipv4/tcp_timer.c |    4 ++--
 3 files changed, 11 insertions(+), 3 deletions(-)
include/net/tcp.h +8 -0
index 75be5a2..305810e 100644
@@ -1032,6 +1032,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
 	return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
 }
 
+static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
+{
+	const struct inet_connection_sock *icsk = &tp->inet_conn;
+
+	return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+			  tcp_time_stamp - tp->rcv_tstamp);
+}
+
 static inline int tcp_fin_time(const struct sock *sk)
 {
 	int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
net/ipv4/tcp.c +1 -1
index 0f8caf6..48a6f33 100644
@@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = keepalive_time_elapsed(tp);
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_timer.c +1 -1
index 8a0ab29..a9155f9 100644
@@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
 	struct sock *sk = (struct sock *) data;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
-	__u32 elapsed;
+	u32 elapsed;
 
 	/* Only process if socket is not in use. */
 	bh_lock_sock(sk);

net/ipv4/tcp_timer.c static void tcp_keepalive_timer (unsigned long data) · line 560

Quoted 8 lines
net/ipv4/tcp_timer.c +1 -1
@@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
-	elapsed = tcp_time_stamp - tp->rcv_tstamp;
+	elapsed = keepalive_time_elapsed(tp);
 
 	if (elapsed >= keepalive_time_when(tp)) {
 		if (icsk->icsk_probes_out >= keepalive_probes(tp)) {

Thanks. Looks very nice now.

Signature · 1 line
 i.
maintainer Applied
#14 lore raw

Re: [PATCH v4] TCP: avoid to send keepalive probes if receiving data

From: "Ilpo Järvinen" <[email protected]>
Date: Tue, 27 Apr 2010 09:08:08 +0300 (EEST)

Quoted 15 lines · Flavio Leitner
Quoted 14 lines

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

The acknowledgement packet is reseting the keepalive timer but the data packet isn't. This patch fixes it by checking the timestamp of the last received data packet too when the keepalive timer expires.

...

Quoted 1 line

...

Quoted 1 line

Applied, thanks everyone.

#15 lore raw

Re: [PATCH v2] TCP: avoid to send keepalive probes if it is receiving data

In reply to Eric Dumazet
Quoted 16 lines · Eric Dumazet
Quoted 7 lines · Flavio Leitner

RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval.
...

Quoted 6 lines

Fix this by storing the timestamp of last received data packet and checking for it when the keepalive timer expires.

-v2 fix do_tcp_setsockopt() as pointed by Eric Dumazet <[email protected]>

Quoted 6 lines

I find this patch very welcome, and we could easily use this new lrcvtime information available in diagnostic tools (ss command)

But are you sure you update it for all valid packets ?

If we receive a pure ACK, it seems you do not ...

Pure ack is handled by rcv_tstamp in the struct which is considered in tcp_keepalive_time() too.

The idea of exporting those variables is nice, I'll see how 'ss' works.

thanks for reviewing the patch!

Quoted 81 lines
Quoted 65 lines
---
 include/linux/tcp.h  |    1 +
 net/ipv4/tcp.c       |    5 ++++-
 net/ipv4/tcp_input.c |    3 +++
 net/ipv4/tcp_timer.c |    8 ++++++++
 4 files changed, 16 insertions(+), 1 deletions(-)
include/linux/tcp.h +1 -0
index a778ee0..405678f 100644
@@ -314,6 +314,7 @@ struct tcp_sock {
  	u32	snd_sml;	/* Last byte of the most recently transmitted small packet */
 	u32	rcv_tstamp;	/* timestamp of last received ACK (for keepalives) */
 	u32	lsndtime;	/* timestamp of last sent data packet (for restart window) */
+	u32	lrcvtime;	/* timestamp of last received data packet (for keepalives) */
 
 	/* Data for direct copy to user */
 	struct {
net/ipv4/tcp.c +4 -1
index 0f8caf6..a4048d7 100644
@@ -2298,7 +2298,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->sk_state) &
 			      (TCPF_CLOSE | TCPF_LISTEN))) {
-				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				u32 elapsed = min_t(u32,
+						      tcp_time_stamp - tp->rcv_tstamp,
+						      tcp_time_stamp - tp->lrcvtime);
+
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
 				else
net/ipv4/tcp_input.c +3 -0
index f240f57..60d2980 100644
@@ -5391,6 +5391,8 @@ no_ack:
 				__kfree_skb(skb);
 			else
 				sk->sk_data_ready(sk, 0);
+
+			tp->lrcvtime = tcp_time_stamp;
 			return 0;
 		}
 	}
@@ -5421,6 +5423,7 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+	tp->lrcvtime = tcp_time_stamp;
 	return 0;
 
 csum_error:
net/ipv4/tcp_timer.c +1 -0
index 8a0ab29..74dd804 100644
@@ -554,6 +554,14 @@ static void tcp_keepalive_timer (unsigned long data)
 	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
+	elapsed = tcp_time_stamp - tp->lrcvtime;

net/ipv4/tcp_timer.c static void tcp_keepalive_timer (unsigned long data) · line 567

Quoted 10 lines
net/ipv4/tcp_timer.c +7 -0
+	
+	/* receiving data means alive */
+	if (elapsed < keepalive_time_when(tp)) {
+		elapsed = keepalive_time_when(tp) - elapsed;
+		goto resched;
+	}
+
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
 	if (elapsed >= keepalive_time_when(tp)) {

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
Flavio