aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2009-10-19 06:10:40 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-19 22:19:06 -0400
commitb103cf34382f26ff48a87931b83f13b177b47c1a (patch)
tree6922379bca3fc9935d394bc474a91b859ac06813 /net
parent0c3d79bce48034018e840468ac5a642894a521a3 (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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp.c55
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
327EXPORT_SYMBOL(tcp_enter_memory_pressure); 327EXPORT_SYMBOL(tcp_enter_memory_pressure);
328 328
329/* Convert seconds to retransmits based on initial and max timeout */
330static 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 */
350static 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;