summaryrefslogtreecommitdiff
path: root/accel-pppd/radius
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2011-09-05 15:28:02 +0400
committerKozlov Dmitry <xeb@mail.ru>2011-09-05 15:28:02 +0400
commit3e6a720a2cbd08edb6d04255b2246a833df6825c (patch)
treef273c6d460f98f83ffca94e44ac3d7b57ebb7445 /accel-pppd/radius
parent9739251101bffde2c62ba08c1869eb170d952d5b (diff)
downloadaccel-ppp-xebd-3e6a720a2cbd08edb6d04255b2246a833df6825c.tar.gz
accel-ppp-xebd-3e6a720a2cbd08edb6d04255b2246a833df6825c.zip
radius: per-server statistics
Diffstat (limited to 'accel-pppd/radius')
-rw-r--r--accel-pppd/radius/acct.c51
-rw-r--r--accel-pppd/radius/auth.c12
-rw-r--r--accel-pppd/radius/radius.c64
-rw-r--r--accel-pppd/radius/radius_p.h46
-rw-r--r--accel-pppd/radius/serv.c108
-rw-r--r--accel-pppd/radius/stat_accm.c13
6 files changed, 170 insertions, 124 deletions
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index bcc0a12..6f94861 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -103,8 +103,9 @@ static int rad_acct_read(struct triton_md_handler_t *h)
dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 +
(req->reply->tv.tv_usec - req->pack->tv.tv_usec) / 1000;
- stat_accm_add(stat_interim_query_1m, dt);
- stat_accm_add(stat_interim_query_5m, dt);
+
+ stat_accm_add(req->serv->stat_interim_query_1m, dt);
+ stat_accm_add(req->serv->stat_interim_query_5m, dt);
if (req->reply->code != CODE_ACCOUNTING_RESPONSE || req->reply->id != req->pack->id) {
rad_packet_free(req->reply);
@@ -148,9 +149,9 @@ static void rad_acct_timeout(struct triton_timer_t *t)
struct rad_req_t *req = container_of(t, typeof(*req), timeout);
time_t ts, dt;
- __sync_add_and_fetch(&stat_interim_lost, 1);
- stat_accm_add(stat_interim_lost_1m, 1);
- stat_accm_add(stat_interim_lost_5m, 1);
+ __sync_add_and_fetch(&req->serv->stat_interim_lost, 1);
+ stat_accm_add(req->serv->stat_interim_lost_1m, 1);
+ stat_accm_add(req->serv->stat_interim_lost_5m, 1);
if (conf_acct_timeout == 0) {
rad_server_timeout(req->serv);
@@ -189,7 +190,7 @@ static void rad_acct_timeout(struct triton_timer_t *t)
__rad_req_send(req);
- __sync_add_and_fetch(&stat_interim_sent, 1);
+ __sync_add_and_fetch(&req->serv->stat_interim_sent, 1);
}
static void rad_acct_interim_update(struct triton_timer_t *t)
@@ -217,7 +218,7 @@ static void rad_acct_interim_update(struct triton_timer_t *t)
__rad_req_send(rpd->acct_req);
- __sync_add_and_fetch(&stat_interim_sent, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_interim_sent, 1);
triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_req->timeout, 0);
}
@@ -278,31 +279,31 @@ int rad_acct_start(struct radius_pd_t *rpd)
if (rad_req_send(rpd->acct_req, conf_verbose))
goto out_err;
- __sync_add_and_fetch(&stat_acct_sent, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
rad_req_wait(rpd->acct_req, conf_timeout);
if (!rpd->acct_req->reply) {
if (conf_acct_delay_time)
rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
continue;
}
dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
(rpd->acct_req->reply->tv.tv_usec - rpd->acct_req->pack->tv.tv_usec) / 1000;
- stat_accm_add(stat_acct_query_1m, dt);
- stat_accm_add(stat_acct_query_5m, dt);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
rad_packet_free(rpd->acct_req->reply);
rpd->acct_req->reply = NULL;
rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
} else
break;
}
@@ -422,26 +423,26 @@ void rad_acct_stop(struct radius_pd_t *rpd)
}
if (rad_req_send(rpd->acct_req, conf_verbose))
break;
- __sync_add_and_fetch(&stat_acct_sent, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
rad_req_wait(rpd->acct_req, conf_timeout);
if (!rpd->acct_req->reply) {
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
continue;
}
dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
(rpd->acct_req->reply->tv.tv_usec - rpd->acct_req->pack->tv.tv_usec) / 1000;
- stat_accm_add(stat_acct_query_1m, dt);
- stat_accm_add(stat_acct_query_5m, dt);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
rad_packet_free(rpd->acct_req->reply);
rpd->acct_req->reply = NULL;
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
} else
break;
}
diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c
index 089f67b..c9f6655 100644
--- a/accel-pppd/radius/auth.c
+++ b/accel-pppd/radius/auth.c
@@ -159,7 +159,7 @@ static int rad_auth_send(struct rad_req_t *req)
}
for(i = 0; i < conf_max_try; i++) {
- __sync_add_and_fetch(&stat_auth_sent, 1);
+ __sync_add_and_fetch(&req->serv->stat_auth_sent, 1);
gettimeofday(&tv, NULL);
if (rad_req_send(req, conf_verbose))
goto out;
@@ -184,13 +184,13 @@ static int rad_auth_send(struct rad_req_t *req)
if (req->reply) {
dt = (req->reply->tv.tv_sec - tv.tv_sec) * 1000 + (req->reply->tv.tv_usec - tv.tv_usec) / 1000;
- stat_accm_add(stat_auth_query_1m, dt);
- stat_accm_add(stat_auth_query_5m, dt);
+ stat_accm_add(req->serv->stat_auth_query_1m, dt);
+ stat_accm_add(req->serv->stat_auth_query_5m, dt);
break;
} else {
- __sync_add_and_fetch(&stat_auth_lost, 1);
- stat_accm_add(stat_auth_lost_1m, 1);
- stat_accm_add(stat_auth_lost_5m, 1);
+ __sync_add_and_fetch(&req->serv->stat_auth_lost, 1);
+ stat_accm_add(req->serv->stat_auth_lost_1m, 1);
+ stat_accm_add(req->serv->stat_auth_lost_5m, 1);
}
}
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index 3beeb9f..15e5e68 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -12,7 +12,6 @@
#include "pwdb.h"
#include "ipdb.h"
#include "ppp_auth.h"
-#include "cli.h"
#include "radius_p.h"
#include "attr_defs.h"
@@ -45,28 +44,6 @@ int conf_acct_interim_interval;
int conf_accounting;
int conf_fail_time;
-unsigned long stat_auth_sent;
-unsigned long stat_auth_lost;
-unsigned long stat_acct_sent;
-unsigned long stat_acct_lost;
-unsigned long stat_interim_sent;
-unsigned long stat_interim_lost;
-
-struct stat_accm_t *stat_auth_lost_1m;
-struct stat_accm_t *stat_auth_lost_5m;
-struct stat_accm_t *stat_auth_query_1m;
-struct stat_accm_t *stat_auth_query_5m;
-
-struct stat_accm_t *stat_acct_lost_1m;
-struct stat_accm_t *stat_acct_lost_5m;
-struct stat_accm_t *stat_acct_query_1m;
-struct stat_accm_t *stat_acct_query_5m;
-
-struct stat_accm_t *stat_interim_lost_1m;
-struct stat_accm_t *stat_interim_lost_5m;
-struct stat_accm_t *stat_interim_query_1m;
-struct stat_accm_t *stat_interim_query_5m;
-
static LIST_HEAD(sessions);
static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER;
@@ -426,30 +403,6 @@ int rad_check_nas_pack(struct rad_packet_t *pack)
return 0;
}
-static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
-{
- cli_send(client, "radius:\r\n");
- cli_sendv(client, " auth sent: %lu\r\n", stat_auth_sent);
- cli_sendv(client, " auth lost(total/5m/1m): %lu/%lu/%lu\r\n",
- stat_auth_lost, stat_accm_get_cnt(stat_auth_lost_5m), stat_accm_get_cnt(stat_auth_lost_1m));
- cli_sendv(client, " auth avg query time(5m/1m): %lu/%lu ms\r\n",
- stat_accm_get_avg(stat_auth_query_5m), stat_accm_get_avg(stat_auth_query_1m));
-
- cli_sendv(client, " acct sent: %lu\r\n", stat_acct_sent);
- cli_sendv(client, " acct lost(total/5m/1m): %lu/%lu/%lu\r\n",
- stat_acct_lost, stat_accm_get_cnt(stat_acct_lost_5m), stat_accm_get_cnt(stat_acct_lost_1m));
- cli_sendv(client, " acct avg query time(5m/1m): %lu/%lu ms\r\n",
- stat_accm_get_avg(stat_acct_query_5m), stat_accm_get_avg(stat_acct_query_1m));
-
- cli_sendv(client, " interim sent: %lu\r\n", stat_interim_sent);
- cli_sendv(client, " interim lost(total/5m/1m): %lu/%lu/%lu\r\n",
- stat_interim_lost, stat_accm_get_cnt(stat_interim_lost_5m), stat_accm_get_cnt(stat_interim_lost_1m));
- cli_sendv(client, " interim avg query time(5m/1m): %lu/%lu ms\r\n",
- stat_accm_get_avg(stat_interim_query_5m), stat_accm_get_avg(stat_interim_query_1m));
-
- return CLI_CMD_OK;
-}
-
void __export rad_register_plugin(struct ppp_t *ppp, struct rad_plugin_t *plugin)
{
struct radius_pd_t *rpd = find_pd(ppp);
@@ -604,23 +557,6 @@ static void radius_init(void)
triton_event_register_handler(EV_PPP_FINISHING, (triton_event_func)ppp_finishing);
triton_event_register_handler(EV_PPP_FINISHED, (triton_event_func)ppp_finished);
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
-
- cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat");
-
- stat_auth_lost_1m = stat_accm_create(60);
- stat_auth_lost_5m = stat_accm_create(5 * 60);
- stat_auth_query_1m = stat_accm_create(60);
- stat_auth_query_5m = stat_accm_create(5 * 60);
-
- stat_acct_lost_1m = stat_accm_create(60);
- stat_acct_lost_5m = stat_accm_create(5 * 60);
- stat_acct_query_1m = stat_accm_create(60);
- stat_acct_query_5m = stat_accm_create(5 * 60);
-
- stat_interim_lost_1m = stat_accm_create(60);
- stat_interim_lost_5m = stat_accm_create(5 * 60);
- stat_interim_query_1m = stat_accm_create(60);
- stat_interim_query_5m = stat_accm_create(5 * 60);
}
DEFINE_INIT(51, radius_init);
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index 2e76c3f..e038aa8 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -84,6 +84,30 @@ struct rad_server_t
int conf_fail_time;
int timeout_cnt;
pthread_mutex_t lock;
+
+ unsigned long stat_auth_sent;
+ unsigned long stat_auth_lost;
+ unsigned long stat_acct_sent;
+ unsigned long stat_acct_lost;
+ unsigned long stat_interim_sent;
+ unsigned long stat_interim_lost;
+ unsigned long stat_fail_cnt;
+
+ struct stat_accm_t *stat_auth_lost_1m;
+ struct stat_accm_t *stat_auth_lost_5m;
+ struct stat_accm_t *stat_auth_query_1m;
+ struct stat_accm_t *stat_auth_query_5m;
+
+ struct stat_accm_t *stat_acct_lost_1m;
+ struct stat_accm_t *stat_acct_lost_5m;
+ struct stat_accm_t *stat_acct_query_1m;
+ struct stat_accm_t *stat_acct_query_5m;
+
+ struct stat_accm_t *stat_interim_lost_1m;
+ struct stat_accm_t *stat_interim_lost_5m;
+ struct stat_accm_t *stat_interim_query_1m;
+ struct stat_accm_t *stat_interim_query_5m;
+
int need_free:1;
};
@@ -110,13 +134,6 @@ extern int conf_acct_interim_interval;
extern int conf_accounting;
extern int conf_fail_time;
-extern unsigned long stat_auth_sent;
-extern unsigned long stat_auth_lost;
-extern unsigned long stat_acct_sent;
-extern unsigned long stat_acct_lost;
-extern unsigned long stat_interim_sent;
-extern unsigned long stat_interim_lost;
-
int rad_check_nas_pack(struct rad_packet_t *pack);
struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr, const char *csid);
struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack);
@@ -161,23 +178,10 @@ void rad_server_reply(struct rad_server_t *);
struct stat_accm_t;
struct stat_accm_t *stat_accm_create(unsigned int time);
+void stat_accm_free(struct stat_accm_t *);
void stat_accm_add(struct stat_accm_t *, unsigned int);
unsigned long stat_accm_get_cnt(struct stat_accm_t *);
unsigned long stat_accm_get_avg(struct stat_accm_t *);
-extern struct stat_accm_t *stat_auth_lost_1m;
-extern struct stat_accm_t *stat_auth_lost_5m;
-extern struct stat_accm_t *stat_auth_query_1m;
-extern struct stat_accm_t *stat_auth_query_5m;
-
-extern struct stat_accm_t *stat_acct_lost_1m;
-extern struct stat_accm_t *stat_acct_lost_5m;
-extern struct stat_accm_t *stat_acct_query_1m;
-extern struct stat_accm_t *stat_acct_query_5m;
-
-extern struct stat_accm_t *stat_interim_lost_1m;
-extern struct stat_accm_t *stat_interim_lost_5m;
-extern struct stat_accm_t *stat_interim_query_1m;
-extern struct stat_accm_t *stat_interim_query_5m;
#endif
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
index 733c975..6c28324 100644
--- a/accel-pppd/radius/serv.c
+++ b/accel-pppd/radius/serv.c
@@ -13,6 +13,8 @@
#include "log.h"
#include "triton.h"
#include "events.h"
+#include "cli.h"
+#include "utils.h"
#include "radius_p.h"
#include "memdebug.h"
@@ -20,6 +22,8 @@
static int num;
static LIST_HEAD(serv_list);
+static void __free_server(struct rad_server_t *);
+
static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *exclude)
{
struct rad_server_t *s, *s0 = NULL;
@@ -65,10 +69,8 @@ void rad_server_put(struct rad_server_t *s, int type)
{
__sync_sub_and_fetch(&s->client_cnt[type], 1);
- if (s->need_free && !s->client_cnt[0] && !s->client_cnt[1]) {
- log_debug("radius: free(%i)\n", s->id);
- _free(s);
- }
+ if (s->need_free && !s->client_cnt[0] && !s->client_cnt[1])
+ __free_server(s);
}
int rad_server_req_enter(struct rad_req_t *req)
@@ -199,6 +201,59 @@ void rad_server_reply(struct rad_server_t *s)
s->timeout_cnt = 0;
}
+
+static void show_stat(struct rad_server_t *s, void *client)
+{
+ char addr[17];
+ struct timespec ts;
+
+ u_inet_ntoa(s->auth_addr ? s->auth_addr : s->acct_addr, addr);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ cli_sendv(client, "radius(%i, %s):\r\n", s->id, addr);
+
+ if (s->conf_fail_time > 1) {
+ if (ts.tv_sec < s->fail_time)
+ cli_send(client, " state: failed\r\n");
+ else
+ cli_send(client, " state: active\r\n");
+
+ cli_sendv(client, " fail count: %lu\r\n", s->stat_fail_cnt);
+ }
+
+ if (s->auth_addr) {
+ cli_sendv(client, " auth sent: %lu\r\n", s->stat_auth_sent);
+ cli_sendv(client, " auth lost(total/5m/1m): %lu/%lu/%lu\r\n",
+ s->stat_auth_lost, stat_accm_get_cnt(s->stat_auth_lost_5m), stat_accm_get_cnt(s->stat_auth_lost_1m));
+ cli_sendv(client, " auth avg query time(5m/1m): %lu/%lu ms\r\n",
+ stat_accm_get_avg(s->stat_auth_query_5m), stat_accm_get_avg(s->stat_auth_query_1m));
+ }
+
+ if (s->acct_addr) {
+ cli_sendv(client, " acct sent: %lu\r\n", s->stat_acct_sent);
+ cli_sendv(client, " acct lost(total/5m/1m): %lu/%lu/%lu\r\n",
+ s->stat_acct_lost, stat_accm_get_cnt(s->stat_acct_lost_5m), stat_accm_get_cnt(s->stat_acct_lost_1m));
+ cli_sendv(client, " acct avg query time(5m/1m): %lu/%lu ms\r\n",
+ stat_accm_get_avg(s->stat_acct_query_5m), stat_accm_get_avg(s->stat_acct_query_1m));
+
+ cli_sendv(client, " interim sent: %lu\r\n", s->stat_interim_sent);
+ cli_sendv(client, " interim lost(total/5m/1m): %lu/%lu/%lu\r\n",
+ s->stat_interim_lost, stat_accm_get_cnt(s->stat_interim_lost_5m), stat_accm_get_cnt(s->stat_interim_lost_1m));
+ cli_sendv(client, " interim avg query time(5m/1m): %lu/%lu ms\r\n",
+ stat_accm_get_avg(s->stat_interim_query_5m), stat_accm_get_avg(s->stat_interim_query_1m));
+ }
+}
+
+static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
+{
+ struct rad_server_t *s;
+
+ list_for_each_entry(s, &serv_list, entry)
+ show_stat(s, client);
+
+ return CLI_CMD_OK;
+}
+
static void __add_server(struct rad_server_t *s)
{
struct rad_server_t *s1;
@@ -217,6 +272,43 @@ static void __add_server(struct rad_server_t *s)
pthread_mutex_init(&s->lock, NULL);
s->conf_fail_time = conf_fail_time;
list_add_tail(&s->entry, &serv_list);
+
+ s->stat_auth_lost_1m = stat_accm_create(60);
+ s->stat_auth_lost_5m = stat_accm_create(5 * 60);
+ s->stat_auth_query_1m = stat_accm_create(60);
+ s->stat_auth_query_5m = stat_accm_create(5 * 60);
+
+ s->stat_acct_lost_1m = stat_accm_create(60);
+ s->stat_acct_lost_5m = stat_accm_create(5 * 60);
+ s->stat_acct_query_1m = stat_accm_create(60);
+ s->stat_acct_query_5m = stat_accm_create(5 * 60);
+
+ s->stat_interim_lost_1m = stat_accm_create(60);
+ s->stat_interim_lost_5m = stat_accm_create(5 * 60);
+ s->stat_interim_query_1m = stat_accm_create(60);
+ s->stat_interim_query_5m = stat_accm_create(5 * 60);
+}
+
+static void __free_server(struct rad_server_t *s)
+{
+ log_debug("radius: free(%i)\n", s->id);
+
+ stat_accm_free(s->stat_auth_lost_1m);
+ stat_accm_free(s->stat_auth_lost_5m);
+ stat_accm_free(s->stat_auth_query_1m);
+ stat_accm_free(s->stat_auth_query_5m);
+
+ stat_accm_free(s->stat_acct_lost_1m);
+ stat_accm_free(s->stat_acct_lost_5m);
+ stat_accm_free(s->stat_acct_query_1m);
+ stat_accm_free(s->stat_acct_query_5m);
+
+ stat_accm_free(s->stat_interim_lost_1m);
+ stat_accm_free(s->stat_interim_lost_5m);
+ stat_accm_free(s->stat_interim_query_1m);
+ stat_accm_free(s->stat_interim_query_5m);
+
+ _free(s);
}
static int parse_server_old(const char *opt, in_addr_t *addr, int *port, char **secret)
@@ -394,10 +486,8 @@ static void load_config(void)
triton_context_wakeup(r->rpd->ppp->ctrl->ctx);
}
- if (!s->client_cnt[0] && !s->client_cnt[1]) {
- log_debug("radius: free(%i)\n", s->id);
- _free(s);
- }
+ if (!s->client_cnt[0] && !s->client_cnt[1])
+ __free_server(s);
}
}
}
@@ -409,6 +499,8 @@ static void init(void)
load_config();
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+
+ cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat");
}
DEFINE_INIT(52, init);
diff --git a/accel-pppd/radius/stat_accm.c b/accel-pppd/radius/stat_accm.c
index 34935a1..2388c5d 100644
--- a/accel-pppd/radius/stat_accm.c
+++ b/accel-pppd/radius/stat_accm.c
@@ -35,6 +35,19 @@ struct stat_accm_t *stat_accm_create(unsigned int time)
return s;
}
+void stat_accm_free(struct stat_accm_t *s)
+{
+ struct item_t *it;
+
+ while (!list_empty(&s->items)) {
+ it = list_entry(s->items.next, typeof(*it), entry);
+ list_del(&it->entry);
+ mempool_free(it);
+ }
+
+ _free(s);
+}
+
static void stat_accm_clean(struct stat_accm_t *s)
{
struct item_t *it;