/* osmo-bsc statistics */ /* (C) 2021 by sysmocom - s.f.m.c. GmbH * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include const struct rate_ctr_desc bsc_ctr_description[] = { [BSC_CTR_ASSIGNMENT_ATTEMPTED] = {"assignment:attempted", "Assignment attempts"}, [BSC_CTR_ASSIGNMENT_COMPLETED] = {"assignment:completed", "Assignment completed"}, [BSC_CTR_ASSIGNMENT_STOPPED] = {"assignment:stopped", "Connection ended during Assignment"}, [BSC_CTR_ASSIGNMENT_NO_CHANNEL] = {"assignment:no_channel", "Failure to allocate lchan for Assignment"}, [BSC_CTR_ASSIGNMENT_TIMEOUT] = {"assignment:timeout", "Assignment timed out"}, [BSC_CTR_ASSIGNMENT_FAILED] = {"assignment:failed", "Received Assignment Failure message"}, [BSC_CTR_ASSIGNMENT_ERROR] = {"assignment:error", "Assignment failed for other reason"}, [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover:attempted", "Handover attempts"}, [BSC_CTR_HANDOVER_COMPLETED] = {"handover:completed", "Handover completed"}, [BSC_CTR_HANDOVER_STOPPED] = {"handover:stopped", "Connection ended during HO"}, [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover:no_channel", "Failure to allocate lchan for HO"}, [BSC_CTR_HANDOVER_TIMEOUT] = {"handover:timeout", "Handover timed out"}, [BSC_CTR_HANDOVER_FAILED] = {"handover:failed", "Received Handover Fail messages"}, [BSC_CTR_HANDOVER_ERROR] = {"handover:error", "Handover failed for other reason"}, [BSC_CTR_INTRA_CELL_HO_ATTEMPTED] = {"intra_cell_ho:attempted", "Intra-Cell handover attempts"}, [BSC_CTR_INTRA_CELL_HO_COMPLETED] = {"intra_cell_ho:completed", "Intra-Cell handover completed"}, [BSC_CTR_INTRA_CELL_HO_STOPPED] = {"intra_cell_ho:stopped", "Connection ended during HO"}, [BSC_CTR_INTRA_CELL_HO_NO_CHANNEL] = {"intra_cell_ho:no_channel", "Failure to allocate lchan for HO"}, [BSC_CTR_INTRA_CELL_HO_TIMEOUT] = {"intra_cell_ho:timeout", "Handover timed out"}, [BSC_CTR_INTRA_CELL_HO_FAILED] = {"intra_cell_ho:failed", "Received Handover Fail messages"}, [BSC_CTR_INTRA_CELL_HO_ERROR] = {"intra_cell_ho:error", "Intra-cell handover failed for other reason"}, [BSC_CTR_INTRA_BSC_HO_ATTEMPTED] = {"intra_bsc_ho:attempted", "Intra-BSC inter-cell handover attempts"}, [BSC_CTR_INTRA_BSC_HO_COMPLETED] = {"intra_bsc_ho:completed", "Intra-BSC inter-cell handover completed"}, [BSC_CTR_INTRA_BSC_HO_STOPPED] = {"intra_bsc_ho:stopped", "Connection ended during HO"}, [BSC_CTR_INTRA_BSC_HO_NO_CHANNEL] = {"intra_bsc_ho:no_channel", "Failure to allocate lchan for HO"}, [BSC_CTR_INTRA_BSC_HO_TIMEOUT] = {"intra_bsc_ho:timeout", "Handover timed out"}, [BSC_CTR_INTRA_BSC_HO_FAILED] = {"intra_bsc_ho:failed", "Received Handover Fail messages"}, [BSC_CTR_INTRA_BSC_HO_ERROR] = {"intra_bsc_ho:error", "Intra-BSC inter-cell HO failed for other reason"}, [BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED] = {"interbsc_ho_out:attempted", "Attempts to handover to remote BSS"}, [BSC_CTR_INTER_BSC_HO_OUT_COMPLETED] = {"interbsc_ho_out:completed", "Handover to remote BSS completed"}, [BSC_CTR_INTER_BSC_HO_OUT_STOPPED] = {"interbsc_ho_out:stopped", "Connection ended during HO"}, [BSC_CTR_INTER_BSC_HO_OUT_TIMEOUT] = {"interbsc_ho_out:timeout", "Handover timed out"}, [BSC_CTR_INTER_BSC_HO_OUT_FAILED] = {"interbsc_ho_out:failed", "Received Handover Fail message"}, [BSC_CTR_INTER_BSC_HO_OUT_ERROR] = {"interbsc_ho_out:error", "Handover to remote BSS failed for other reason"}, [BSC_CTR_INTER_BSC_HO_IN_ATTEMPTED] = {"interbsc_ho_in:attempted", "Attempts to handover from remote BSS"}, [BSC_CTR_INTER_BSC_HO_IN_COMPLETED] = {"interbsc_ho_in:completed", "Handover from remote BSS completed"}, [BSC_CTR_INTER_BSC_HO_IN_STOPPED] = {"interbsc_ho_in:stopped", "Connection ended during HO"}, [BSC_CTR_INTER_BSC_HO_IN_NO_CHANNEL] = {"interbsc_ho_in:no_channel", "Failure to allocate lchan for HO"}, [BSC_CTR_INTER_BSC_HO_IN_TIMEOUT] = {"interbsc_ho_in:timeout", "Handover from remote BSS timed out"}, [BSC_CTR_INTER_BSC_HO_IN_FAILED] = {"interbsc_ho_in:failed", "Received Handover Fail message"}, [BSC_CTR_INTER_BSC_HO_IN_ERROR] = {"interbsc_ho_in:error", "Handover from remote BSS failed for other reason"}, [BSC_CTR_SRVCC_ATTEMPTED] = {"srvcc:attempted", "Intra-BSC SRVCC attempts"}, [BSC_CTR_SRVCC_COMPLETED] = {"srvcc:completed", "Intra-BSC SRVCC completed"}, [BSC_CTR_SRVCC_STOPPED] = {"srvcc:stopped", "Connection ended during HO"}, [BSC_CTR_SRVCC_NO_CHANNEL] = {"srvcc:no_channel", "Failure to allocate lchan for HO"}, [BSC_CTR_SRVCC_TIMEOUT] = {"srvcc:timeout", "SRVCC timed out"}, [BSC_CTR_SRVCC_FAILED] = {"srvcc:failed", "Received SRVCC Fail messages"}, [BSC_CTR_SRVCC_ERROR] = {"srvcc:error", "Re-assignment failed for other reason"}, [BSC_CTR_PAGING_ATTEMPTED] = {"paging:attempted", "Paging attempts for a subscriber"}, [BSC_CTR_PAGING_DETACHED] = {"paging:detached", "Paging request send failures because no responsible BTS was found"}, [BSC_CTR_PAGING_RESPONDED] = {"paging:responded", "Paging attempts with successful response"}, [BSC_CTR_PAGING_NO_ACTIVE_PAGING] = {"paging:no_active_paging", "Paging response without an active paging request (arrived after paging expiration?)"}, [BSC_CTR_UNKNOWN_UNIT_ID] = {"abis:unknown_unit_id", "Connection attempts from unknown IPA CCM Unit ID"}, [BSC_CTR_MSCPOOL_SUBSCR_NO_MSC] = {"mscpool:subscr:no_msc", "Complete Layer 3 requests lost because no connected MSC is found available"}, [BSC_CTR_MSCPOOL_EMERG_FORWARDED] = {"mscpool:emerg:forwarded", "Emergency call requests forwarded to an MSC (see also per-MSC counters"}, [BSC_CTR_MSCPOOL_EMERG_LOST] = {"mscpool:emerg:lost", "Emergency call requests lost because no MSC was found available"}, [BSC_CTR_ALL_ALLOCATED_SDCCH] = {"all_allocated:sdcch", "Cumulative counter of seconds where all SDCCH channels were allocated"}, [BSC_CTR_ALL_ALLOCATED_STATIC_SDCCH] = {"all_allocated:static_sdcch", "Cumulative counter of seconds where all non-dynamic SDCCH channels were allocated"}, [BSC_CTR_ALL_ALLOCATED_TCH] = {"all_allocated:tch", "Cumulative counter of seconds where all TCH channels were allocated"}, [BSC_CTR_ALL_ALLOCATED_STATIC_TCH] = {"all_allocated:static_tch", "Cumulative counter of seconds where all non-dynamic TCH channels were allocated"}, }; const struct rate_ctr_group_desc bsc_ctrg_desc = { "bsc", "base station controller", OSMO_STATS_CLASS_GLOBAL, ARRAY_SIZE(bsc_ctr_description), bsc_ctr_description, }; static const struct osmo_stat_item_desc bsc_stat_desc[] = { [BSC_STAT_NUM_BTS_OML_CONNECTED] = { "num_bts:oml_connected", "Number of BTS for this BSC where OML is up", "", 16, 0 }, [BSC_STAT_NUM_BTS_ALL_TRX_RSL_CONNECTED] = { "num_bts:all_trx_rsl_connected", "Number of BTS for this BSC where RSL is up for all TRX", "", 16, 0 }, [BSC_STAT_NUM_BTS_TOTAL] = { "num_bts:total", "Number of configured BTS for this BSC", "", 16, 0 }, [BSC_STAT_NUM_TRX_RSL_CONNECTED] = { "num_trx:rsl_connected", "Number of TRX where RSL is up, total sum across all BTS", "", 16, 0 }, [BSC_STAT_NUM_TRX_TOTAL] = { "num_trx:total", "Number of configured TRX, total sum across all BTS", "", 1, 0 }, [BSC_STAT_NUM_MSC_CONNECTED] = { "num_msc:connected", "Number of actively connected MSCs", "", 16, 0 }, [BSC_STAT_NUM_MSC_TOTAL] = { "num_msc:total", "Number of configured MSCs, not necessarily connected", "", 1, 0 }, }; const struct osmo_stat_item_group_desc bsc_statg_desc = { .group_name_prefix = "bsc", .group_description = "base station controller", .class_id = OSMO_STATS_CLASS_GLOBAL, .num_items = ARRAY_SIZE(bsc_stat_desc), .item_desc = bsc_stat_desc, }; /* Count all BTS and TRX OML and RSL stati and update stat items */ void bsc_update_connection_stats(struct gsm_network *net) { struct gsm_bts *bts; struct gsm_bts_trx *trx; /* Nr of configured BTS and total sum of configured TRX across all BTS */ int num_bts = 0; int num_trx_total = 0; /* Nr of BTS where OML is up */ int bts_oml_connected = 0; /* Nr of TRX across all BTS where RSL is up */ int trx_rsl_connected_total = 0; /* Nr of BTS that have all TRX RSL up */ int bts_rsl_all_trx_connected = 0; llist_for_each_entry(bts, &net->bts_list, list) { bool oml_connected = false; int num_trx = 0; int trx_rsl_connected = 0; llist_for_each_entry(trx, &bts->trx_list, list) { /* If any one trx is usable, it means OML for this BTS is connected */ if (trx_is_usable(trx)) oml_connected = true; /* Count nr of TRX for this BTS */ num_trx++; if (trx->ts[0].is_rsl_ready) trx_rsl_connected++; } osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_NUM_TRX_RSL_CONNECTED), trx_rsl_connected); osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_NUM_TRX_TOTAL), num_trx); num_trx_total += num_trx; trx_rsl_connected_total += trx_rsl_connected; num_bts++; if (oml_connected) bts_oml_connected++; if (trx_rsl_connected == num_trx) bts_rsl_all_trx_connected++; } osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_BTS_OML_CONNECTED), bts_oml_connected); osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_BTS_ALL_TRX_RSL_CONNECTED), bts_rsl_all_trx_connected); osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_BTS_TOTAL), num_bts); osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_TRX_RSL_CONNECTED), trx_rsl_connected_total); osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_TRX_TOTAL), num_trx_total); /* Make sure to notice cells that become disconnected */ bsc_update_time_cc_all_allocated(net); } void bsc_update_time_cc_all_allocated(struct gsm_network *net) { struct gsm_bts *bts; struct gsm_bts_trx *trx; struct chan_counts bsc_counts; chan_counts_zero(&bsc_counts); llist_for_each_entry(bts, &net->bts_list, list) { struct chan_counts bts_counts; chan_counts_zero(&bts_counts); llist_for_each_entry(trx, &bts->trx_list, list) { struct chan_counts trx_counts; chan_counts_for_trx(&trx_counts, trx); chan_counts_add(&bts_counts, &trx_counts); } time_cc_set_flag(&bts->all_allocated_sdcch, bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH] && !bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]); time_cc_set_flag(&bts->all_allocated_static_sdcch, bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH] && !bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]); time_cc_set_flag(&bts->all_allocated_tch, (bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F] + bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H]) && !(bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F] + bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H])); time_cc_set_flag(&bts->all_allocated_static_tch, (bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F] + bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H]) && !(bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F] + bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H])); chan_counts_add(&bsc_counts, &bts_counts); } time_cc_set_flag(&net->all_allocated_sdcch, bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH] && !bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]); time_cc_set_flag(&net->all_allocated_static_sdcch, bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH] && !bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]); time_cc_set_flag(&net->all_allocated_tch, (bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F] + bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H]) && !(bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F] + bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H])); time_cc_set_flag(&net->all_allocated_static_tch, (bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F] + bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H]) && !(bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F] + bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H])); }