diff options
Diffstat (limited to 'net/ipv4/tcp_timer.c')
| -rw-r--r-- | net/ipv4/tcp_timer.c | 93 |
1 files changed, 2 insertions, 91 deletions
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index b614ad4d30c9..72cec6981830 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
| @@ -424,103 +424,14 @@ out_unlock: | |||
| 424 | sock_put(sk); | 424 | sock_put(sk); |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | void reqsk_queue_prune(struct request_sock_queue *queue, struct sock *parent, | ||
| 428 | const unsigned long interval, const unsigned long timeout, | ||
| 429 | const unsigned long max_rto, int max_retries) | ||
| 430 | { | ||
| 431 | struct inet_connection_sock *icsk = inet_csk(parent); | ||
| 432 | struct listen_sock *lopt = queue->listen_opt; | ||
| 433 | int thresh = max_retries; | ||
| 434 | unsigned long now = jiffies; | ||
| 435 | struct request_sock **reqp, *req; | ||
| 436 | int i, budget; | ||
| 437 | |||
| 438 | if (lopt == NULL || lopt->qlen == 0) | ||
| 439 | return; | ||
| 440 | |||
| 441 | /* Normally all the openreqs are young and become mature | ||
| 442 | * (i.e. converted to established socket) for first timeout. | ||
| 443 | * If synack was not acknowledged for 3 seconds, it means | ||
| 444 | * one of the following things: synack was lost, ack was lost, | ||
| 445 | * rtt is high or nobody planned to ack (i.e. synflood). | ||
| 446 | * When server is a bit loaded, queue is populated with old | ||
| 447 | * open requests, reducing effective size of queue. | ||
| 448 | * When server is well loaded, queue size reduces to zero | ||
| 449 | * after several minutes of work. It is not synflood, | ||
| 450 | * it is normal operation. The solution is pruning | ||
| 451 | * too old entries overriding normal timeout, when | ||
| 452 | * situation becomes dangerous. | ||
| 453 | * | ||
| 454 | * Essentially, we reserve half of room for young | ||
| 455 | * embrions; and abort old ones without pity, if old | ||
| 456 | * ones are about to clog our table. | ||
| 457 | */ | ||
| 458 | if (lopt->qlen>>(lopt->max_qlen_log-1)) { | ||
| 459 | int young = (lopt->qlen_young<<1); | ||
| 460 | |||
| 461 | while (thresh > 2) { | ||
| 462 | if (lopt->qlen < young) | ||
| 463 | break; | ||
| 464 | thresh--; | ||
| 465 | young <<= 1; | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | if (queue->rskq_defer_accept) | ||
| 470 | max_retries = queue->rskq_defer_accept; | ||
| 471 | |||
| 472 | budget = 2 * (lopt->nr_table_entries / (timeout / interval)); | ||
| 473 | i = lopt->clock_hand; | ||
| 474 | |||
| 475 | do { | ||
| 476 | reqp=&lopt->syn_table[i]; | ||
| 477 | while ((req = *reqp) != NULL) { | ||
| 478 | if (time_after_eq(now, req->expires)) { | ||
| 479 | if ((req->retrans < thresh || | ||
| 480 | (inet_rsk(req)->acked && req->retrans < max_retries)) | ||
| 481 | && !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) { | ||
| 482 | unsigned long timeo; | ||
| 483 | |||
| 484 | if (req->retrans++ == 0) | ||
| 485 | lopt->qlen_young--; | ||
| 486 | timeo = min((timeout << req->retrans), max_rto); | ||
| 487 | req->expires = now + timeo; | ||
| 488 | reqp = &req->dl_next; | ||
| 489 | continue; | ||
| 490 | } | ||
| 491 | |||
| 492 | /* Drop this request */ | ||
| 493 | inet_csk_reqsk_queue_unlink(parent, req, reqp); | ||
| 494 | reqsk_queue_removed(&icsk->icsk_accept_queue, req); | ||
| 495 | reqsk_free(req); | ||
| 496 | continue; | ||
| 497 | } | ||
| 498 | reqp = &req->dl_next; | ||
| 499 | } | ||
| 500 | |||
| 501 | i = (i + 1) & (lopt->nr_table_entries - 1); | ||
| 502 | |||
| 503 | } while (--budget > 0); | ||
| 504 | |||
| 505 | lopt->clock_hand = i; | ||
| 506 | |||
| 507 | if (lopt->qlen) | ||
| 508 | inet_csk_reset_keepalive_timer(parent, interval); | ||
| 509 | } | ||
| 510 | |||
| 511 | EXPORT_SYMBOL_GPL(reqsk_queue_prune); | ||
| 512 | |||
| 513 | /* | 427 | /* |
| 514 | * Timer for listening sockets | 428 | * Timer for listening sockets |
| 515 | */ | 429 | */ |
| 516 | 430 | ||
| 517 | static void tcp_synack_timer(struct sock *sk) | 431 | static void tcp_synack_timer(struct sock *sk) |
| 518 | { | 432 | { |
| 519 | struct inet_connection_sock *icsk = inet_csk(sk); | 433 | inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL, |
| 520 | const int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; | 434 | TCP_TIMEOUT_INIT, TCP_RTO_MAX); |
| 521 | |||
| 522 | reqsk_queue_prune(&icsk->icsk_accept_queue, sk, TCP_SYNQ_INTERVAL, | ||
| 523 | TCP_TIMEOUT_INIT, TCP_RTO_MAX, max_retries); | ||
| 524 | } | 435 | } |
| 525 | 436 | ||
| 526 | void tcp_set_keepalive(struct sock *sk, int val) | 437 | void tcp_set_keepalive(struct sock *sk, int val) |
