Hi all,
I'm using freeradius as a radius server for a Cisco SSG (Service Selection
Gateway) which
we use to make people authenticate before they access the internet.
We then charge for the volume of traffic used.
The SSG sends large numbers (300+) of radius accounting alive packets back
to back
without waiting for a reply. With several thousand users (and hence
accounting
update packets) the burst rate of radius requests gets very high and
freeradius drops requests.
In threaded mode, freeradius drops the request if there are no threads
available.
In non-threaded mode, it doesn't process the requests fast enough for my
needs.
To get around the situation I wrote the following patch which does two
things:
1. It increases the buffer size of the udp socket so the OS will buffer udp
packets
2. It checks to make sure a thread is available to handle the request before
it reads
from the socket. If a thread is not available it sleeps for a mili
second and tries again.
I've found that running freeradius multithreaded backended into a db on
multi-cpu
machine increased by an order of magnitude the rate of accounting packets/s
that can be processed.
I'm running freeradius release 0.9.0_final on Solaris 8 on a variety of sun
sparc boxes backended into
Sybase and Postgresql. Freeradius was compiled under gcc 2.95.3
It helped me.
I hope it helps someone else too.
Regards,
- Hindrik
-------------------------------------------------
Hindrik Buining
Senior Network Services Engineer
Communications Unit
University of New South Wales
Sydney, Australia
+61-2-9385-1144(w)
+61-2-9385-1112(f)
-------------------------------------------------
*** radiusd.c.orig Thu Aug 14 13:49:00 2003
--- radiusd.c Thu Aug 14 13:53:20 2003
***************
*** 139,145 ****
--- 139,147 ----
static int refresh_request(REQUEST *request, void *data);
#ifdef HAVE_PTHREAD_H
extern int rad_spawn_child(REQUEST *, RAD_REQUEST_FUNP);
+ extern int threads_available();
#else
+ static inline int threads_available() { return(1); }
#ifdef ALLOW_CHILD_FORKS
static int rad_spawn_child(REQUEST *, RAD_REQUEST_FUNP);
#endif
***************
*** 284,289 ****
--- 286,303 ----
struct sigaction act;
#endif
+ /* Hindrik June 2003
+ * Variables used to increase the receive socket buffer size
+ */
+ int optval,optlen;
+
+ /* Hindrik May 2003
+ * We want to sleep for a few mili seconds
+ */
+ struct timeval sleep_time;
+ sleep_time.tv_sec=0;
+ sleep_time.tv_usec = 1000;
+
syslog_facility = LOG_DAEMON;
#ifdef OSFC2
***************
*** 536,541 ****
--- 550,564 ----
perror ("acct socket");
exit(1);
}
+ optval = 256*1024;
+ optlen = sizeof(optval);
+ if( setsockopt(acctfd, SOL_SOCKET,
+ SO_RCVBUF, (void *)&optval, optlen)
+ ) {
+ perror( "Setting socket option");
+ exit(1);
+ }
+
sa = (struct sockaddr_in *) &salocal;
memset ((char *) sa, '\0', sizeof(salocal));
***************
*** 769,774 ****
--- 792,800 ----
#endif
radlog(L_INFO, "Ready to process requests.");
+ #ifdef HAVE_PTHREAD_H
+ radlog(L_INFO, "Running with threads.");
+ #endif
start_time = time(NULL);
/*
***************
*** 887,892 ****
--- 913,924 ----
}
#endif
+
+ while( !threads_available() ) {
+ radlog(L_ERR, "No threads available yet. Sleeping...");
+ select(0,NULL,NULL,NULL,&sleep_time);
+ }
+
status = select(max_fd + 1, &readfds, NULL, NULL, tv);
#ifndef HAVE_PTHREAD_H
/*
***************
*** 2184,2189 ****
--- 2216,2222 ----
return request;
}
+
/*
* If we're using the thread pool, then the function in
* 'threads.c' replaces this one.
*** threads.c.orig Thu Aug 14 13:55:30 2003
--- threads.c Thu Aug 14 13:50:32 2003
***************
*** 209,215 ****
self->thread_num);
break;
}
-
/*
* Stupid implementations of sem_wait return on
* signals, but don't return -1.
--- 209,214 ----
***************
*** 297,302 ****
--- 296,337 ----
free(handle);
}
+
+
+ /*
+ * Check to see if we can process another request.
+ * Returns true if the threadpool is not full and all threads
+ * are busy.
+ *
+ *
+ */
+ int threads_available() {
+ THREAD_HANDLE *handle;
+
+ /* printf("threads_available():\tThread Count: total %d, max
%d\n",thread_pool.total_threads, thread_pool.max_threads); */
+
+ /* If we can still span another thread than we have threads available */
+ if (thread_pool.total_threads < thread_pool.max_threads) {
+ return(1);
+ }
+
+ /* Search the thread list looking for an available thread */
+ for (handle = thread_pool.head; handle != NULL; handle = handle->next){
+
+ /* Ignore threads which aren't running. */
+ if( handle->status != THREAD_RUNNING ) {
+ continue;
+ }
+
+ if (handle->request == NULL) {
+ /* radlog(L_INFO, "threads_available():\tFound a free request."); */
+ return(1); /* We've found an available thread */
+ }
+ }
+ return (0);
+
+ }
+
/*
* Spawn a new thread, and place it in the thread pool.
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html