statistics: Introduce 'struct counter' instead of using unsigned long

This has the advantage that counters can be added all over the code
very easily, while having only one routine that stores all of the
current counter values to the database.  The counters are synced
every 60 seconds, providing relatively fine grained statistics
about the network usage as time passes by.
This commit is contained in:
Harald Welte 2009-12-22 19:07:32 +01:00
parent 4983921af1
commit ffa55a4e87
15 changed files with 255 additions and 66 deletions

View File

@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \
silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \
system_information.h handover.h system_information.h handover.h statistics.h

View File

@ -53,4 +53,8 @@ int db_sms_mark_sent(struct gsm_sms *sms);
int db_apdu_blob_store(struct gsm_subscriber *subscr, int db_apdu_blob_store(struct gsm_subscriber *subscr,
u_int8_t apdu_id_flags, u_int8_t len, u_int8_t apdu_id_flags, u_int8_t len,
u_int8_t *apdu); u_int8_t *apdu);
/* Statistics counter storage */
int db_store_counter(struct counter *ctr);
#endif /* _DB_H */ #endif /* _DB_H */

View File

@ -61,6 +61,7 @@ enum gsm_chreq_reason_t {
#include <openbsc/mncc.h> #include <openbsc/mncc.h>
#include <openbsc/tlv.h> #include <openbsc/tlv.h>
#include <openbsc/bitvec.h> #include <openbsc/bitvec.h>
#include <openbsc/statistics.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@ -460,43 +461,43 @@ struct gsm_bts {
/* Some statistics of our network */ /* Some statistics of our network */
struct gsmnet_stats { struct gsmnet_stats {
struct { struct {
unsigned long total; struct counter *total;
unsigned long no_channel; struct counter *no_channel;
} chreq; } chreq;
struct { struct {
unsigned long attempted; struct counter *attempted;
unsigned long no_channel; /* no channel available */ struct counter *no_channel; /* no channel available */
unsigned long timeout; /* T3103 timeout */ struct counter *timeout; /* T3103 timeout */
unsigned long completed; /* HO COMPL received */ struct counter *completed; /* HO COMPL received */
unsigned long failed; /* HO FAIL received */ struct counter *failed; /* HO FAIL received */
} handover; } handover;
struct { struct {
unsigned long attach; struct counter *attach;
unsigned long normal; struct counter *normal;
unsigned long periodic; struct counter *periodic;
unsigned long detach; struct counter *detach;
} loc_upd_type; } loc_upd_type;
struct { struct {
unsigned long reject; struct counter *reject;
unsigned long accept; struct counter *accept;
} loc_upd_resp; } loc_upd_resp;
struct { struct {
unsigned long attempted; struct counter *attempted;
unsigned long detached; struct counter *detached;
unsigned long completed; struct counter *completed;
unsigned long expired; struct counter *expired;
} paging; } paging;
struct { struct {
unsigned long submitted; /* MO SMS submissions */ struct counter *submitted; /* MO SMS submissions */
unsigned long no_receiver; struct counter *no_receiver;
unsigned long delivered; /* MT SMS deliveries */ struct counter *delivered; /* MT SMS deliveries */
unsigned long rp_err_mem; struct counter *rp_err_mem;
unsigned long rp_err_other; struct counter *rp_err_other;
} sms; } sms;
struct { struct {
unsigned long dialled; /* total number of dialled calls */ struct counter *dialled; /* total number of dialled calls */
unsigned long alerted; /* we alerted the other end */ struct counter *alerted; /* we alerted the other end */
unsigned long connected;/* how many calls were accepted */ struct counter *connected;/* how many calls were accepted */
} call; } call;
}; };

View File

@ -0,0 +1,30 @@
#ifndef _STATISTICS_H
#define _STATISTICS_H
struct counter {
struct llist_head list;
const char *name;
const char *description;
unsigned long value;
};
static inline void counter_inc(struct counter *ctr)
{
ctr->value++;
}
static inline unsigned long counter_get(struct counter *ctr)
{
return ctr->value;
}
static inline void counter_reset(struct counter *ctr)
{
ctr->value = 0;
}
struct counter *counter_alloc(const char *name);
void counter_free(struct counter *ctr);
int counters_store_db(void);
#endif /* _STATISTICS_H */

View File

@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
talloc_ctx.c system_information.c bitvec.c rest_octets.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \
rtp_proxy.c rtp_proxy.c statistics.c
libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \

View File

@ -1261,14 +1261,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci); lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci);
chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci); chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci);
bts->network->stats.chreq.total++; counter_inc(bts->network->stats.chreq.total);
/* check availability / allocate channel */ /* check availability / allocate channel */
lchan = lchan_alloc(bts, lctype); lchan = lchan_alloc(bts, lctype);
if (!lchan) { if (!lchan) {
DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n",
gsm_lchan_name(lctype), rqd_ref->ra); gsm_lchan_name(lctype), rqd_ref->ra);
bts->network->stats.chreq.no_channel++; counter_inc(bts->network->stats.chreq.no_channel);
/* FIXME: send some kind of reject ?!? */ /* FIXME: send some kind of reject ?!? */
return -ENOMEM; return -ENOMEM;
} }

View File

@ -71,6 +71,11 @@ static const char *trx1_password = "1111111111";
static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 }; static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
/* dummy function to keep gsm_data.c happy */
struct counter *counter_alloc(const char *name)
{
return NULL;
}
int handle_serial_msg(struct msgb *rx_msg); int handle_serial_msg(struct msgb *rx_msg);

View File

@ -25,6 +25,7 @@
#include <openbsc/db.h> #include <openbsc/db.h>
#include <openbsc/talloc.h> #include <openbsc/talloc.h>
#include <openbsc/debug.h> #include <openbsc/debug.h>
#include <openbsc/statistics.h>
#include <libgen.h> #include <libgen.h>
#include <stdio.h> #include <stdio.h>
@ -117,6 +118,12 @@ static char *create_stmts[] = {
"subscriber_id INTEGER NOT NULL, " "subscriber_id INTEGER NOT NULL, "
"apdu BLOB " "apdu BLOB "
")", ")",
"CREATE TABLE IF NOT EXISTS Counters ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"timestamp TIMESTAMP NOT NULL, "
"value INTEGER NOT NULL "
"name TEXT NOT NULL, "
")",
}; };
void db_error_func(dbi_conn conn, void* data) { void db_error_func(dbi_conn conn, void* data) {
@ -902,3 +909,24 @@ int db_apdu_blob_store(struct gsm_subscriber *subscr,
dbi_result_free(result); dbi_result_free(result);
return 0; return 0;
} }
int db_store_counter(struct counter *ctr)
{
dbi_result result;
char *q_name;
dbi_conn_quote_string_copy(conn, ctr->name, &q_name);
result = dbi_conn_queryf(conn,
"INSERT INTO Counters "
"(timestamp,name,value) VALUES "
"(datetime('now'),%s,%lu)", q_name, ctr->value);
free(q_name);
if (!result)
return -EIO;
dbi_result_free(result);
return 0;
}

View File

@ -831,7 +831,7 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
bts->network->stats.loc_upd_resp.reject++; counter_inc(bts->network->stats.loc_upd_resp.reject);
return gsm48_sendmsg(msg, NULL); return gsm48_sendmsg(msg, NULL);
} }
@ -860,7 +860,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
bts->network->stats.loc_upd_resp.accept++; counter_inc(bts->network->stats.loc_upd_resp.accept);
return gsm48_sendmsg(msg, NULL); return gsm48_sendmsg(msg, NULL);
} }
@ -982,13 +982,13 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
switch (lu->type) { switch (lu->type) {
case GSM48_LUPD_NORMAL: case GSM48_LUPD_NORMAL:
bts->network->stats.loc_upd_type.normal++; counter_inc(bts->network->stats.loc_upd_type.normal);
break; break;
case GSM48_LUPD_IMSI_ATT: case GSM48_LUPD_IMSI_ATT:
bts->network->stats.loc_upd_type.attach++; counter_inc(bts->network->stats.loc_upd_type.attach);
break; break;
case GSM48_LUPD_PERIODIC: case GSM48_LUPD_PERIODIC:
bts->network->stats.loc_upd_type.periodic++; counter_inc(bts->network->stats.loc_upd_type.periodic);
break; break;
} }
@ -1318,7 +1318,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ", DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
mi_type, mi_string); mi_type, mi_string);
bts->network->stats.loc_upd_type.detach++; counter_inc(bts->network->stats.loc_upd_type.detach);
switch (mi_type) { switch (mi_type) {
case GSM_MI_TYPE_TMSI: case GSM_MI_TYPE_TMSI:

View File

@ -517,7 +517,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0; int rc = 0;
bts->network->stats.sms.submitted++; counter_inc(bts->network->stats.sms.submitted);
gsms = sms_alloc(); gsms = sms_alloc();
if (!gsms) if (!gsms)
@ -607,7 +607,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr); gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
if (!gsms->receiver) { if (!gsms->receiver) {
rc = 1; /* cause 1: unknown subscriber */ rc = 1; /* cause 1: unknown subscriber */
bts->network->stats.sms.no_receiver++; counter_inc(bts->network->stats.sms.no_receiver);
goto out; goto out;
} }
@ -761,6 +761,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph) struct gsm411_rp_hdr *rph)
{ {
struct gsm_network *net = trans->lchan->ts->trx->bts->network;
struct gsm_sms *sms = trans->sms.sms; struct gsm_sms *sms = trans->sms.sms;
u_int8_t cause_len = rph->data[0]; u_int8_t cause_len = rph->data[0];
u_int8_t cause = rph->data[1]; u_int8_t cause = rph->data[1];
@ -794,9 +795,9 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
* to store this in our database and wati for a SMMA message */ * to store this in our database and wati for a SMMA message */
/* FIXME */ /* FIXME */
dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr); dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
trans->lchan->ts->trx->bts->network->stats.sms.rp_err_mem++; counter_inc(net->stats.sms.rp_err_mem);
} else } else
trans->lchan->ts->trx->bts->network->stats.sms.rp_err_other++; counter_inc(net->stats.sms.rp_err_other);
sms_free(sms); sms_free(sms);
trans->sms.sms = NULL; trans->sms.sms = NULL;
@ -1073,7 +1074,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
DEBUGP(DSMS, "TX: SMS DELIVER\n"); DEBUGP(DSMS, "TX: SMS DELIVER\n");
lchan->ts->trx->bts->network->stats.sms.delivered++; counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered);
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref); return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
/* FIXME: enter 'wait for RP-ACK' state, start TR1N */ /* FIXME: enter 'wait for RP-ACK' state, start TR1N */

View File

@ -28,6 +28,7 @@
#include <openbsc/gsm_data.h> #include <openbsc/gsm_data.h>
#include <openbsc/talloc.h> #include <openbsc/talloc.h>
#include <openbsc/abis_nm.h> #include <openbsc/abis_nm.h>
#include <openbsc/statistics.h>
void *tall_bsc_ctx; void *tall_bsc_ctx;
@ -226,6 +227,32 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->upqueue);
INIT_LLIST_HEAD(&net->bts_list); INIT_LLIST_HEAD(&net->bts_list);
net->stats.chreq.total = counter_alloc("net.chreq.total");
net->stats.chreq.no_channel = counter_alloc("net.chreq.no_channel");
net->stats.handover.attempted = counter_alloc("net.handover.attempted");
net->stats.handover.no_channel = counter_alloc("net.handover.no_channel");
net->stats.handover.timeout = counter_alloc("net.handover.timeout");
net->stats.handover.completed = counter_alloc("net.handover.completed");
net->stats.handover.failed = counter_alloc("net.handover.failed");
net->stats.loc_upd_type.attach = counter_alloc("net.loc_upd_type.attach");
net->stats.loc_upd_type.normal = counter_alloc("net.loc_upd_type.normal");
net->stats.loc_upd_type.periodic = counter_alloc("net.loc_upd_type.periodic");
net->stats.loc_upd_type.detach = counter_alloc("net.imsi_detach.count");
net->stats.loc_upd_resp.reject = counter_alloc("net.loc_upd_resp.reject");
net->stats.loc_upd_resp.accept = counter_alloc("net.loc_upd_resp.accept");
net->stats.paging.attempted = counter_alloc("net.paging.attempted");
net->stats.paging.detached = counter_alloc("net.paging.detached");
net->stats.paging.completed = counter_alloc("net.paging.completed");
net->stats.paging.expired = counter_alloc("net.paging.expired");
net->stats.sms.submitted = counter_alloc("net.sms.submitted");
net->stats.sms.no_receiver = counter_alloc("net.sms.no_receiver");
net->stats.sms.delivered = counter_alloc("net.sms.delivered");
net->stats.sms.rp_err_mem = counter_alloc("net.sms.rp_err_mem");
net->stats.sms.rp_err_other = counter_alloc("net.sms.rp_err_other");
net->stats.call.dialled = counter_alloc("net.call.dialled");
net->stats.call.alerted = counter_alloc("net.call.alerted");
net->stats.call.connected = counter_alloc("net.call.connected");
net->mncc_recv = mncc_recv; net->mncc_recv = mncc_recv;
return net; return net;

View File

@ -97,12 +97,12 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n",
old_lchan->ts->trx->bts->nr, bts->nr); old_lchan->ts->trx->bts->nr, bts->nr);
bts->network->stats.handover.attempted++; counter_inc(bts->network->stats.handover.attempted);
new_lchan = lchan_alloc(bts, old_lchan->type); new_lchan = lchan_alloc(bts, old_lchan->type);
if (!new_lchan) { if (!new_lchan) {
LOGP(DHO, LOGL_NOTICE, "No free channel\n"); LOGP(DHO, LOGL_NOTICE, "No free channel\n");
bts->network->stats.handover.no_channel++; counter_inc(bts->network->stats.handover.no_channel);
return -ENOSPC; return -ENOSPC;
} }
@ -144,9 +144,10 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
static void ho_T3103_cb(void *_ho) static void ho_T3103_cb(void *_ho)
{ {
struct bsc_handover *ho = _ho; struct bsc_handover *ho = _ho;
struct gsm_network *net = ho->new_lchan->ts->trx->bts->network;
DEBUGP(DHO, "HO T3103 expired\n"); DEBUGP(DHO, "HO T3103 expired\n");
ho->new_lchan->ts->trx->bts->network->stats.handover.timeout++; counter_inc(net->stats.handover.timeout);
lchan_free(ho->new_lchan); lchan_free(ho->new_lchan);
llist_del(&ho->list); llist_del(&ho->list);
@ -207,6 +208,7 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan)
/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */ /* GSM 04.08 HANDOVER COMPLETE has been received on new channel */
static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
{ {
struct gsm_network *net = new_lchan->ts->trx->bts->network;
struct bsc_handover *ho; struct bsc_handover *ho;
ho = bsc_ho_by_new_lchan(new_lchan); ho = bsc_ho_by_new_lchan(new_lchan);
@ -215,7 +217,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
return -ENODEV; return -ENODEV;
} }
new_lchan->ts->trx->bts->network->stats.handover.completed++; counter_inc(net->stats.handover.completed);
bsc_del_timer(&ho->T3103); bsc_del_timer(&ho->T3103);
@ -236,6 +238,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
/* GSM 04.08 HANDOVER FAIL has been received */ /* GSM 04.08 HANDOVER FAIL has been received */
static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
{ {
struct gsm_network *net = old_lchan->ts->trx->bts->network;
struct bsc_handover *ho; struct bsc_handover *ho;
ho = bsc_ho_by_old_lchan(old_lchan); ho = bsc_ho_by_old_lchan(old_lchan);
@ -244,7 +247,7 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
return -ENODEV; return -ENODEV;
} }
old_lchan->ts->trx->bts->network->stats.handover.failed++; counter_inc(net->stats.handover.failed);
bsc_del_timer(&ho->T3103); bsc_del_timer(&ho->T3103);
llist_del(&ho->list); llist_del(&ho->list);

View File

@ -212,7 +212,7 @@ static void paging_T3113_expired(void *data)
cbfn = req->cbfn; cbfn = req->cbfn;
paging_remove_request(&req->bts->paging, req); paging_remove_request(&req->bts->paging, req);
req->bts->network->stats.paging.expired++; counter_inc(req->bts->network->stats.paging.expired);
dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
if (cbfn) if (cbfn)
@ -256,7 +256,7 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
struct gsm_bts *bts = NULL; struct gsm_bts *bts = NULL;
int num_pages = 0; int num_pages = 0;
network->stats.paging.attempted++; counter_inc(network->stats.paging.attempted);
/* start paging subscriber on all BTS within Location Area */ /* start paging subscriber on all BTS within Location Area */
do { do {
@ -274,7 +274,7 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
} while (1); } while (1);
if (num_pages == 0) if (num_pages == 0)
network->stats.paging.detached++; counter_inc(network->stats.paging.detached);
return num_pages; return num_pages;
} }

85
openbsc/src/statistics.c Normal file
View File

@ -0,0 +1,85 @@
/* utility routines for keeping some statistics */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <sys/types.h>
#include <openbsc/gsm_data.h>
#include <openbsc/signal.h>
#include <openbsc/linuxlist.h>
#include <openbsc/talloc.h>
#include <openbsc/statistics.h>
#include <openbsc/db.h>
#include <openbsc/timer.h>
static LLIST_HEAD(counters);
static struct timer_list db_sync_timer;
#define DB_SYNC_INTERVAL 60, 0
struct counter *counter_alloc(const char *name)
{
struct counter *ctr = talloc_zero(tall_bsc_ctx, struct counter);
if (!ctr)
return NULL;
ctr->name = name;
llist_add_tail(&ctr->list, &counters);
return ctr;
}
void counter_free(struct counter *ctr)
{
llist_del(&ctr->list);
talloc_free(ctr);
}
int counters_store_db(void)
{
struct counter *ctr;
int rc = 0;
llist_for_each_entry(ctr, &counters, list) {
rc = db_store_counter(ctr);
if (rc < 0)
return rc;
}
return rc;
}
static void db_sync_timer_cb(void *data)
{
/* store counters to database and re-schedule */
counters_store_db();
bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
}
static __attribute__((constructor)) void on_dso_load_stat(void)
{
db_sync_timer.cb = db_sync_timer_cb;
db_sync_timer.data = NULL;
bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
}

View File

@ -811,30 +811,35 @@ DEFUN(show_stats,
struct gsm_network *net = gsmnet; struct gsm_network *net = gsmnet;
vty_out(vty, "Channel Requests: %lu total, %lu no channel%s", vty_out(vty, "Channel Requests: %lu total, %lu no channel%s",
net->stats.chreq.total, net->stats.chreq.no_channel, counter_get(net->stats.chreq.total),
VTY_NEWLINE); counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s", vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s",
net->stats.loc_upd_type.attach, net->stats.loc_upd_type.normal, counter_get(net->stats.loc_upd_type.attach),
net->stats.loc_upd_type.periodic, VTY_NEWLINE); counter_get(net->stats.loc_upd_type.normal),
vty_out(vty, "IMSI Detach Indications: %lu%s\n", counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
net->stats.loc_upd_type.detach, VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications: %lu%s",
counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
net->stats.loc_upd_resp.accept, counter_get(net->stats.loc_upd_resp.accept),
net->stats.loc_upd_resp.reject, VTY_NEWLINE); counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s", vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s",
net->stats.paging.attempted, net->stats.paging.completed, counter_get(net->stats.paging.attempted),
net->stats.paging.expired, VTY_NEWLINE); counter_get(net->stats.paging.completed),
counter_get(net->stats.paging.expired), VTY_NEWLINE);
vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, " vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, "
"%lu completed, %lu failed%s", net->stats.handover.attempted, "%lu completed, %lu failed%s",
net->stats.handover.no_channel, net->stats.handover.timeout, counter_get(net->stats.handover.attempted),
net->stats.handover.completed, net->stats.handover.failed, counter_get(net->stats.handover.no_channel),
VTY_NEWLINE); counter_get(net->stats.handover.timeout),
counter_get(net->stats.handover.completed),
counter_get(net->stats.handover.failed), VTY_NEWLINE);
vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s", vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s",
net->stats.sms.submitted, net->stats.sms.no_receiver, counter_get(net->stats.sms.submitted),
VTY_NEWLINE); counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s", vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s",
net->stats.sms.delivered, net->stats.sms.rp_err_mem, counter_get(net->stats.sms.delivered),
net->stats.sms.rp_err_other, VTY_NEWLINE); counter_get(net->stats.sms.rp_err_mem),
counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
return CMD_SUCCESS; return CMD_SUCCESS;
} }