From: Alex Bergmann <hidden> Date: 2012-08-21 23:59:57
Hi David,
I'm not 100% sure, but it looks like I found an RFC mismatch with the
current default values of the TCP implementation.
Alex
From 8b854a525eb45f64ad29dfab16f9d9f681e84495 Mon Sep 17 00:00:00 2001
From: Alexander Bergmann <redacted>
Date: Wed, 22 Aug 2012 00:29:08 +0200
Subject: [PATCH 1/1] tcp: Wrong timeout for SYN segments
Commit 9ad7c049 changed the initRTO from 3secs to 1sec in accordance to
RFC6298 (former RFC2988bis). This introduced a gap with RFC1122 that
defines a minimum retransmission window for SYN segments of at least
180secs.
Prior to 9ad7c049 the timeout was defined with 189secs. Now we have only
a timeout of 63secs.
((2 << 5) - 1) * 3 secs = 189 secs
((2 << 5) - 1) * 1 secs = 63 secs
To fulfill the MUST constraint in RFC1122 section 4.2.3.5 about R2 for
SYN segments, the values of TCP_SYN_RETRIES and TCP_SYNACK_RETRIES must
be changed to 7 reties.
((2 << 7) - 1) * 1 secs = 255 secs
This would result in an ETIMEDOUT of 4 minutes 15 seconds.
Signed-off-by: Alexander Bergmann <redacted>
---
include/net/tcp.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
@@ -98,10 +98,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);*15is~13-30mindependingonRTO.*/-#define TCP_SYN_RETRIES 5 /* number of times to retry active opening a+#define TCP_SYN_RETRIES 7 /* number of times to retry active opening a*connection:~180secisRFCminimum*/-#define TCP_SYNACK_RETRIES 5 /* number of times to retry passive opening a+#define TCP_SYNACK_RETRIES 7 /* number of times to retry passive opening a*connection:~180secisRFCminimum*/#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
From: Eric Dumazet <hidden> Date: 2012-08-22 08:06:54
On Wed, 2012-08-22 at 01:29 +0200, Alex Bergmann wrote:
Hi David,
I'm not 100% sure, but it looks like I found an RFC mismatch with the
current default values of the TCP implementation.
Alex
From 8b854a525eb45f64ad29dfab16f9d9f681e84495 Mon Sep 17 00:00:00 2001
From: Alexander Bergmann <redacted>
Date: Wed, 22 Aug 2012 00:29:08 +0200
Subject: [PATCH 1/1] tcp: Wrong timeout for SYN segments
Commit 9ad7c049 changed the initRTO from 3secs to 1sec in accordance to
RFC6298 (former RFC2988bis). This introduced a gap with RFC1122 that
defines a minimum retransmission window for SYN segments of at least
180secs.
Prior to 9ad7c049 the timeout was defined with 189secs. Now we have only
a timeout of 63secs.
((2 << 5) - 1) * 3 secs = 189 secs
((2 << 5) - 1) * 1 secs = 63 secs
Strange maths ... here I have :
(1+2+4+8+16) * 3 = 93 secs
vs
(1+2+4+8+16) * 1 = 31 secs
So even before said commit, we were not rfc1122 compliant.
Using 7 retries would give 127 seconds, still not rfc compliant.
quoted hunk
To fulfill the MUST constraint in RFC1122 section 4.2.3.5 about R2 for
SYN segments, the values of TCP_SYN_RETRIES and TCP_SYNACK_RETRIES must
be changed to 7 reties.
((2 << 7) - 1) * 1 secs = 255 secs
This would result in an ETIMEDOUT of 4 minutes 15 seconds.
Signed-off-by: Alexander Bergmann <redacted>
---
include/net/tcp.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
@@ -98,10 +98,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);*15is~13-30mindependingonRTO.*/-#define TCP_SYN_RETRIES 5 /* number of times to retry active opening a+#define TCP_SYN_RETRIES 7 /* number of times to retry active opening a*connection:~180secisRFCminimum*/-#define TCP_SYNACK_RETRIES 5 /* number of times to retry passive opening a+#define TCP_SYNACK_RETRIES 7 /* number of times to retry passive opening a*connection:~180secisRFCminimum*/#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
Nice catch !
I kind of disagree with the SYNACK part.
RFC 1122 says in 4.2.3.5 :
However, the values of R1 and R2 may be different for SYN
and data segments. In particular, R2 for a SYN segment MUST
be set large enough to provide retransmission of the segment
for at least 3 minutes. The application can close the
connection (i.e., give up on the open attempt) sooner, of
course.
I am not sure SYNACK segments were considered as a 'SYN segment' in this
section. (as the application cannot 'close' the connection on the passive
side, only kernel is aware of a SYN_RECV socket)
Increasing TCP_SYNACK_RETRIES from 5 to 7 or 8 amplifies the
SYN/synflood problem.
A valid client should retransmit its SYN packet for 180 seconds, I dont
believe we should make sure the SYNACK will be sent for 180 seconds as
well.
If we _really_ want to have a 3 minutes R2 for SYNACK, I suggest
changing things to that we dont send more than 5 SYNACKS, maybe using
RTO=6 after one retransmit
current situation :
1 sec
2 sec
4 sec
8 sec
16 sec
----
total of 31 seconds
1 sec
12 sec // switch to RTO = 6
24 sec
48 sec
96 sec
-----
total of 181 seconds
From: Alex Bergmann <hidden> Date: 2012-08-22 08:48:33
On 08/22/2012 10:06 AM, Eric Dumazet wrote:
quoted
Prior to 9ad7c049 the timeout was defined with 189secs. Now we have only
a timeout of 63secs.
((2 << 5) - 1) * 3 secs = 189 secs
((2 << 5) - 1) * 1 secs = 63 secs
Strange maths ... here I have :
(1+2+4+8+16) * 3 = 93 secs
vs
(1+2+4+8+16) * 1 = 31 secs
So even before said commit, we were not rfc1122 compliant.
Using 7 retries would give 127 seconds, still not rfc compliant.
You're missing the timeout after the 5th SYN packet was sent. This
would result in another 32 seconds (96 seconds).
The timeout is calculated here:
net/ipv4/tcp_timer.c(146:150)
if (boundary <= linear_backoff_thresh)
timeout = ((2 << boundary) - 1) * rto_base;
else
timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
(boundary - linear_backoff_thresh) * TCP_RTO_MAX;
quoted
To fulfill the MUST constraint in RFC1122 section 4.2.3.5 about R2 for
SYN segments, the values of TCP_SYN_RETRIES and TCP_SYNACK_RETRIES must
be changed to 7 reties.
((2 << 7) - 1) * 1 secs = 255 secs
This would result in an ETIMEDOUT of 4 minutes 15 seconds.
Signed-off-by: Alexander Bergmann <redacted>
---
include/net/tcp.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
@@ -98,10 +98,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);*15is~13-30mindependingonRTO.*/-#define TCP_SYN_RETRIES 5 /* number of times to retry active opening a+#define TCP_SYN_RETRIES 7 /* number of times to retry active opening a*connection:~180secisRFCminimum*/-#define TCP_SYNACK_RETRIES 5 /* number of times to retry passive opening a+#define TCP_SYNACK_RETRIES 7 /* number of times to retry passive opening a*connection:~180secisRFCminimum*/#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
Nice catch !
I kind of disagree with the SYNACK part.
I will look into this.
RFC 1122 says in 4.2.3.5 :
However, the values of R1 and R2 may be different for SYN
and data segments. In particular, R2 for a SYN segment MUST
be set large enough to provide retransmission of the segment
for at least 3 minutes. The application can close the
connection (i.e., give up on the open attempt) sooner, of
course.
I am not sure SYNACK segments were considered as a 'SYN segment' in this
section. (as the application cannot 'close' the connection on the passive
side, only kernel is aware of a SYN_RECV socket)
Increasing TCP_SYNACK_RETRIES from 5 to 7 or 8 amplifies the
SYN/synflood problem.
A valid client should retransmit its SYN packet for 180 seconds, I dont
believe we should make sure the SYNACK will be sent for 180 seconds as
well.
If we _really_ want to have a 3 minutes R2 for SYNACK, I suggest
changing things to that we dont send more than 5 SYNACKS, maybe using
RTO=6 after one retransmit
current situation :
1 sec
2 sec
4 sec
8 sec
16 sec
----
total of 31 seconds
1 sec
12 sec // switch to RTO = 6
24 sec
48 sec
96 sec
-----
total of 181 seconds
From: Eric Dumazet <hidden> Date: 2012-08-22 08:58:43
On Wed, 2012-08-22 at 10:48 +0200, Alex Bergmann wrote:
On 08/22/2012 10:06 AM, Eric Dumazet wrote:
quoted
quoted
Prior to 9ad7c049 the timeout was defined with 189secs. Now we have only
a timeout of 63secs.
((2 << 5) - 1) * 3 secs = 189 secs
((2 << 5) - 1) * 1 secs = 63 secs
Strange maths ... here I have :
(1+2+4+8+16) * 3 = 93 secs
vs
(1+2+4+8+16) * 1 = 31 secs
So even before said commit, we were not rfc1122 compliant.
Using 7 retries would give 127 seconds, still not rfc compliant.
You're missing the timeout after the 5th SYN packet was sent. This
would result in another 32 seconds (96 seconds).
The timeout is calculated here:
net/ipv4/tcp_timer.c(146:150)
if (boundary <= linear_backoff_thresh)
timeout = ((2 << boundary) - 1) * rto_base;
else
timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
(boundary - linear_backoff_thresh) * TCP_RTO_MAX;
Thats the code yes but you miss the fact that last occurence of the
timer doesnt send a frame on the _network_
R2 is derived from the last frame sent.
Fact that the connect() is a bit long to return to user space is not
relevant. We could block the task for 2 hours and still be non RFC
compliant.
Actual 5 frames are sent, so the effective global timeout is the one I
quoted.
1 + 2 + 4 + 8 + 16 and its 31
Just do a tcpdump and you can see it.
From: Alex Bergmann <hidden> Date: 2012-08-22 09:29:41
On 08/22/2012 10:58 AM, Eric Dumazet wrote:
On Wed, 2012-08-22 at 10:48 +0200, Alex Bergmann wrote:
quoted
On 08/22/2012 10:06 AM, Eric Dumazet wrote:
quoted
quoted
Prior to 9ad7c049 the timeout was defined with 189secs. Now we have only
a timeout of 63secs.
((2 << 5) - 1) * 3 secs = 189 secs
((2 << 5) - 1) * 1 secs = 63 secs
Strange maths ... here I have :
(1+2+4+8+16) * 3 = 93 secs
vs
(1+2+4+8+16) * 1 = 31 secs
So even before said commit, we were not rfc1122 compliant.
Using 7 retries would give 127 seconds, still not rfc compliant.
You're missing the timeout after the 5th SYN packet was sent. This
would result in another 32 seconds (96 seconds).
The timeout is calculated here:
net/ipv4/tcp_timer.c(146:150)
if (boundary <= linear_backoff_thresh)
timeout = ((2 << boundary) - 1) * rto_base;
else
timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
(boundary - linear_backoff_thresh) * TCP_RTO_MAX;
Thats the code yes but you miss the fact that last occurence of the
timer doesnt send a frame on the _network_
R2 is derived from the last frame sent.
Fact that the connect() is a bit long to return to user space is not
relevant. We could block the task for 2 hours and still be non RFC
compliant.
Actual 5 frames are sent, so the effective global timeout is the one I
quoted.
1 + 2 + 4 + 8 + 16 and its 31
Just do a tcpdump and you can see it.
Actual 6 SYN frames are sent. The initial one and 5 retries.
The kernel is waiting another 32 seconds for a SYN+ACK and then gives
the ETIMEDOUT back to userspace.
Do you mean that we have to send another SYN packet after the 3 minutes?
From: Eric Dumazet <hidden> Date: 2012-08-22 10:00:08
On Wed, 2012-08-22 at 11:29 +0200, Alex Bergmann wrote:
Actual 6 SYN frames are sent. The initial one and 5 retries.
first one had a t0 + 0 delay. How can it count ???
The kernel is waiting another 32 seconds for a SYN+ACK and then gives
the ETIMEDOUT back to userspace.
Do you mean that we have to send another SYN packet after the 3 minutes?
First SYN is not a retransmit
R2 = time_of_last_SYN - time_of_initial_SYN (t0) = 31
If you read RFC it states :
"In particular, R2 for a SYN segment MUST
be set large enough to provide retransmission of the segment
for at least 3 minutes."
That means that the last _retransmit_ MUST happen after 180 seconds.
And not :
Send all the restransmits at t0 + 1, then wait 180 seconds before giving
connect() a timeout indication.
From: Eric Dumazet <hidden> Date: 2012-08-22 10:03:34
On Wed, 2012-08-22 at 12:00 +0200, Eric Dumazet wrote:
On Wed, 2012-08-22 at 11:29 +0200, Alex Bergmann wrote:
quoted
Actual 6 SYN frames are sent. The initial one and 5 retries.
first one had a t0 + 0 delay. How can it count ???
quoted
The kernel is waiting another 32 seconds for a SYN+ACK and then gives
the ETIMEDOUT back to userspace.
Do you mean that we have to send another SYN packet after the 3 minutes?
First SYN is not a retransmit
R2 = time_of_last_SYN - time_of_initial_SYN (t0) = 31
If you read RFC it states :
"In particular, R2 for a SYN segment MUST
be set large enough to provide retransmission of the segment
for at least 3 minutes."
That means that the last _retransmit_ MUST happen after 180 seconds.
And not :
Send all the restransmits at t0 + 1, then wait 180 seconds before giving
connect() a timeout indication.
Therefore, the minimal connect() timeout should be : 180 + 100 seconds
(allowing 100 seconds for the SYNACKs sent in answer of the very last
retransmit to come back)
(100 seconds is the R2 for non SYN frames)
RFC quote : The value of R2 SHOULD
correspond to at least 100 seconds.
From: H.K. Jerry Chu <hidden> Date: 2012-08-22 16:44:15
On Tue, Aug 21, 2012 at 4:29 PM, Alex Bergmann [off-list ref] wrote:
Hi David,
I'm not 100% sure, but it looks like I found an RFC mismatch with the
current default values of the TCP implementation.
Alex
From 8b854a525eb45f64ad29dfab16f9d9f681e84495 Mon Sep 17 00:00:00 2001
From: Alexander Bergmann <redacted>
Date: Wed, 22 Aug 2012 00:29:08 +0200
Subject: [PATCH 1/1] tcp: Wrong timeout for SYN segments
Commit 9ad7c049 changed the initRTO from 3secs to 1sec in accordance to
RFC6298 (former RFC2988bis). This introduced a gap with RFC1122 that
defines a minimum retransmission window for SYN segments of at least
180secs.
Prior to 9ad7c049 the timeout was defined with 189secs. Now we have only
a timeout of 63secs.
((2 << 5) - 1) * 3 secs = 189 secs
((2 << 5) - 1) * 1 secs = 63 secs
To fulfill the MUST constraint in RFC1122 section 4.2.3.5 about R2 for
SYN segments, the values of TCP_SYN_RETRIES and TCP_SYNACK_RETRIES must
be changed to 7 reties.
((2 << 7) - 1) * 1 secs = 255 secs
This would result in an ETIMEDOUT of 4 minutes 15 seconds.
This issue occurred to me right after I submitted the patch for RFC6298.
I did not commit any more change because RFC compliance aside, 180secs
just seem like eternity in the Internet age.
(See my past post on this at
http://marc.info/?l=linux-netdev&m=130759078118866&w=2)
Jerry
@@ -98,10 +98,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);*15is~13-30mindependingonRTO.*/-#define TCP_SYN_RETRIES 5 /* number of times to retry active opening a+#define TCP_SYN_RETRIES 7 /* number of times to retry active opening a*connection:~180secisRFCminimum*/-#define TCP_SYNACK_RETRIES 5 /* number of times to retry passive opening a+#define TCP_SYNACK_RETRIES 7 /* number of times to retry passive opening a*connection:~180secisRFCminimum*/#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT--
1.7.8.6
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: H.K. Jerry Chu <hidden> Date: 2012-08-22 17:29:30
On Wed, Aug 22, 2012 at 3:03 AM, Eric Dumazet [off-list ref] wrote:
On Wed, 2012-08-22 at 12:00 +0200, Eric Dumazet wrote:
quoted
On Wed, 2012-08-22 at 11:29 +0200, Alex Bergmann wrote:
quoted
Actual 6 SYN frames are sent. The initial one and 5 retries.
first one had a t0 + 0 delay. How can it count ???
quoted
The kernel is waiting another 32 seconds for a SYN+ACK and then gives
the ETIMEDOUT back to userspace.
Do you mean that we have to send another SYN packet after the 3 minutes?
First SYN is not a retransmit
R2 = time_of_last_SYN - time_of_initial_SYN (t0) = 31
If you read RFC it states :
"In particular, R2 for a SYN segment MUST
be set large enough to provide retransmission of the segment
for at least 3 minutes."
That means that the last _retransmit_ MUST happen after 180 seconds.
And not :
Send all the restransmits at t0 + 1, then wait 180 seconds before giving
connect() a timeout indication.
Therefore, the minimal connect() timeout should be : 180 + 100 seconds
(allowing 100 seconds for the SYNACKs sent in answer of the very last
retransmit to come back)
(100 seconds is the R2 for non SYN frames)
RFC quote : The value of R2 SHOULD
correspond to at least 100 seconds.
I agree if you take RFC1122 literally the last retransmission must
happen no less than 3 minutes from the 1st SYN... Oh actually it'd be
3 minutes plus initRTO because the 3 minutes applies only to
"retransmission" as in
"R2 for a SYN segment MUST be set large enough to provide retransmission
of the segment for at least 3 minutes.:
But IMHO 6 retries providing 1+2+4+8+16+32 = 63 secs retransmission plus
64 secs wait time totaling 127 secs is really plenty enough.
You have a good point on SYN-ACK.
Jerry
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html