diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 9d2549ca1..74e193832 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -457,6 +457,49 @@ struct gsm_bts { struct llist_head trx_list; }; +/* Some statistics of our network */ +struct gsmnet_stats { + struct { + unsigned long total; + unsigned long no_channel; + } chreq; + struct { + unsigned long attempted; + unsigned long no_channel; /* no channel available */ + unsigned long timeout; /* T3103 timeout */ + unsigned long completed; /* HO COMPL received */ + unsigned long failed; /* HO FAIL received */ + } handover; + struct { + unsigned long attach; + unsigned long normal; + unsigned long periodic; + unsigned long detach; + } loc_upd_type; + struct { + unsigned long reject; + unsigned long accept; + } loc_upd_resp; + struct { + unsigned long attempted; + unsigned long detached; + unsigned long completed; + unsigned long expired; + } paging; + struct { + unsigned long submitted; /* MO SMS submissions */ + unsigned long no_receiver; + unsigned long delivered; /* MT SMS deliveries */ + unsigned long rp_err_mem; + unsigned long rp_err_other; + } sms; + struct { + unsigned long dialled; /* total number of dialled calls */ + unsigned long alerted; /* we alerted the other end */ + unsigned long connected;/* how many calls were accepted */ + } call; +}; + enum gsm_auth_policy { GSM_AUTH_POLICY_CLOSED, /* only subscribers authorized in DB */ GSM_AUTH_POLICY_ACCEPT_ALL, /* accept everyone, even if not authorized in DB */ @@ -494,6 +537,8 @@ struct gsm_network { unsigned int max_distance; /* TA values */ } handover; + struct gsmnet_stats stats; + /* layer 4 */ int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); struct llist_head upqueue; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 72ae9dbb6..ae1d6af5d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1261,11 +1261,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg) 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); + bts->network->stats.chreq.total++; + /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", gsm_lchan_name(lctype), rqd_ref->ra); + bts->network->stats.chreq.no_channel++; /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 156927f56..2b9dcc238 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -886,6 +886,7 @@ static int encode_more(struct msgb *msg) /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) { + struct gsm_bts *bts = lchan->ts->trx->bts; struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -897,6 +898,8 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) gh->data[0] = cause; DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); + + bts->network->stats.loc_upd_resp.reject++; return gsm48_sendmsg(msg, NULL); } @@ -925,6 +928,8 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); + bts->network->stats.loc_upd_resp.accept++; + return gsm48_sendmsg(msg, NULL); } @@ -1043,6 +1048,18 @@ static int mm_rx_loc_upd_req(struct msgb *msg) dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, &lu->mi_len); + switch (lu->type) { + case GSM48_LUPD_NORMAL: + bts->network->stats.loc_upd_type.normal++; + break; + case GSM48_LUPD_IMSI_ATT: + bts->network->stats.loc_upd_type.attach++; + break; + case GSM48_LUPD_PERIODIC: + bts->network->stats.loc_upd_type.periodic++; + break; + } + /* * Pseudo Spoof detection: Just drop a second/concurrent * location updating request. @@ -1369,6 +1386,8 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ", mi_type, mi_string); + bts->network->stats.loc_upd_type.detach++; + switch (mi_type) { case GSM_MI_TYPE_TMSI: subscr = subscr_get_by_tmsi(bts->network, diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index e96a1ca09..2cd571e24 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -488,6 +488,8 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) sig_data.bts = msg->lchan->ts->trx->bts; sig_data.lchan = msg->lchan; + bts->network->stats.paging.completed++; + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); /* Stop paging on the bts we received the paging response */ diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 17a583113..579bb55d1 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -517,6 +517,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; + bts->network->stats.sms.submitted++; + gsms = sms_alloc(); if (!gsms) return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; @@ -605,6 +607,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr); if (!gsms->receiver) { rc = 1; /* cause 1: unknown subscriber */ + bts->network->stats.sms.no_receiver++; goto out; } @@ -791,7 +794,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 */ /* FIXME */ dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr); - } + trans->lchan->ts->trx->bts->network->stats.sms.rp_err_mem++; + } else + trans->lchan->ts->trx->bts->network->stats.sms.rp_err_other++; sms_free(sms); trans->sms.sms = NULL; @@ -1064,6 +1069,8 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) DEBUGP(DSMS, "TX: SMS DELIVER\n"); + lchan->ts->trx->bts->network->stats.sms.delivered++; + return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref); /* FIXME: enter 'wait for RP-ACK' state, start TR1N */ } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 94d3d0d1e..393b0f2ad 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -97,9 +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", old_lchan->ts->trx->bts->nr, bts->nr); + bts->network->stats.handover.attempted++; + new_lchan = lchan_alloc(bts, old_lchan->type); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); + bts->network->stats.handover.no_channel++; return -ENOSPC; } @@ -143,6 +146,7 @@ static void ho_T3103_cb(void *_ho) struct bsc_handover *ho = _ho; DEBUGP(DHO, "HO T3103 expired\n"); + ho->new_lchan->ts->trx->bts->network->stats.handover.timeout++; lchan_free(ho->new_lchan); llist_del(&ho->list); @@ -211,6 +215,8 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) return -ENODEV; } + new_lchan->ts->trx->bts->network->stats.handover.completed++; + bsc_del_timer(&ho->T3103); /* update lchan pointer of transaction */ @@ -238,6 +244,8 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) return -ENODEV; } + old_lchan->ts->trx->bts->network->stats.handover.failed++; + bsc_del_timer(&ho->T3103); llist_del(&ho->list); put_lchan(ho->new_lchan); diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index b273419c3..538e0a8ec 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -212,6 +212,8 @@ static void paging_T3113_expired(void *data) cbfn = req->cbfn; paging_remove_request(&req->bts->paging, req); + req->bts->network->stats.paging.expired++; + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); if (cbfn) cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL, @@ -254,6 +256,8 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, struct gsm_bts *bts = NULL; int num_pages = 0; + network->stats.paging.attempted++; + /* start paging subscriber on all BTS within Location Area */ do { int rc; @@ -269,6 +273,9 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, return rc; } while (1); + if (num_pages == 0) + network->stats.paging.detached++; + return num_pages; } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index b13dc5f58..fa9b45da4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -761,6 +761,41 @@ DEFUN(show_paging, return CMD_SUCCESS; } +DEFUN(show_stats, + show_stats_cmd, + "show statistics", + SHOW_STR "Display network statistics\n") +{ + struct gsm_network *net = gsmnet; + + vty_out(vty, "Channel Requests: %lu total, %lu no channel%s", + net->stats.chreq.total, net->stats.chreq.no_channel, + VTY_NEWLINE); + vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s", + net->stats.loc_upd_type.attach, net->stats.loc_upd_type.normal, + net->stats.loc_upd_type.periodic, VTY_NEWLINE); + vty_out(vty, "IMSI Detach Indications: %lu%s\n", + net->stats.loc_upd_type.detach, VTY_NEWLINE); + vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", + net->stats.loc_upd_resp.accept, + net->stats.loc_upd_resp.reject, VTY_NEWLINE); + vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s", + net->stats.paging.attempted, net->stats.paging.completed, + net->stats.paging.expired, VTY_NEWLINE); + vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, " + "%lu completed, %lu failed%s", net->stats.handover.attempted, + net->stats.handover.no_channel, net->stats.handover.timeout, + net->stats.handover.completed, net->stats.handover.failed, + VTY_NEWLINE); + vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s", + net->stats.sms.submitted, net->stats.sms.no_receiver, + VTY_NEWLINE); + vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s", + net->stats.sms.delivered, net->stats.sms.rp_err_mem, + net->stats.sms.rp_err_other, VTY_NEWLINE); + return CMD_SUCCESS; +} + DEFUN(cfg_net, cfg_net_cmd, "network", @@ -1435,6 +1470,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_e1ts_cmd); install_element(VIEW_NODE, &show_paging_cmd); + install_element(VIEW_NODE, &show_stats_cmd); install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net);