Include endpoint address in accounting dump files.

Convert mainloop to use epoll rather than select.
This commit is contained in:
bodea 2005-06-04 15:42:35 +00:00
parent a51e573de1
commit ec4de7f8c5
12 changed files with 549 additions and 267 deletions

11
Changes
View file

@ -1,9 +1,7 @@
* Thu Jun 2 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0 * Sun Jun 5 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0
- Add IPv6 support from Jonathan McDowell. - Add IPv6 support from Jonathan McDowell.
- Add CHAP support from Jordan Hrycaj. - Add CHAP support from Jordan Hrycaj.
- Add interim accounting support from Vladislav Bjelic. - Add interim accounting support from Vladislav Bjelic.
- Add Acct-Output-Gigawords, Acct-Input-Gigawords attributes to RADIUS
accounting packets.
- Negotiate MRU, default 1458 to avoid fragmentation. - Negotiate MRU, default 1458 to avoid fragmentation.
- Sanity check that cluster_send_session is not called from a child - Sanity check that cluster_send_session is not called from a child
process. process.
@ -31,6 +29,13 @@
- New config option: allow_duplicate_users which determines whether - New config option: allow_duplicate_users which determines whether
or not to kill older sessions with the same username. or not to kill older sessions with the same username.
- Fix byte counters in accounting records. - Fix byte counters in accounting records.
- Add Acct-Output-Gigawords, Acct-Input-Gigawords attributes to RADIUS
accounting packets.
- Fix icmp host unreachable to use router address.
- Include endpoint address in accounting dump files.
- Convert mainloop to use epoll rather than select.
- Add note about fragmentation in Docs/manual.html, and a sample
iptables rule for MSS clamping.
- Merge 2.0.22: - Merge 2.0.22:
+ Show session open time in "show session"/"show user" detailed output. + Show session open time in "show session"/"show user" detailed output.
+ Have slaves with BGP configured drop BGP on receipt of a shutdown + Have slaves with BGP configured drop BGP on receipt of a shutdown

View file

@ -37,6 +37,7 @@ TESTS = generateload bounce
DEFINES += -DSTATISTICS DEFINES += -DSTATISTICS
DEFINES += -DSTAT_CALLS DEFINES += -DSTAT_CALLS
DEFINES += -DRINGBUFFER DEFINES += -DRINGBUFFER
DEFINES += -DHAVE_EPOLL
DEFINES += -DBGP DEFINES += -DBGP
OBJS += bgp.o OBJS += bgp.o

85
bgp.c
View file

@ -10,7 +10,7 @@
* nor RFC2385 (which requires a kernel patch on 2.4 kernels). * nor RFC2385 (which requires a kernel patch on 2.4 kernels).
*/ */
char const *cvs_id_bgp = "$Id: bgp.c,v 1.9 2004/12/16 08:49:52 bodea Exp $"; char const *cvs_id_bgp = "$Id: bgp.c,v 1.10 2005/06/04 15:42:35 bodea Exp $";
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -75,6 +75,10 @@ int bgp_setup(int as)
return 0; return 0;
} }
peer->edata.type = FD_TYPE_BGP;
peer->edata.index = i;
peer->events = 0;
} }
if (as < 1) if (as < 1)
@ -270,6 +274,7 @@ static void bgp_clear(struct bgp_peer *peer)
peer->inbuf->done = 0; peer->inbuf->done = 0;
peer->cli_flag = 0; peer->cli_flag = 0;
peer->events = 0;
if (peer->state != peer->next_state) if (peer->state != peer->next_state)
{ {
@ -487,40 +492,69 @@ void bgp_enable_routing(int enable)
LOG(4, 0, 0, "%s BGP routing\n", enable ? "Enabled" : "Suspended"); LOG(4, 0, 0, "%s BGP routing\n", enable ? "Enabled" : "Suspended");
} }
/* return a bitmask indicating if the socket should be added to the #ifdef HAVE_EPOLL
read set (1) and or write set (2) for select */ # include <sys/epoll.h>
int bgp_select_state(struct bgp_peer *peer) #else
# include "fake_epoll.h"
#endif
/* return a bitmask of the events required to poll this peer's fd */
int bgp_set_poll()
{ {
int flags = 0; int i;
if (!bgp_configured) if (!bgp_configured)
return 0; return 0;
for (i = 0; i < BGP_NUM_PEERS; i++)
{
struct bgp_peer *peer = &bgp_peers[i];
int events = 0;
if (peer->state == Disabled || peer->state == Idle) if (peer->state == Disabled || peer->state == Idle)
return 0; continue;
if (peer->inbuf->done < BGP_MAX_PACKET_SIZE) if (peer->inbuf->done < BGP_MAX_PACKET_SIZE)
flags |= 1; events |= EPOLLIN;
if (peer->state == Connect || /* connection in progress */ if (peer->state == Connect || /* connection in progress */
peer->update_routes || /* routing updates */ peer->update_routes || /* routing updates */
peer->outbuf->packet.header.len) /* pending output */ peer->outbuf->packet.header.len) /* pending output */
flags |= 2; events |= EPOLLOUT;
return flags; if (peer->events != events)
{
struct epoll_event ev;
ev.events = peer->events = events;
ev.data.ptr = &peer->edata;
epoll_ctl(epollfd, EPOLL_CTL_MOD, peer->sock, &ev);
}
}
return 1;
} }
/* process bgp peer */ /* process bgp events/timers */
int bgp_process(struct bgp_peer *peer, int readable, int writable) int bgp_process(uint32_t events[])
{ {
int i;
if (!bgp_configured) if (!bgp_configured)
return 0; return 0;
for (i = 0; i < BGP_NUM_PEERS; i++)
{
struct bgp_peer *peer = &bgp_peers[i];
if (*peer->name && peer->cli_flag == BGP_CLI_RESTART) if (*peer->name && peer->cli_flag == BGP_CLI_RESTART)
return bgp_restart(peer); {
bgp_restart(peer);
continue;
}
if (peer->state == Disabled) if (peer->state == Disabled)
return 1; continue;
if (peer->cli_flag) if (peer->cli_flag)
{ {
@ -551,7 +585,7 @@ int bgp_process(struct bgp_peer *peer, int readable, int writable)
} }
/* handle empty/fill of buffers */ /* handle empty/fill of buffers */
if (writable) if (events[i] & EPOLLOUT)
{ {
int r = 1; int r = 1;
if (peer->state == Connect) if (peer->state == Connect)
@ -560,13 +594,13 @@ int bgp_process(struct bgp_peer *peer, int readable, int writable)
r = bgp_write(peer); r = bgp_write(peer);
if (!r) if (!r)
return 0; continue;
} }
if (readable) if (events[i] & (EPOLLIN|EPOLLHUP))
{ {
if (!bgp_read(peer)) if (!bgp_read(peer))
return 0; continue;
} }
/* process input buffer contents */ /* process input buffer contents */
@ -574,7 +608,7 @@ int bgp_process(struct bgp_peer *peer, int readable, int writable)
&& !peer->outbuf->packet.header.len) /* may need to queue a response */ && !peer->outbuf->packet.header.len) /* may need to queue a response */
{ {
if (bgp_handle_input(peer) < 0) if (bgp_handle_input(peer) < 0)
return 0; continue;
} }
/* process pending updates */ /* process pending updates */
@ -582,7 +616,7 @@ int bgp_process(struct bgp_peer *peer, int readable, int writable)
&& !peer->outbuf->packet.header.len) /* ditto */ && !peer->outbuf->packet.header.len) /* ditto */
{ {
if (!bgp_send_update(peer)) if (!bgp_send_update(peer))
return 0; continue;
} }
/* process timers */ /* process timers */
@ -594,7 +628,7 @@ int bgp_process(struct bgp_peer *peer, int readable, int writable)
peer->name, peer->hold); peer->name, peer->hold);
bgp_send_notification(peer, BGP_ERR_HOLD_TIMER_EXP, 0); bgp_send_notification(peer, BGP_ERR_HOLD_TIMER_EXP, 0);
return 0; continue;
} }
if (time_now > peer->keepalive_time && !peer->outbuf->packet.header.len) if (time_now > peer->keepalive_time && !peer->outbuf->packet.header.len)
@ -603,14 +637,15 @@ int bgp_process(struct bgp_peer *peer, int readable, int writable)
else if (peer->state == Idle) else if (peer->state == Idle)
{ {
if (time_now > peer->retry_time) if (time_now > peer->retry_time)
return bgp_connect(peer); bgp_connect(peer);
} }
else if (time_now > peer->state_time + BGP_STATE_TIME) else if (time_now > peer->state_time + BGP_STATE_TIME)
{ {
LOG(1, 0, 0, "%s timer expired for BGP peer %s\n", LOG(1, 0, 0, "%s timer expired for BGP peer %s\n",
bgp_state_str(peer->state), peer->name); bgp_state_str(peer->state), peer->name);
return bgp_restart(peer); bgp_restart(peer);
}
} }
return 1; return 1;
@ -661,6 +696,7 @@ static int bgp_connect(struct bgp_peer *peer)
{ {
static int bgp_port = 0; static int bgp_port = 0;
struct sockaddr_in addr; struct sockaddr_in addr;
struct epoll_event ev;
if (!bgp_port) if (!bgp_port)
{ {
@ -683,6 +719,11 @@ static int bgp_connect(struct bgp_peer *peer)
return 0; return 0;
} }
/* add to poll set */
ev.events = peer->events = EPOLLOUT;
ev.data.ptr = &peer->edata;
epoll_ctl(epollfd, EPOLL_CTL_ADD, peer->sock, &ev);
/* set to non-blocking */ /* set to non-blocking */
fcntl(peer->sock, F_SETFL, fcntl(peer->sock, F_GETFL, 0) | O_NONBLOCK); fcntl(peer->sock, F_SETFL, fcntl(peer->sock, F_GETFL, 0) | O_NONBLOCK);

8
bgp.h
View file

@ -1,5 +1,5 @@
/* BGPv4 (RFC1771) */ /* BGPv4 (RFC1771) */
/* $Id: bgp.h,v 1.4 2004/12/16 08:49:52 bodea Exp $ */ /* $Id: bgp.h,v 1.5 2005/06/04 15:42:35 bodea Exp $ */
#ifndef __BGP_H__ #ifndef __BGP_H__
#define __BGP_H__ #define __BGP_H__
@ -173,6 +173,8 @@ struct bgp_peer {
int cli_flag; /* updates requested from CLI */ int cli_flag; /* updates requested from CLI */
char *path_attrs; /* path attrs to send in UPDATE message */ char *path_attrs; /* path attrs to send in UPDATE message */
int path_attr_len; /* length of path attrs */ int path_attr_len; /* length of path attrs */
uint32_t events; /* events to poll */
struct event_data edata; /* poll data */
}; };
/* bgp_peer.cli_flag */ /* bgp_peer.cli_flag */
@ -194,8 +196,8 @@ int bgp_restart(struct bgp_peer *peer);
int bgp_add_route(in_addr_t ip, in_addr_t mask); int bgp_add_route(in_addr_t ip, in_addr_t mask);
int bgp_del_route(in_addr_t ip, in_addr_t mask); int bgp_del_route(in_addr_t ip, in_addr_t mask);
void bgp_enable_routing(int enable); void bgp_enable_routing(int enable);
int bgp_select_state(struct bgp_peer *peer); int bgp_set_poll(void);
int bgp_process(struct bgp_peer *peer, int readable, int writable); int bgp_process(uint32_t events[]);
char const *bgp_state_str(enum bgp_state state); char const *bgp_state_str(enum bgp_state state);
extern char const *cvs_id_bgp; extern char const *cvs_id_bgp;

66
cli.c
View file

@ -2,7 +2,7 @@
// vim: sw=8 ts=8 // vim: sw=8 ts=8
char const *cvs_name = "$Name: $"; char const *cvs_name = "$Name: $";
char const *cvs_id_cli = "$Id: cli.c,v 1.60 2005/06/02 11:32:30 bodea Exp $"; char const *cvs_id_cli = "$Id: cli.c,v 1.61 2005/06/04 15:42:35 bodea Exp $";
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
@ -49,15 +49,6 @@ extern struct cli_tunnel_actions *cli_tunnel_actions;
extern tbft *filter_list; extern tbft *filter_list;
extern ip_filtert *ip_filters; extern ip_filtert *ip_filters;
static char *debug_levels[] = {
"CRIT",
"ERROR",
"WARN",
"INFO",
"CALL",
"DATA",
};
struct struct
{ {
char critical; char critical;
@ -68,15 +59,24 @@ struct
char data; char data;
} debug_flags; } debug_flags;
static int debug_session; #ifdef RINGBUFFER
static int debug_tunnel;
static int debug_rb_tail; static int debug_rb_tail;
static char *debug_levels[] = {
"CRIT",
"ERROR",
"WARN",
"INFO",
"CALL",
"DATA",
};
#endif
static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc);
@ -84,7 +84,6 @@ static int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int
static int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc);
@ -102,6 +101,11 @@ static int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc)
static int regular_stuff(struct cli_def *cli); static int regular_stuff(struct cli_def *cli);
static void parsemac(char *string, char mac[6]); static void parsemac(char *string, char mac[6]);
#ifdef STATISTICS
static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc);
#endif /* STATISTICS */
#ifdef BGP #ifdef BGP
#define MODE_CONFIG_BGP 8 #define MODE_CONFIG_BGP 8
static int cmd_router_bgp(struct cli_def *cli, char *command, char **argv, int argc); static int cmd_router_bgp(struct cli_def *cli, char *command, char **argv, int argc);
@ -312,8 +316,6 @@ void cli_do(int sockfd)
cli->users = 0; cli->users = 0;
} }
debug_session = 0;
debug_tunnel = 0;
#ifdef RINGBUFFER #ifdef RINGBUFFER
debug_rb_tail = ringbuffer->tail; debug_rb_tail = ringbuffer->tail;
#endif #endif
@ -646,6 +648,7 @@ static int cmd_show_users(struct cli_def *cli, char *command, char **argv, int a
return CLI_OK; return CLI_OK;
} }
#ifdef STATISTICS
static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc) static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc)
{ {
if (CLI_HELP_REQUESTED) if (CLI_HELP_REQUESTED)
@ -697,7 +700,7 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
cli_print(cli, "%-30s%u", "multi_read_exceeded", GET_STAT(multi_read_exceeded)); cli_print(cli, "%-30s%u", "multi_read_exceeded", GET_STAT(multi_read_exceeded));
#ifdef STATISTICS #ifdef STAT_CALLS
cli_print(cli, "\n%-30s%-10s", "Counter", "Value"); cli_print(cli, "\n%-30s%-10s", "Counter", "Value");
cli_print(cli, "-----------------------------------------"); cli_print(cli, "-----------------------------------------");
cli_print(cli, "%-30s%u", "call_processtun", GET_STAT(call_processtun)); cli_print(cli, "%-30s%u", "call_processtun", GET_STAT(call_processtun));
@ -731,7 +734,7 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
cli_print(cli, "%-30s%u", "call_radiussend", GET_STAT(call_radiussend)); cli_print(cli, "%-30s%u", "call_radiussend", GET_STAT(call_radiussend));
cli_print(cli, "%-30s%u", "call_radiusretry", GET_STAT(call_radiusretry)); cli_print(cli, "%-30s%u", "call_radiusretry", GET_STAT(call_radiusretry));
cli_print(cli, "%-30s%u", "call_random_data", GET_STAT(call_random_data)); cli_print(cli, "%-30s%u", "call_random_data", GET_STAT(call_random_data));
#endif #endif /* STAT_CALLS */
{ {
time_t l = GET_STAT(last_reset); time_t l = GET_STAT(last_reset);
@ -746,6 +749,19 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
return CLI_OK; return CLI_OK;
} }
static int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc)
{
if (CLI_HELP_REQUESTED)
return CLI_HELP_NO_ARGS;
memset(_statistics, 0, sizeof(struct Tstats));
SET_STAT(last_reset, time(NULL));
cli_print(cli, "Counters cleared");
return CLI_OK;
}
#endif /* STATISTICS */
static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc) static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc)
{ {
int tag = 0; int tag = 0;
@ -1134,18 +1150,6 @@ static int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int
return CLI_OK; return CLI_OK;
} }
static int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc)
{
if (CLI_HELP_REQUESTED)
return CLI_HELP_NO_ARGS;
memset(_statistics, 0, sizeof(struct Tstats));
SET_STAT(last_reset, time(NULL));
cli_print(cli, "Counters cleared");
return CLI_OK;
}
static int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc) static int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc)
{ {
int i; int i;
@ -1896,10 +1900,10 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
int regular_stuff(struct cli_def *cli) int regular_stuff(struct cli_def *cli)
{ {
#ifdef RINGBUFFER
int out = 0; int out = 0;
int i; int i;
#ifdef RINGBUFFER
for (i = debug_rb_tail; i != ringbuffer->tail; i = (i + 1) % RINGBUFFER_SIZE) for (i = debug_rb_tail; i != ringbuffer->tail; i = (i + 1) % RINGBUFFER_SIZE)
{ {
char *m = ringbuffer->buffer[i].message; char *m = ringbuffer->buffer[i].message;

View file

@ -1,6 +1,6 @@
// L2TPNS Clustering Stuff // L2TPNS Clustering Stuff
char const *cvs_id_cluster = "$Id: cluster.c,v 1.40 2005/06/02 11:32:30 bodea Exp $"; char const *cvs_id_cluster = "$Id: cluster.c,v 1.41 2005/06/04 15:42:35 bodea Exp $";
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -38,7 +38,7 @@ char const *cvs_id_cluster = "$Id: cluster.c,v 1.40 2005/06/02 11:32:30 bodea Ex
*/ */
// Module variables. // Module variables.
int cluster_sockfd = 0; // The filedescriptor for the cluster communications port. extern int cluster_sockfd; // The filedescriptor for the cluster communications port.
in_addr_t my_address = 0; // The network address of my ethernet port. in_addr_t my_address = 0; // The network address of my ethernet port.
static int walk_session_number = 0; // The next session to send when doing the slow table walk. static int walk_session_number = 0; // The next session to send when doing the slow table walk.

179
fake_epoll.h Normal file
View file

@ -0,0 +1,179 @@
/* kludge up some limited epoll semantics using select for 2.4 kernels */
/* $Id: fake_epoll.h,v 1.1 2005/06/04 15:42:35 bodea Exp $ */
#ifndef __FAKE_EPOLL_H__
#define __FAKE_EPOLL_H__
#define EPOLLIN 0x01
#define EPOLLOUT 0x04
#define EPOLLERR 0x08
#define EPOLLHUP 0x10
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
struct epoll_event {
uint32_t events;
union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} data;
};
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
#ifdef FAKE_EPOLL_IMPLEMENTATION
#include <sys/select.h>
static fd_set _epoll_read_set;
static fd_set _epoll_write_set;
static int _epoll_fds;
static struct epoll_event *_epoll_data[128];
static int epoll_create(int size __attribute__ ((unused)))
{
static int once = 0;
if (once++)
{
errno = ENFILE; /* only support one instance */
return -1;
}
FD_ZERO(&_epoll_read_set);
FD_ZERO(&_epoll_write_set);
_epoll_fds = 0;
memset(_epoll_data, 0, sizeof(_epoll_data));
return 1; /* "descriptor" */
}
int epoll_ctl(int epfd __attribute__ ((unused)), int op, int fd,
struct epoll_event *event)
{
if (fd > (sizeof(_epoll_data)/sizeof(*_epoll_data)) - 1)
{
errno = EINVAL;
return -1;
}
switch (op)
{
case EPOLL_CTL_ADD:
if (event->events & EPOLLIN)
FD_SET(fd, &_epoll_read_set);
if (event->events & EPOLLOUT)
FD_SET(fd, &_epoll_write_set);
if (fd >= _epoll_fds)
_epoll_fds = fd + 1;
if (_epoll_data[fd])
free(_epoll_data[fd]);
if (!(_epoll_data[fd] = malloc(sizeof(*_epoll_data))))
{
errno = ENOMEM;
return -1;
}
memcpy(_epoll_data[fd], &event->data, sizeof(*_epoll_data));
break;
case EPOLL_CTL_MOD:
if (event->events & EPOLLIN)
FD_SET(fd, &_epoll_read_set);
else
FD_CLR(fd, &_epoll_read_set);
if (event->events & EPOLLOUT)
FD_SET(fd, &_epoll_write_set);
else
FD_CLR(fd, &_epoll_write_set);
memcpy(_epoll_data[fd], &event->data, sizeof(*_epoll_data));
break;
case EPOLL_CTL_DEL:
FD_CLR(fd, &_epoll_read_set);
FD_CLR(fd, &_epoll_write_set);
free(_epoll_data[fd]);
_epoll_data[fd] = 0;
if (fd == _epoll_fds - 1)
{
_epoll_fds = 0;
while (fd-- > 0)
{
if (FD_ISSET(fd, &_epoll_read_set) ||
FD_ISSET(fd, &_epoll_write_set))
{
_epoll_fds = fd + 1;
break;
}
}
}
break;
}
return 0;
}
static int epoll_wait(int epfd __attribute__ ((unused)),
struct epoll_event *events, int maxevents, int timout)
{
fd_set r;
fd_set w;
struct timeval t;
struct timeval *tp;
int n;
int e;
int i;
memcpy(&r, &_epoll_read_set, sizeof(r));
memcpy(&w, &_epoll_write_set, sizeof(w));
if (timout >= 0)
{
t.tv_sec = 0;
t.tv_usec = timout * 1000;
tp = &t;
}
else
tp = 0;
n = select(_epoll_fds, &r, &w, 0, tp);
if (n > maxevents)
n = maxevents;
for (i = e = 0; n > 0 && i < _epoll_fds; i++)
{
if (!_epoll_data[i])
continue;
events[e].events = 0;
if (FD_ISSET(i, &r))
events[e].events |= EPOLLIN;
if (FD_ISSET(i, &w))
events[e].events |= EPOLLOUT;
if (events[e].events)
{
memcpy(&events[e++].data, _epoll_data[i], sizeof(events[0].data));
n--;
}
}
return e;
}
#endif /* FAKE_EPOLL_IMPLEMENTATION */
#endif /* __FAKE_EPOLL_H__ */

245
l2tpns.c
View file

@ -4,7 +4,7 @@
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
// vim: sw=8 ts=8 // vim: sw=8 ts=8
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.107 2005/06/02 11:32:30 bodea Exp $"; char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.108 2005/06/04 15:42:35 bodea Exp $";
#include <arpa/inet.h> #include <arpa/inet.h>
#include <assert.h> #include <assert.h>
@ -52,7 +52,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.107 2005/06/02 11:32:30 bodea Exp
#ifdef BGP #ifdef BGP
#include "bgp.h" #include "bgp.h"
#endif /* BGP */ #endif
// Globals // Globals
configt *config = NULL; // all configuration configt *config = NULL; // all configuration
@ -64,13 +64,14 @@ int snoopfd = -1; // UDP file handle for sending out intercept data
int *radfds = NULL; // RADIUS requests file handles int *radfds = NULL; // RADIUS requests file handles
int ifrfd = -1; // File descriptor for routing, etc int ifrfd = -1; // File descriptor for routing, etc
int ifr6fd = -1; // File descriptor for IPv6 routing, etc int ifr6fd = -1; // File descriptor for IPv6 routing, etc
static int rand_fd = -1; // Random data source int rand_fd = -1; // Random data source
int cluster_sockfd = -1; // Intra-cluster communications socket.
int epollfd = -1; // event polling
time_t basetime = 0; // base clock time_t basetime = 0; // base clock
char hostname[1000] = ""; // us. char hostname[1000] = ""; // us.
static int tunidx; // ifr_ifindex of tun device static int tunidx; // ifr_ifindex of tun device
static int syslog_log = 0; // are we logging to syslog static int syslog_log = 0; // are we logging to syslog
static FILE *log_stream = 0; // file handle for direct logging (i.e. direct into file, not via syslog). static FILE *log_stream = 0; // file handle for direct logging (i.e. direct into file, not via syslog).
extern int cluster_sockfd; // Intra-cluster communications socket.
uint32_t last_id = 0; // Unique ID for radius accounting uint32_t last_id = 0; // Unique ID for radius accounting
struct cli_session_actions *cli_session_actions = NULL; // Pending session changes requested by CLI struct cli_session_actions *cli_session_actions = NULL; // Pending session changes requested by CLI
@ -1012,7 +1013,8 @@ static void processipout(uint8_t * buf, int len)
if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second. if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
{ {
LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0)); LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0));
host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4), ip, buf, (len < 64) ? 64 : len); host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4),
config->bind_address ? config->bind_address : my_address, buf, len);
} }
return; return;
} }
@ -2850,13 +2852,13 @@ static void regular_cleanups(double period)
static int still_busy(void) static int still_busy(void)
{ {
int i; int i;
static time_t stopped_bgp = 0;
static clockt last_talked = 0; static clockt last_talked = 0;
static clockt start_busy_wait = 0; static clockt start_busy_wait = 0;
if (!config->cluster_iam_master) if (!config->cluster_iam_master)
{ {
#ifdef BGP #ifdef BGP
static time_t stopped_bgp = 0;
if (bgp_configured) if (bgp_configured)
{ {
if (!stopped_bgp) if (!stopped_bgp)
@ -2924,41 +2926,89 @@ static int still_busy(void)
return 0; return 0;
} }
static fd_set readset; #ifdef HAVE_EPOLL
static int readset_n = 0; # include <sys/epoll.h>
#else
# define FAKE_EPOLL_IMPLEMENTATION /* include the functions */
# include "fake_epoll.h"
#endif
// the base set of fds polled: control, cli, udp, tun, cluster
#define BASE_FDS 5
// additional polled fds
#ifdef BGP
# define EXTRA_FDS BGP_NUM_PEERS
#else
# define EXTRA_FDS 0
#endif
// main loop - gets packets on tun or udp and processes them // main loop - gets packets on tun or udp and processes them
static void mainloop(void) static void mainloop(void)
{ {
int i; int i;
uint8_t buf[65536]; uint8_t buf[65536];
struct timeval to;
clockt next_cluster_ping = 0; // send initial ping immediately clockt next_cluster_ping = 0; // send initial ping immediately
struct epoll_event events[BASE_FDS + RADIUS_FDS + EXTRA_FDS];
int maxevent = sizeof(events)/sizeof(*events);
if ((epollfd = epoll_create(maxevent)) < 0)
{
LOG(0, 0, 0, "epoll_create failed: %s\n", strerror(errno));
exit(1);
}
LOG(4, 0, 0, "Beginning of main loop. udpfd=%d, tunfd=%d, cluster_sockfd=%d, controlfd=%d\n", LOG(4, 0, 0, "Beginning of main loop. udpfd=%d, tunfd=%d, cluster_sockfd=%d, controlfd=%d\n",
udpfd, tunfd, cluster_sockfd, controlfd); udpfd, tunfd, cluster_sockfd, controlfd);
FD_ZERO(&readset); /* setup our fds to poll for input */
FD_SET(udpfd, &readset); {
FD_SET(tunfd, &readset); static struct event_data d[BASE_FDS];
FD_SET(controlfd, &readset); struct epoll_event e;
FD_SET(clifd, &readset);
if (cluster_sockfd) FD_SET(cluster_sockfd, &readset); e.events = EPOLLIN;
readset_n = udpfd; i = 0;
if (tunfd > readset_n) readset_n = tunfd;
if (controlfd > readset_n) readset_n = controlfd; d[i].type = FD_TYPE_CONTROL;
if (clifd > readset_n) readset_n = clifd; e.data.ptr = &d[i++];
if (cluster_sockfd > readset_n) readset_n = cluster_sockfd; epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e);
d[i].type = FD_TYPE_CLI;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &e);
d[i].type = FD_TYPE_UDP;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e);
d[i].type = FD_TYPE_TUN;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, tunfd, &e);
d[i].type = FD_TYPE_CLUSTER;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, cluster_sockfd, &e);
}
#ifdef BGP
signal(SIGPIPE, SIG_IGN);
bgp_setup(config->as_number);
if (config->bind_address)
bgp_add_route(config->bind_address, 0xffffffff);
for (i = 0; i < BGP_NUM_PEERS; i++)
{
if (config->neighbour[i].name[0])
bgp_start(&bgp_peers[i], config->neighbour[i].name,
config->neighbour[i].as, config->neighbour[i].keepalive,
config->neighbour[i].hold, 0); /* 0 = routing disabled */
}
#endif /* BGP */
while (!main_quit || still_busy()) while (!main_quit || still_busy())
{ {
fd_set r;
int n = readset_n;
#ifdef BGP
fd_set w;
int bgp_set[BGP_NUM_PEERS];
#endif /* BGP */
int more = 0; int more = 0;
int n;
if (config->reload_config) if (config->reload_config)
{ {
@ -2966,35 +3016,11 @@ static void mainloop(void)
update_config(); update_config();
} }
memcpy(&r, &readset, sizeof(fd_set));
to.tv_sec = 0;
to.tv_usec = 100000; // 1/10th of a second.
#ifdef BGP #ifdef BGP
FD_ZERO(&w); bgp_set_poll();
for (i = 0; i < BGP_NUM_PEERS; i++)
{
bgp_set[i] = bgp_select_state(&bgp_peers[i]);
if (bgp_set[i] & 1)
{
FD_SET(bgp_peers[i].sock, &r);
if (bgp_peers[i].sock > n)
n = bgp_peers[i].sock;
}
if (bgp_set[i] & 2)
{
FD_SET(bgp_peers[i].sock, &w);
if (bgp_peers[i].sock > n)
n = bgp_peers[i].sock;
}
}
n = select(n + 1, &r, &w, 0, &to);
#else /* BGP */
n = select(n + 1, &r, 0, 0, &to);
#endif /* BGP */ #endif /* BGP */
n = epoll_wait(epollfd, events, maxevent, 100); // timeout 100ms (1/10th sec)
STAT(select_called); STAT(select_called);
TIME = now(NULL); TIME = now(NULL);
@ -3008,37 +3034,34 @@ static void mainloop(void)
main_quit++; main_quit++;
break; break;
} }
else if (n)
if (n)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int alen, c, s; int alen, c, s;
int udp_ready = 0;
int tun_ready = 0;
int cluster_ready = 0;
int udp_pkts = 0; int udp_pkts = 0;
int tun_pkts = 0; int tun_pkts = 0;
int cluster_pkts = 0; int cluster_pkts = 0;
#ifdef BGP
uint32_t bgp_events[BGP_NUM_PEERS];
memset(bgp_events, 0, sizeof(bgp_events));
#endif /* BGP */
// nsctl commands for (c = n, i = 0; i < c; i++)
if (FD_ISSET(controlfd, &r))
{ {
struct event_data *d = events[i].data.ptr;
switch (d->type)
{
case FD_TYPE_CONTROL: // nsctl commands
alen = sizeof(addr); alen = sizeof(addr);
processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen); processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
n--; n--;
} break;
// RADIUS responses case FD_TYPE_CLI: // CLI connections
if (config->cluster_iam_master)
{
for (i = 0; i < config->num_radfds; i++)
{
if (FD_ISSET(radfds[i], &r))
{
processrad(buf, recv(radfds[i], buf, sizeof(buf), 0), i);
n--;
}
}
}
// CLI connections
if (FD_ISSET(clifd, &r))
{ {
int cli; int cli;
@ -3052,23 +3075,42 @@ static void mainloop(void)
LOG(0, 0, 0, "accept error: %s\n", strerror(errno)); LOG(0, 0, 0, "accept error: %s\n", strerror(errno));
n--; n--;
break;
}
// these are handled below, with multiple interleaved reads
case FD_TYPE_UDP: udp_ready++; break;
case FD_TYPE_TUN: tun_ready++; break;
case FD_TYPE_CLUSTER: cluster_ready++; break;
case FD_TYPE_RADIUS: // RADIUS response
s = recv(radfds[d->index], buf, sizeof(buf), 0);
if (s >= 0 && config->cluster_iam_master)
processrad(buf, s, d->index);
n--;
break;
#ifdef BGP
case FD_TYPE_BGP:
bgp_events[d->index] = events[i].events;
n--;
break;
#endif /* BGP */
default:
LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type);
}
} }
#ifdef BGP #ifdef BGP
for (i = 0; i < BGP_NUM_PEERS; i++) bgp_process(bgp_events);
{
int isr = bgp_set[i] ? FD_ISSET(bgp_peers[i].sock, &r) : 0;
int isw = bgp_set[i] ? FD_ISSET(bgp_peers[i].sock, &w) : 0;
bgp_process(&bgp_peers[i], isr, isw);
if (isr) n--;
if (isw) n--;
}
#endif /* BGP */ #endif /* BGP */
for (c = 0; n && c < config->multi_read_count; c++) for (c = 0; n && c < config->multi_read_count; c++)
{ {
// L2TP // L2TP
if (FD_ISSET(udpfd, &r)) if (udp_ready)
{ {
alen = sizeof(addr); alen = sizeof(addr);
if ((s = recvfrom(udpfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0) if ((s = recvfrom(udpfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0)
@ -3078,13 +3120,13 @@ static void mainloop(void)
} }
else else
{ {
FD_CLR(udpfd, &r); udp_ready = 0;
n--; n--;
} }
} }
// incoming IP // incoming IP
if (FD_ISSET(tunfd, &r)) if (tun_ready)
{ {
if ((s = read(tunfd, buf, sizeof(buf))) > 0) if ((s = read(tunfd, buf, sizeof(buf))) > 0)
{ {
@ -3093,13 +3135,13 @@ static void mainloop(void)
} }
else else
{ {
FD_CLR(tunfd, &r); tun_ready = 0;
n--; n--;
} }
} }
// cluster // cluster
if (FD_ISSET(cluster_sockfd, &r)) if (cluster_ready)
{ {
alen = sizeof(addr); alen = sizeof(addr);
if ((s = recvfrom(cluster_sockfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen)) > 0) if ((s = recvfrom(cluster_sockfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen)) > 0)
@ -3109,7 +3151,7 @@ static void mainloop(void)
} }
else else
{ {
FD_CLR(cluster_sockfd, &r); cluster_ready = 0;
n--; n--;
} }
} }
@ -3129,7 +3171,7 @@ static void mainloop(void)
} }
// Runs on every machine (master and slaves). // Runs on every machine (master and slaves).
if (cluster_sockfd && next_cluster_ping <= TIME) if (next_cluster_ping <= TIME)
{ {
// Check to see which of the cluster is still alive.. // Check to see which of the cluster is still alive..
@ -3707,10 +3749,12 @@ static int dump_session(FILE **f, sessiont *s)
LOG(3, 0, 0, "Dumping accounting information to %s\n", filename); LOG(3, 0, 0, "Dumping accounting information to %s\n", filename);
fprintf(*f, "# dslwatch.pl dump file V1.01\n" fprintf(*f, "# dslwatch.pl dump file V1.01\n"
"# host: %s\n" "# host: %s\n"
"# endpoint: %s\n"
"# time: %ld\n" "# time: %ld\n"
"# uptime: %ld\n" "# uptime: %ld\n"
"# format: username ip qos uptxoctets downrxoctets\n", "# format: username ip qos uptxoctets downrxoctets\n",
hostname, hostname,
fmtaddr(config->bind_address ? config->bind_address : my_address, 0),
now, now,
now - basetime); now - basetime);
} }
@ -3851,19 +3895,6 @@ int main(int argc, char *argv[])
if (cluster_init() < 0) if (cluster_init() < 0)
exit(1); exit(1);
#ifdef BGP
signal(SIGPIPE, SIG_IGN);
bgp_setup(config->as_number);
bgp_add_route(config->bind_address, 0xffffffff);
for (i = 0; i < BGP_NUM_PEERS; i++)
{
if (config->neighbour[i].name[0])
bgp_start(&bgp_peers[i], config->neighbour[i].name,
config->neighbour[i].as, config->neighbour[i].keepalive,
config->neighbour[i].hold, 0); /* 0 = routing disabled */
}
#endif /* BGP */
inittun(); inittun();
LOG(1, 0, 0, "Set up on interface %s\n", config->tundevice); LOG(1, 0, 0, "Set up on interface %s\n", config->tundevice);
@ -4094,8 +4125,6 @@ static void update_config()
if (!config->numradiusservers) if (!config->numradiusservers)
LOG(0, 0, 0, "No RADIUS servers defined!\n"); LOG(0, 0, 0, "No RADIUS servers defined!\n");
config->num_radfds = 1 << RADIUS_SHIFT;
// parse radius_authtypes_s // parse radius_authtypes_s
config->radius_authtypes = config->radius_authprefer = 0; config->radius_authtypes = config->radius_authprefer = 0;
p = config->radius_authtypes_s; p = config->radius_authtypes_s;
@ -4853,6 +4882,9 @@ static tunnelidt new_tunnel()
void become_master(void) void become_master(void)
{ {
int s, i; int s, i;
static struct event_data d[RADIUS_FDS];
struct epoll_event e;
run_plugins(PLUGIN_BECOME_MASTER, NULL); run_plugins(PLUGIN_BECOME_MASTER, NULL);
// running a bunch of iptables commands is slow and can cause // running a bunch of iptables commands is slow and can cause
@ -4871,11 +4903,14 @@ void become_master(void)
} }
// add radius fds // add radius fds
for (i = 0; i < config->num_radfds; i++) e.events = EPOLLIN;
for (i = 0; i < RADIUS_FDS; i++)
{ {
FD_SET(radfds[i], &readset); d[i].type = FD_TYPE_RADIUS;
if (radfds[i] > readset_n) d[i].index = i;
readset_n = radfds[i]; e.data.ptr = &d[i];
epoll_ctl(epollfd, EPOLL_CTL_ADD, radfds[i], &e);
} }
} }

View file

@ -1,5 +1,5 @@
// L2TPNS Global Stuff // L2TPNS Global Stuff
// $Id: l2tpns.h,v 1.75 2005/06/02 11:32:31 bodea Exp $ // $Id: l2tpns.h,v 1.76 2005/06/04 15:42:36 bodea Exp $
#ifndef __L2TPNS_H__ #ifndef __L2TPNS_H__
#define __L2TPNS_H__ #define __L2TPNS_H__
@ -23,6 +23,7 @@
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session. #define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
#define RADIUS_SHIFT 6 #define RADIUS_SHIFT 6
#define RADIUS_FDS (1 << RADIUS_SHIFT)
#define RADIUS_MASK ((1 << RADIUS_SHIFT) - 1) #define RADIUS_MASK ((1 << RADIUS_SHIFT) - 1)
#define MAXRADIUS (1 << (8 + RADIUS_SHIFT)) #define MAXRADIUS (1 << (8 + RADIUS_SHIFT))
@ -455,7 +456,6 @@ typedef struct
in_addr_t radiusserver[MAXRADSERVER]; // radius servers in_addr_t radiusserver[MAXRADSERVER]; // radius servers
uint16_t radiusport[MAXRADSERVER]; // radius base ports uint16_t radiusport[MAXRADSERVER]; // radius base ports
uint8_t numradiusservers; // radius server count uint8_t numradiusservers; // radius server count
short num_radfds; // Number of radius filehandles allocated
char radius_authtypes_s[32]; // list of valid authentication types (chap, pap) in order of preference char radius_authtypes_s[32]; // list of valid authentication types (chap, pap) in order of preference
int radius_authtypes; int radius_authtypes;
@ -692,7 +692,20 @@ extern struct Tstats *_statistics;
extern in_addr_t my_address; extern in_addr_t my_address;
extern int tun_write(uint8_t *data, int size); extern int tun_write(uint8_t *data, int size);
extern int clifd; extern int clifd;
extern int epollfd;
struct event_data {
enum {
FD_TYPE_CONTROL,
FD_TYPE_CLI,
FD_TYPE_UDP,
FD_TYPE_TUN,
FD_TYPE_CLUSTER,
FD_TYPE_RADIUS,
FD_TYPE_BGP,
} type;
int index; // for RADIUS, BGP
};
#define TIME (config->current_time) #define TIME (config->current_time)

View file

@ -43,5 +43,5 @@ rm -rf %{buildroot}
%attr(644,root,root) /usr/share/man/man[58]/* %attr(644,root,root) /usr/share/man/man[58]/*
%changelog %changelog
* Thu Jun 2 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0-1 * Sun Jun 5 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0-1
- 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes - 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes

View file

@ -1,6 +1,6 @@
// L2TPNS Radius Stuff // L2TPNS Radius Stuff
char const *cvs_id_radius = "$Id: radius.c,v 1.32 2005/06/02 11:32:32 bodea Exp $"; char const *cvs_id_radius = "$Id: radius.c,v 1.33 2005/06/04 15:42:36 bodea Exp $";
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
@ -29,9 +29,9 @@ extern ip_filtert *ip_filters;
void initrad(void) void initrad(void)
{ {
int i; int i;
LOG(3, 0, 0, "Creating %d sockets for RADIUS queries\n", config->num_radfds); LOG(3, 0, 0, "Creating %d sockets for RADIUS queries\n", RADIUS_FDS);
radfds = calloc(sizeof(int), config->num_radfds); radfds = calloc(sizeof(int), RADIUS_FDS);
for (i = 0; i < config->num_radfds; i++) for (i = 0; i < RADIUS_FDS; i++)
{ {
int flags; int flags;
radfds[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); radfds[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

8
util.c
View file

@ -1,6 +1,6 @@
/* Misc util functions */ /* Misc util functions */
char const *cvs_id_util = "$Id: util.c,v 1.10 2005/01/25 04:19:07 bodea Exp $"; char const *cvs_id_util = "$Id: util.c,v 1.11 2005/06/04 15:42:36 bodea Exp $";
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
@ -40,7 +40,7 @@ void *shared_malloc(unsigned int size)
} }
extern int forked; extern int forked;
extern int udpfd, controlfd, tunfd, snoopfd, ifrfd, ifr6fd, cluster_sockfd; extern int udpfd, controlfd, tunfd, snoopfd, ifrfd, ifr6fd, rand_fd, cluster_sockfd;
extern int *radfds; extern int *radfds;
pid_t fork_and_close() pid_t fork_and_close()
@ -79,10 +79,12 @@ pid_t fork_and_close()
if (snoopfd != -1) close(snoopfd); if (snoopfd != -1) close(snoopfd);
if (ifrfd != -1) close(ifrfd); if (ifrfd != -1) close(ifrfd);
if (ifr6fd != -1) close(ifr6fd); if (ifr6fd != -1) close(ifr6fd);
if (rand_fd != -1) close(rand_fd);
if (cluster_sockfd != -1) close(cluster_sockfd); if (cluster_sockfd != -1) close(cluster_sockfd);
if (clifd != -1) close(clifd); if (clifd != -1) close(clifd);
if (epollfd != -1) close(epollfd);
for (i = 0; radfds && i < config->num_radfds; i++) for (i = 0; radfds && i < RADIUS_FDS; i++)
close(radfds[i]); close(radfds[i]);
#ifdef BGP #ifdef BGP
for (i = 0; i < BGP_NUM_PEERS; i++) for (i = 0; i < BGP_NUM_PEERS; i++)