diff options
author | Julian Anastasov <ja@ssi.bg> | 2009-10-19 06:10:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-19 22:19:06 -0400 |
commit | b103cf34382f26ff48a87931b83f13b177b47c1a (patch) | |
tree | 6922379bca3fc9935d394bc474a91b859ac06813 | |
parent | 0c3d79bce48034018e840468ac5a642894a521a3 (diff) |
tcp: fix TCP_DEFER_ACCEPT retrans calculation
Fix TCP_DEFER_ACCEPT conversion between seconds and
retransmission to match the TCP SYN-ACK retransmission periods
because the time is converted to such retransmissions. The old
algorithm selects one more retransmission in some cases. Allow
up to 255 retransmissions.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/tcp.c | 55 |
1 files changed, 43 insertions, 12 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 64d0af675823..9b2756fbdf9b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -326,6 +326,43 @@ void tcp_enter_memory_pressure(struct sock *sk) | |||
326 | 326 | ||
327 | EXPORT_SYMBOL(tcp_enter_memory_pressure); | 327 | EXPORT_SYMBOL(tcp_enter_memory_pressure); |
328 | 328 | ||
329 | /* Convert seconds to retransmits based on initial and max timeout */ | ||
330 | static u8 secs_to_retrans(int seconds, int timeout, int rto_max) | ||
331 | { | ||
332 | u8 res = 0; | ||
333 | |||
334 | if (seconds > 0) { | ||
335 | int period = timeout; | ||
336 | |||
337 | res = 1; | ||
338 | while (seconds > period && res < 255) { | ||
339 | res++; | ||
340 | timeout <<= 1; | ||
341 | if (timeout > rto_max) | ||
342 | timeout = rto_max; | ||
343 | period += timeout; | ||
344 | } | ||
345 | } | ||
346 | return res; | ||
347 | } | ||
348 | |||
349 | /* Convert retransmits to seconds based on initial and max timeout */ | ||
350 | static int retrans_to_secs(u8 retrans, int timeout, int rto_max) | ||
351 | { | ||
352 | int period = 0; | ||
353 | |||
354 | if (retrans > 0) { | ||
355 | period = timeout; | ||
356 | while (--retrans) { | ||
357 | timeout <<= 1; | ||
358 | if (timeout > rto_max) | ||
359 | timeout = rto_max; | ||
360 | period += timeout; | ||
361 | } | ||
362 | } | ||
363 | return period; | ||
364 | } | ||
365 | |||
329 | /* | 366 | /* |
330 | * Wait for a TCP event. | 367 | * Wait for a TCP event. |
331 | * | 368 | * |
@@ -2163,16 +2200,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
2163 | break; | 2200 | break; |
2164 | 2201 | ||
2165 | case TCP_DEFER_ACCEPT: | 2202 | case TCP_DEFER_ACCEPT: |
2166 | icsk->icsk_accept_queue.rskq_defer_accept = 0; | 2203 | /* Translate value in seconds to number of retransmits */ |
2167 | if (val > 0) { | 2204 | icsk->icsk_accept_queue.rskq_defer_accept = |
2168 | /* Translate value in seconds to number of | 2205 | secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, |
2169 | * retransmits */ | 2206 | TCP_RTO_MAX / HZ); |
2170 | while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && | ||
2171 | val > ((TCP_TIMEOUT_INIT / HZ) << | ||
2172 | icsk->icsk_accept_queue.rskq_defer_accept)) | ||
2173 | icsk->icsk_accept_queue.rskq_defer_accept++; | ||
2174 | icsk->icsk_accept_queue.rskq_defer_accept++; | ||
2175 | } | ||
2176 | break; | 2207 | break; |
2177 | 2208 | ||
2178 | case TCP_WINDOW_CLAMP: | 2209 | case TCP_WINDOW_CLAMP: |
@@ -2353,8 +2384,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level, | |||
2353 | val = (val ? : sysctl_tcp_fin_timeout) / HZ; | 2384 | val = (val ? : sysctl_tcp_fin_timeout) / HZ; |
2354 | break; | 2385 | break; |
2355 | case TCP_DEFER_ACCEPT: | 2386 | case TCP_DEFER_ACCEPT: |
2356 | val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 : | 2387 | val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept, |
2357 | ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1)); | 2388 | TCP_TIMEOUT_INIT / HZ, TCP_RTO_MAX / HZ); |
2358 | break; | 2389 | break; |
2359 | case TCP_WINDOW_CLAMP: | 2390 | case TCP_WINDOW_CLAMP: |
2360 | val = tp->window_clamp; | 2391 | val = tp->window_clamp; |