2005-06-19 09:47:59 +04:00
/*
* NET Generic infrastructure for Network protocols .
*
* Authors : Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
*
* From code originally in include / net / tcp . h
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/module.h>
# include <linux/random.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <net/request_sock.h>
2005-06-19 09:49:40 +04:00
/*
* Maximum number of SYN_RECV sockets in queue per LISTEN socket .
* One SYN_RECV socket costs about 80 bytes on a 32 bit machine .
* It would be better to replace it with a global counter for all sockets
* but then some measure against one socket starving all other sockets
* would be needed .
*
* It was 128 by default . Experiments with real servers show , that
* it is absolutely not enough even at 100 conn / sec . 256 cures most
* of problems . This value is adjusted to 128 for very small machines
* ( < = 32 Mb of memory ) and to 1024 on normal or better ones ( > = 256 Mb ) .
* Further increasing requires to change hash table size .
*/
int sysctl_max_syn_backlog = 256 ;
2005-06-19 09:47:59 +04:00
int reqsk_queue_alloc ( struct request_sock_queue * queue ,
const int nr_table_entries )
{
2005-06-19 09:48:55 +04:00
const int lopt_size = sizeof ( struct listen_sock ) +
2005-06-19 09:47:59 +04:00
nr_table_entries * sizeof ( struct request_sock * ) ;
2006-04-08 01:52:59 +04:00
struct listen_sock * lopt = kzalloc ( lopt_size , GFP_KERNEL ) ;
2005-06-19 09:47:59 +04:00
if ( lopt = = NULL )
return - ENOMEM ;
for ( lopt - > max_qlen_log = 6 ;
( 1 < < lopt - > max_qlen_log ) < sysctl_max_syn_backlog ;
lopt - > max_qlen_log + + ) ;
get_random_bytes ( & lopt - > hash_rnd , sizeof ( lopt - > hash_rnd ) ) ;
rwlock_init ( & queue - > syn_wait_lock ) ;
2006-03-27 05:39:55 +04:00
queue - > rskq_accept_head = NULL ;
2005-08-10 06:33:31 +04:00
lopt - > nr_table_entries = nr_table_entries ;
2005-06-19 09:47:59 +04:00
write_lock_bh ( & queue - > syn_wait_lock ) ;
queue - > listen_opt = lopt ;
write_unlock_bh ( & queue - > syn_wait_lock ) ;
return 0 ;
}
EXPORT_SYMBOL ( reqsk_queue_alloc ) ;
2005-08-10 06:33:31 +04:00
void reqsk_queue_destroy ( struct request_sock_queue * queue )
{
/* make all the listen_opt local to us */
struct listen_sock * lopt = reqsk_queue_yank_listen_sk ( queue ) ;
if ( lopt - > qlen ! = 0 ) {
int i ;
for ( i = 0 ; i < lopt - > nr_table_entries ; i + + ) {
struct request_sock * req ;
while ( ( req = lopt - > syn_table [ i ] ) ! = NULL ) {
lopt - > syn_table [ i ] = req - > dl_next ;
lopt - > qlen - - ;
reqsk_free ( req ) ;
}
}
}
BUG_TRAP ( lopt - > qlen = = 0 ) ;
kfree ( lopt ) ;
}
EXPORT_SYMBOL ( reqsk_queue_destroy ) ;