[ICSK]: Move generalised functions from tcp to inet_connection_sock

This also improves reqsk_queue_prune and renames it to
inet_csk_reqsk_queue_prune, as it deals with both inet_connection_sock
and inet_request_sock objects, not just with request_sock ones thus
belonging to inet_request_sock.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Arnaldo Carvalho de Melo 2005-08-09 20:15:09 -07:00 committed by David S. Miller
parent 7c657876b6
commit a019d6fe2b
7 changed files with 224 additions and 226 deletions

View file

@ -424,103 +424,14 @@ out_unlock:
sock_put(sk);
}
void reqsk_queue_prune(struct request_sock_queue *queue, struct sock *parent,
const unsigned long interval, const unsigned long timeout,
const unsigned long max_rto, int max_retries)
{
struct inet_connection_sock *icsk = inet_csk(parent);
struct listen_sock *lopt = queue->listen_opt;
int thresh = max_retries;
unsigned long now = jiffies;
struct request_sock **reqp, *req;
int i, budget;
if (lopt == NULL || lopt->qlen == 0)
return;
/* Normally all the openreqs are young and become mature
* (i.e. converted to established socket) for first timeout.
* If synack was not acknowledged for 3 seconds, it means
* one of the following things: synack was lost, ack was lost,
* rtt is high or nobody planned to ack (i.e. synflood).
* When server is a bit loaded, queue is populated with old
* open requests, reducing effective size of queue.
* When server is well loaded, queue size reduces to zero
* after several minutes of work. It is not synflood,
* it is normal operation. The solution is pruning
* too old entries overriding normal timeout, when
* situation becomes dangerous.
*
* Essentially, we reserve half of room for young
* embrions; and abort old ones without pity, if old
* ones are about to clog our table.
*/
if (lopt->qlen>>(lopt->max_qlen_log-1)) {
int young = (lopt->qlen_young<<1);
while (thresh > 2) {
if (lopt->qlen < young)
break;
thresh--;
young <<= 1;
}
}
if (queue->rskq_defer_accept)
max_retries = queue->rskq_defer_accept;
budget = 2 * (lopt->nr_table_entries / (timeout / interval));
i = lopt->clock_hand;
do {
reqp=&lopt->syn_table[i];
while ((req = *reqp) != NULL) {
if (time_after_eq(now, req->expires)) {
if ((req->retrans < thresh ||
(inet_rsk(req)->acked && req->retrans < max_retries))
&& !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) {
unsigned long timeo;
if (req->retrans++ == 0)
lopt->qlen_young--;
timeo = min((timeout << req->retrans), max_rto);
req->expires = now + timeo;
reqp = &req->dl_next;
continue;
}
/* Drop this request */
inet_csk_reqsk_queue_unlink(parent, req, reqp);
reqsk_queue_removed(&icsk->icsk_accept_queue, req);
reqsk_free(req);
continue;
}
reqp = &req->dl_next;
}
i = (i + 1) & (lopt->nr_table_entries - 1);
} while (--budget > 0);
lopt->clock_hand = i;
if (lopt->qlen)
inet_csk_reset_keepalive_timer(parent, interval);
}
EXPORT_SYMBOL_GPL(reqsk_queue_prune);
/*
* Timer for listening sockets
*/
static void tcp_synack_timer(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
const int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
reqsk_queue_prune(&icsk->icsk_accept_queue, sk, TCP_SYNQ_INTERVAL,
TCP_TIMEOUT_INIT, TCP_RTO_MAX, max_retries);
inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL,
TCP_TIMEOUT_INIT, TCP_RTO_MAX);
}
void tcp_set_keepalive(struct sock *sk, int val)