Change in osmo-bsc[master]: Use new stat item/ctr getter APIs

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Fri Jun 4 19:39:07 UTC 2021


laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/24551 )

Change subject: Use new stat item/ctr getter APIs
......................................................................

Use new stat item/ctr getter APIs

Generated with  following and similar spatch snippets:
"""
@@
expression E1, E2;
@@
- &E2->ctr[E1]
+ rate_ctr_group_get_ctr(E2, E1)
"""

Change-Id: I0b43f922a595d694ac0aeda80107ef9bf4e755e7
---
M src/osmo-bsc/a_reset.c
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/bsc_subscr_conn_fsm.c
M src/osmo-bsc/bsc_vty.c
M src/osmo-bsc/bts.c
M src/osmo-bsc/bts_ipaccess_nanobts.c
M src/osmo-bsc/chan_alloc.c
M src/osmo-bsc/gsm_08_08.c
M src/osmo-bsc/handover_fsm.c
M src/osmo-bsc/lb.c
M src/osmo-bsc/lchan_fsm.c
M src/osmo-bsc/lcs_loc_req.c
M src/osmo-bsc/osmo_bsc_bssap.c
M src/osmo-bsc/osmo_bsc_filter.c
M src/osmo-bsc/osmo_bsc_main.c
M src/osmo-bsc/osmo_bsc_sigtran.c
M src/osmo-bsc/paging.c
M src/osmo-bsc/timeslot_fsm.c
19 files changed, 179 insertions(+), 181 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved



diff --git a/src/osmo-bsc/a_reset.c b/src/osmo-bsc/a_reset.c
index 2371499..0befd72 100644
--- a/src/osmo-bsc/a_reset.c
+++ b/src/osmo-bsc/a_reset.c
@@ -42,7 +42,7 @@
 {
 	struct bsc_msc_data *msc = data;
 	LOGP(DMSC, LOGL_NOTICE, "(msc%d) BSSMAP assocation is up\n", msc->nr);
-	osmo_stat_item_inc(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);
+	osmo_stat_item_inc(osmo_stat_item_group_get_item(msc->msc_statg, MSC_STAT_MSC_LINKS_ACTIVE), 1);
 	osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, msc);
 }
 
@@ -50,7 +50,7 @@
 {
 	struct bsc_msc_data *msc = data;
 	LOGP(DMSC, LOGL_NOTICE, "(msc%d) BSSMAP assocation is down\n", msc->nr);
-	osmo_stat_item_dec(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);
+	osmo_stat_item_dec(osmo_stat_item_group_get_item(msc->msc_statg, MSC_STAT_MSC_LINKS_ACTIVE), 1);
 	osmo_signal_dispatch(SS_MSC, S_MSC_LOST, msc);
 	osmo_bsc_sigtran_reset(msc);
 }
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 1fb4c04..00bb5dc 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -72,10 +72,10 @@
 	if (lchan->type == GSM_LCHAN_TCH_H) {
 		switch (gsm48_chan_mode_to_non_vamos(lchan->current_ch_mode_rate.chan_mode)) {
 		case GSM48_CMODE_SPEECH_AMR:
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_AMR_H]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CODEC_AMR_H));
 			break;
 		case GSM48_CMODE_SPEECH_V1:
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_V1_HR]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CODEC_V1_HR));
 			break;
 		default:
 			break;
@@ -83,13 +83,13 @@
 	} else if (lchan->type == GSM_LCHAN_TCH_F) {
 		switch (gsm48_chan_mode_to_non_vamos(lchan->current_ch_mode_rate.chan_mode)) {
 		case GSM48_CMODE_SPEECH_AMR:
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_AMR_F]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CODEC_AMR_F));
 			break;
 		case GSM48_CMODE_SPEECH_V1:
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_V1_FR]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CODEC_V1_FR));
 			break;
 		case GSM48_CMODE_SPEECH_EFR:
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_EFR]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CODEC_EFR));
 			break;
 		default:
 			break;
@@ -609,14 +609,14 @@
 
 	msg->dst = rsl_chan_link(lchan);
 
-	rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHAN_ACT_TOTAL]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHAN_ACT_TOTAL));
 	switch (lchan->type) {
 	case GSM_LCHAN_SDCCH:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHAN_ACT_SDCCH]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHAN_ACT_SDCCH));
 		break;
 	case GSM_LCHAN_TCH_H:
 	case GSM_LCHAN_TCH_F:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHAN_ACT_TCH]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHAN_ACT_TCH));
 		break;
 	default:
 		break;
@@ -956,7 +956,7 @@
 	struct gsm_lchan *lchan = msg->lchan;
 	const uint8_t *cause_p;
 
-	rate_ctr_inc(&msg->lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_CHAN_ACT_NACK]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(msg->lchan->ts->trx->bts->bts_ctrs, BTS_CTR_CHAN_ACT_NACK));
 
 	if (dh->ie_chan != RSL_IE_CHAN_NR) {
 		LOG_LCHAN(msg->lchan, LOGL_ERROR, "Invalid IE: expected CHAN_NR IE (0x%x), got 0x%x\n",
@@ -989,14 +989,14 @@
 
 	LOG_LCHAN(lchan, LOGL_ERROR, "CONNECTION FAIL%s\n", rsl_cause_name(&tp));
 
-	rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_CHAN_RF_FAIL]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_CHAN_RF_FAIL));
 	switch (lchan->type) {
 	case GSM_LCHAN_SDCCH:
-		rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_CHAN_RF_FAIL_SDCCH]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_CHAN_RF_FAIL_SDCCH));
 		break;
 	case GSM_LCHAN_TCH_H:
 	case GSM_LCHAN_TCH_F:
-		rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_CHAN_RF_FAIL_TCH]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_CHAN_RF_FAIL_TCH));
 		break;
 	default:
 		break;
@@ -1278,7 +1278,7 @@
 		break;
 	case RSL_MT_MODE_MODIFY_NACK:
 		LOG_LCHAN(msg->lchan, LOGL_DEBUG, "CHANNEL MODE MODIFY NACK\n");
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_MODE_MODIFY_NACK]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_MODE_MODIFY_NACK));
 		osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK, NULL);
 		break;
 	case RSL_MT_IPAC_PDCH_ACT_ACK:
@@ -1303,12 +1303,12 @@
 	case RSL_MT_MR_CODEC_MOD_PER:
 		LOG_LCHAN(msg->lchan, LOGL_NOTICE, "Unimplemented Abis RSL DChan msg 0x%02x\n",
 			  rslh->c.msg_type);
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 		break;
 	default:
 		LOG_LCHAN(msg->lchan, LOGL_NOTICE, "Unknown Abis RSL DChan msg 0x%02x\n",
 			  rslh->c.msg_type);
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 		return -EINVAL;
 	}
 
@@ -1357,7 +1357,7 @@
 	default:
 		LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
 			"type 0x%02x\n", gsm_trx_name(sign_link->trx), rslh->msg_type);
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 		return -EINVAL;
 	}
 	return rc;
@@ -1537,7 +1537,7 @@
 	if (rqd->ta > bts->rach_max_delay) {
 		LOG_BTS(bts, DRSL, LOGL_INFO, "Ignoring CHAN RQD: Access Delay(%d) greater than %u\n",
 			rqd->ta, bts->rach_max_delay);
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_MAX_DELAY_EXCEEDED]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_MAX_DELAY_EXCEEDED));
 		talloc_free(rqd);
 		return -EINVAL;
 	}
@@ -1547,28 +1547,28 @@
 	LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n",
 		get_value_string(gsm_chreq_descs, rqd->reason), rqd->ref.ra, bts->network->neci, rqd->reason);
 
-	rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_TOTAL]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_TOTAL));
 	switch (rqd->reason) {
 	case GSM_CHREQ_REASON_EMERG:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_EMERG]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_EMERG));
 		break;
 	case GSM_CHREQ_REASON_CALL:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_CALL]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_CALL));
 		break;
 	case GSM_CHREQ_REASON_LOCATION_UPD:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_LOCATION_UPD]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_LOCATION_UPD));
 		break;
 	case GSM_CHREQ_REASON_PAG:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_PAG]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_PAG));
 		break;
 	case GSM_CHREQ_REASON_PDCH:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_PDCH]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_PDCH));
 		break;
 	case GSM_CHREQ_REASON_OTHER:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_OTHER]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_OTHER));
 		break;
 	default:
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_ATTEMPTED_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_ATTEMPTED_UNKNOWN));
 		break;
 	}
 
@@ -1759,7 +1759,7 @@
 	if (!lchan) {
 		LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x\n",
 			gsm_lchant_name(lctype), rqd->ref.ra);
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_NO_CHANNEL]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_NO_CHANNEL));
 		rsl_tx_imm_ass_rej(bts, &rqd->ref);
 		llist_del(&rqd->entry);
 		talloc_free(rqd);
@@ -1821,7 +1821,7 @@
 	rc = rsl_imm_assign_cmd(bts, sizeof(*ia)+ia->mob_alloc_len, (uint8_t *) ia);
 
 	if (!rc)
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_SUCCESSFUL]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL));
 
 	return rc;
 }
@@ -1864,8 +1864,8 @@
 				busy_percent = 100;
 			}
 
-			osmo_stat_item_set(sd.bts->bts_statg->items[BTS_STAT_RACH_BUSY], busy_percent);
-			osmo_stat_item_set(sd.bts->bts_statg->items[BTS_STAT_RACH_ACCESS], access_percent);
+			osmo_stat_item_set(osmo_stat_item_group_get_item(sd.bts->bts_statg, BTS_STAT_RACH_BUSY), busy_percent);
+			osmo_stat_item_set(osmo_stat_item_group_get_item(sd.bts->bts_statg, BTS_STAT_RACH_ACCESS), access_percent);
 			/* dispatch signal */
 			osmo_signal_dispatch(SS_CCCH, S_CCCH_RACH_LOAD, &sd);
 		}
@@ -1952,7 +1952,7 @@
 	case RSL_MT_DELETE_IND:
 		/* CCCH overloaded, IMM_ASSIGN was dropped */
 		LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "DELETE INDICATION (Downlink CCCH overload)\n");
-		rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_RSL_DELETE_IND]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_RSL_DELETE_IND));
 		break;
 	case RSL_MT_CBCH_LOAD_IND:
 		/* current load on the CBCH */
@@ -1964,7 +1964,7 @@
 	default:
 		LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message type "
 			"0x%02x\n", rslh->c.msg_type);
-		rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 		return -EINVAL;
 	}
 
@@ -1988,7 +1988,7 @@
 
 	rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
 
-	rate_ctr_inc(&msg->lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_CHAN_RLL_ERR]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(msg->lchan->ts->trx->bts->bts_ctrs, BTS_CTR_CHAN_RLL_ERR));
 
 	osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RLL_ERR_IND, &rlm_cause);
 
@@ -2089,7 +2089,7 @@
 	default:
 		LOG_LCHAN(msg->lchan, LOGL_NOTICE, "SAPI=%u Unknown Abis RLL message type 0x%02x\n",
 			  sapi, rllh->c.msg_type);
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 	}
 	return rc;
 }
@@ -2348,7 +2348,7 @@
 	struct e1inp_sign_link *sign_link = msg->dst;
 	struct gsm_lchan *lchan = msg->lchan;
 
-	rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_IPA_NACK]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_IPA_NACK));
 
 	if (!lchan->fi_rtp) {
 		LOG_LCHAN(msg->lchan, LOGL_ERROR, "Rx RSL IPACC: CRCX NACK message for unconfigured lchan\n");
@@ -2386,7 +2386,7 @@
 	struct e1inp_sign_link *sign_link = msg->dst;
 	struct gsm_lchan *lchan = msg->lchan;
 
-	rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_IPA_NACK]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_IPA_NACK));
 
 	if (!lchan->fi_rtp) {
 		LOG_LCHAN(msg->lchan, LOGL_ERROR, "Rx RSL IPACC: MDCX NACK message for unconfigured lchan\n");
@@ -2455,7 +2455,7 @@
 	default:
 		LOG_LCHAN(msg->lchan, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x\n",
 			  rllh->c.msg_type);
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 		break;
 	}
 
@@ -2584,7 +2584,7 @@
 	default:
 		LOGP(DRSL, LOGL_NOTICE, "unknown RSL message discriminator "
 			"0x%02x\n", rslh->msg_discr);
-		rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_UNKNOWN]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(sign_link->trx->bts->bts_ctrs, BTS_CTR_RSL_UNKNOWN));
 		rc = -EINVAL;
 	}
 	msgb_free(msg);
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 0f38eec..6a9eb81 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -81,17 +81,17 @@
 		LOG_ASSIGNMENT(conn, LOGL_DEBUG, "incrementing rate counter: %s %s\n", \
 			       bsc_ctr_description[BSC_##counter].name, \
 			       bsc_ctr_description[BSC_##counter].description); \
-		rate_ctr_inc(&conn->network->bsc_ctrs->ctr[BSC_##counter]); \
+		rate_ctr_inc(rate_ctr_group_get_ctr(conn->network->bsc_ctrs, BSC_##counter)); \
 		if (bts) { \
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_##counter]); \
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_##counter)); \
 			switch (gsm48_chan_mode_to_non_vamos(conn->assignment.req.ch_mode_rate_list[0].chan_mode)) { \
 			case GSM48_CMODE_SIGN: \
-				rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_##counter##_SIGN]); \
+				rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_##counter##_SIGN)); \
 				break; \
 			case GSM48_CMODE_SPEECH_V1: \
 			case GSM48_CMODE_SPEECH_EFR: \
 			case GSM48_CMODE_SPEECH_AMR: \
-				rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_##counter##_SPEECH]); \
+				rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_##counter##_SPEECH)); \
 				break; \
 			default: \
 				break; \
@@ -140,7 +140,7 @@
 		if (!resp) {
 			LOG_ASSIGNMENT(conn, LOGL_ERROR, "Unable to compose BSSMAP Assignment Failure message\n");
 		} else {
-			rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_ASSIGMENT_FAILURE]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_ASSIGMENT_FAILURE));
 			gscon_sigtran_send(conn, resp);
 		}
 	}
@@ -230,7 +230,7 @@
 	    conn->assignment.req.use_osmux)
 		_gsm0808_ass_compl_extend_osmux(resp, osmux_cid);
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_ASSIGMENT_COMPLETE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_ASSIGMENT_COMPLETE));
 	rc = gscon_sigtran_send(conn, resp);
 	if (rc) {
 		assignment_fail(GSM0808_CAUSE_EQUIPMENT_FAILURE,
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index aa9d536..8b89e1a 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -161,7 +161,7 @@
 		return;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CLEAR_RQST]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLEAR_RQST));
 	rc = osmo_bsc_sigtran_send(conn, resp);
 	if (rc < 0)
 		LOGPFSML(conn->fi, LOGL_ERROR, "Unable to deliver BSSMAP Clear Request message\n");
@@ -176,7 +176,7 @@
 	OSMO_ASSERT(conn);
 
 	resp = gsm0808_create_dtap(msg, OBSC_LINKID_CB(msg));
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_DTAP]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_DTAP));
 	gscon_sigtran_send(conn, resp);
 }
 
@@ -843,7 +843,7 @@
 		/* Close MGCP connections */
 		osmo_mgcpc_ep_clear(conn->user_plane.mgw_endpoint);
 
-		rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CLEAR_COMPLETE]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLEAR_COMPLETE));
 		gscon_sigtran_send(conn, gsm0808_create_clear_complete());
 		break;
 	case GSCON_EV_A_DISC_IND:
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index 6f4e2ec..5b1f503 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -536,16 +536,16 @@
 	bts_dump_vty_cbch(vty, &bts->cbch_extended);
 
 	vty_out(vty, "  Channel Requests        : %"PRIu64" total, %"PRIu64" no channel%s",
-		bts->bts_ctrs->ctr[BTS_CTR_CHREQ_TOTAL].current,
-		bts->bts_ctrs->ctr[BTS_CTR_CHREQ_NO_CHANNEL].current,
+		rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_TOTAL)->current,
+		rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_NO_CHANNEL)->current,
 		VTY_NEWLINE);
 	vty_out(vty, "  Channel Failures        : %"PRIu64" rf_failures, %"PRIu64" rll failures%s",
-		bts->bts_ctrs->ctr[BTS_CTR_CHAN_RF_FAIL].current,
-		bts->bts_ctrs->ctr[BTS_CTR_CHAN_RLL_ERR].current,
+		rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHAN_RF_FAIL)->current,
+		rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHAN_RLL_ERR)->current,
 		VTY_NEWLINE);
 	vty_out(vty, "  BTS failures            : %"PRIu64" OML, %"PRIu64" RSL%s",
-		bts->bts_ctrs->ctr[BTS_CTR_BTS_OML_FAIL].current,
-		bts->bts_ctrs->ctr[BTS_CTR_BTS_RSL_FAIL].current,
+		rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_BTS_OML_FAIL)->current,
+		rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_BTS_RSL_FAIL)->current,
 		VTY_NEWLINE);
 
 	vty_out_stat_item_group(vty, "  ", bts->bts_statg);
@@ -2318,7 +2318,7 @@
 		/* allocate a new one */
 		bts = bsc_bts_alloc_register(gsmnet, GSM_BTS_TYPE_UNKNOWN,
 					     HARDCODED_BSIC);
-		osmo_stat_item_inc(gsmnet->bsc_statg->items[BSC_STAT_NUM_BTS_TOTAL], 1);
+		osmo_stat_item_inc(osmo_stat_item_group_get_item(gsmnet->bsc_statg, BSC_STAT_NUM_BTS_TOTAL), 1);
 	} else
 		bts = gsm_bts_num(gsmnet, bts_nr);
 
@@ -6390,7 +6390,7 @@
 		}
 	} else {
 		if (lchan->fi->state == LCHAN_ST_BORKEN) {
-			rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_VTY]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(lchan->ts->trx->bts->bts_ctrs, BTS_CTR_LCHAN_BORKEN_EV_VTY));
 			osmo_fsm_inst_state_chg(lchan->fi, LCHAN_ST_UNUSED, 0, 0);
 		} else {
 			vty_out(vty,
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index 857ddd2..bdaece7 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -558,7 +558,7 @@
 
 void bts_store_uptime(struct gsm_bts *bts)
 {
-	osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_UPTIME_SECONDS], bts_uptime(bts));
+	osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_UPTIME_SECONDS), bts_uptime(bts));
 }
 
 unsigned long long bts_uptime(const struct gsm_bts *bts)
diff --git a/src/osmo-bsc/bts_ipaccess_nanobts.c b/src/osmo-bsc/bts_ipaccess_nanobts.c
index 1e3e9c1..b97ae1c 100644
--- a/src/osmo-bsc/bts_ipaccess_nanobts.c
+++ b/src/osmo-bsc/bts_ipaccess_nanobts.c
@@ -531,7 +531,7 @@
 	LOG_TRX(trx, DLINP, LOGL_NOTICE, "Dropping RSL link: %s\n", reason);
 	e1inp_sign_link_destroy(trx->rsl_link_primary);
 	trx->rsl_link_primary = NULL;
-	osmo_stat_item_dec(trx->bts->bts_statg->items[BTS_STAT_RSL_CONNECTED], 1);
+	osmo_stat_item_dec(osmo_stat_item_group_get_item(trx->bts->bts_statg, BTS_STAT_RSL_CONNECTED), 1);
 
 	if (trx->bts->c0 == trx)
 		paging_flush_bts(trx->bts, NULL);
@@ -555,7 +555,7 @@
 	e1inp_sign_link_destroy(bts->oml_link);
 	bts->oml_link = NULL;
 	bts->uptime = 0;
-	osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_OML_CONNECTED], 1);
+	osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_OML_CONNECTED), 1);
 
 	/* we have issues reconnecting RSL, drop everything. */
 	llist_for_each_entry(trx, &bts->trx_list, list) {
@@ -631,7 +631,7 @@
 	/* Write to log and increase counter */
 	LOGP(DLINP, LOGL_ERROR, "Unable to find BTS configuration for %u/%u/%u, disconnecting\n", site_id, bts_id,
 		trx_id);
-	rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_UNKNOWN_UNIT_ID]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_UNKNOWN_UNIT_ID));
 
 	/* Get remote IP */
 	if (osmo_sock_get_remote_ip(ts->driver.ipaccess.fd.fd, ip, sizeof(ip)))
@@ -712,7 +712,7 @@
 					sign_link->tei, sign_link->sapi);
 			sign_link->trx->bts->ip_access.flags |= OML_UP;
 		}
-		osmo_stat_item_inc(bts->bts_statg->items[BTS_STAT_OML_CONNECTED], 1);
+		osmo_stat_item_inc(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_OML_CONNECTED), 1);
 		break;
 	case E1INP_SIGN_RSL: {
 		struct e1inp_ts *ts;
@@ -740,7 +740,7 @@
 			sign_link->trx->bts->ip_access.flags |=
 					(RSL_UP << sign_link->trx->nr);
 		}
-		osmo_stat_item_inc(bts->bts_statg->items[BTS_STAT_RSL_CONNECTED], 1);
+		osmo_stat_item_inc(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_RSL_CONNECTED), 1);
 		break;
 	}
 	default:
diff --git a/src/osmo-bsc/chan_alloc.c b/src/osmo-bsc/chan_alloc.c
index 402ca46..5915a93 100644
--- a/src/osmo-bsc/chan_alloc.c
+++ b/src/osmo-bsc/chan_alloc.c
@@ -121,36 +121,36 @@
 	case GSM_PCHAN_UNKNOWN:
 		break;
 	case GSM_PCHAN_CCCH_SDCCH4:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_CCCH_SDCCH4_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_CCCH_SDCCH4_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_CCCH_SDCCH4_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_CCCH_SDCCH4_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_TCH_F:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_F_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_F_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_F_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_F_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_TCH_H:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_H_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_H_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_H_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_H_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_SDCCH8_SACCH8C:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_SDCCH8_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_SDCCH8_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_SDCCH8_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_SDCCH8_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_TCH_F_PDCH:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_F_PDCH_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_F_PDCH_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_F_PDCH_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_F_PDCH_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_CCCH_SDCCH4_CBCH:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_CCCH_SDCCH4_CBCH_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_CCCH_SDCCH4_CBCH_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_CCCH_SDCCH4_CBCH_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_CCCH_SDCCH4_CBCH_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_SDCCH8_CBCH_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_SDCCH8_CBCH_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_SDCCH8_CBCH_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_SDCCH8_CBCH_TOTAL), lc->total);
 		break;
 	case GSM_PCHAN_TCH_F_TCH_H_PDCH:
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_F_TCH_H_PDCH_USED], lc->used);
-		osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_TCH_F_TCH_H_PDCH_TOTAL], lc->total);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_F_TCH_H_PDCH_USED), lc->used);
+		osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_TCH_F_TCH_H_PDCH_TOTAL), lc->total);
 		break;
 	default:
 		LOG_BTS(bts, DRLL, LOGL_NOTICE, "Unknown channel type %d\n", pchan);
@@ -232,7 +232,7 @@
 		(load & 0xffffff00) >> 8, (load & 0xff) / 10);
 	bts->chan_load_avg = ((load & 0xffffff00) >> 8);
 	OSMO_ASSERT(bts->chan_load_avg <= 100);
-	osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_LOAD_AVERAGE], bts->chan_load_avg);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_CHAN_LOAD_AVERAGE), bts->chan_load_avg);
 
 	/* Calculate new T3122 wait indicator. */
 	wait_ind = ((used / total) * max_wait_ind);
@@ -244,5 +244,5 @@
 
 	LOG_BTS(bts, DRLL, LOGL_DEBUG, "T3122 wait indicator set to %"PRIu64" seconds\n", wait_ind);
 	bts->T3122 = (uint8_t)wait_ind;
-	osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_T3122], wait_ind);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_T3122), wait_ind);
 }
diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c
index e943ec1..80ed874 100644
--- a/src/osmo-bsc/gsm_08_08.c
+++ b/src/osmo-bsc/gsm_08_08.c
@@ -77,7 +77,7 @@
 	LOGP(DMSC, LOGL_NOTICE, "Tx MSC SAPI N REJECT (dlci=0x%02x, cause='%s')\n",
 	     dlci, gsm0808_cause_name(cause));
 	resp = gsm0808_create_sapi_reject_cause(dlci, cause);
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_SAPI_N_REJECT]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_SAPI_N_REJECT));
 	rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
 	if (rc != 0)
 		msgb_free(resp);
@@ -94,7 +94,7 @@
 
 	LOGP(DMSC, LOGL_DEBUG, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
 	resp = gsm0808_create_cipher_complete(msg, chosen_encr);
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CIPHER_COMPLETE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CIPHER_COMPLETE));
 	rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
 	if (rc != 0)
 		msgb_free(resp);
@@ -233,7 +233,7 @@
 			if (nri_matches_msc) {
 				LOG_NRI(LOGL_DEBUG, "matches msc %d, but this MSC is currently not connected\n",
 					msc->nr);
-				rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_ATTACH_LOST]);
+				rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_ATTACH_LOST));
 			}
 			continue;
 		}
@@ -245,10 +245,10 @@
 					msc->nr);
 			} else {
 				LOG_NRI(LOGL_DEBUG, "matches msc %d\n", msc->nr);
-				rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_KNOWN]);
+				rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_KNOWN));
 				if (is_emerg) {
-					rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_EMERG_FORWARDED]);
-					rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_EMERG_FORWARDED]);
+					rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_MSCPOOL_EMERG_FORWARDED));
+					rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_EMERG_FORWARDED));
 				}
 				return msc;
 			}
@@ -283,9 +283,9 @@
 	 * them are usable -- wrap to the start. */
 	msc_target = msc_round_robin_next ? : msc_round_robin_first;
 	if (!msc_target) {
-		rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_SUBSCR_NO_MSC]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_SUBSCR_NO_MSC));
 		if (is_emerg)
-			rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_EMERG_LOST]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_EMERG_LOST));
 		return NULL;
 	}
 
@@ -293,13 +293,13 @@
 	     osmo_mobile_identity_to_str_c(OTC_SELECT, mi), msc_target->nr);
 
 	if (is_null_nri)
-		rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_REATTACH]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc_target->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_REATTACH));
 	else
-		rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_NEW]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc_target->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_NEW));
 
 	if (is_emerg) {
-		rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_EMERG_FORWARDED]);
-		rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_EMERG_FORWARDED]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc_target->msc_ctrs, MSC_CTR_MSCPOOL_EMERG_FORWARDED));
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_EMERG_FORWARDED));
 	}
 
 	/* An MSC was picked by round-robin, so update the next round-robin nr to pick */
@@ -457,12 +457,12 @@
 				     "%s Unsolicited Paging Response, possibly an MT-CSFB call.\n",
 				     osmo_mobile_identity_to_str_c(OTC_SELECT, &mi));
 
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_NO_ACTIVE_PAGING]);
-			rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_PAGING_NO_ACTIVE_PAGING]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_NO_ACTIVE_PAGING));
+			rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_PAGING_NO_ACTIVE_PAGING));
 		} else if (is_msc_usable(paged_from_msc, is_emerg)) {
 			LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG, "%s matches earlier Paging from msc %d\n",
 				     osmo_mobile_identity_to_str_c(OTC_SELECT, &mi), paged_from_msc->nr);
-			rate_ctr_inc(&paged_from_msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_PAGED]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(paged_from_msc->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_PAGED));
 		} else {
 			LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG,
 				     "%s matches earlier Paging from msc %d, but this MSC is not connected\n",
@@ -617,7 +617,7 @@
 	if (!msc_connected(conn))
 		return;
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CLASSMARK_UPDATE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLASSMARK_UPDATE));
 	resp = gsm0808_create_classmark_update(cm2, cm2_len, cm3, cm3_len);
 	rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
 	if (rc != 0)
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index ec70be3..8141a5d 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -88,7 +88,7 @@
 		LOG_HO(conn, LOGL_DEBUG, "(BSC) incrementing rate counter: %s %s\n", \
 		       bsc_ctr_description[counter].name, \
 		       bsc_ctr_description[counter].description); \
-		rate_ctr_inc(&conn->network->bsc_ctrs->ctr[counter]); \
+		rate_ctr_inc(rate_ctr_group_get_ctr(conn->network->bsc_ctrs, counter)); \
 	} while(0)
 
 /* Assume presence of local var 'conn' as struct gsm_subscriber_connection.
@@ -102,9 +102,9 @@
 		       bts_ctr_description[counter].name, \
 		       bts_ctr_description[counter].description); \
 		if (bts) \
-			rate_ctr_inc(&bts->bts_ctrs->ctr[counter]); \
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, counter)); \
 		else \
-			rate_ctr_inc(&conn->network->bts_unknown_ctrs->ctr[counter]); \
+			rate_ctr_inc(rate_ctr_group_get_ctr(conn->network->bts_unknown_ctrs, counter)); \
 	} while(0)
 
 #define ho_count(bts, counter) do { \
@@ -881,7 +881,7 @@
 		return;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_HANDOVER_PERFORMED]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_HANDOVER_PERFORMED));
 	rc = gscon_sigtran_send(conn, msg);
 	if (rc < 0) {
 		LOG_HO(conn, LOGL_ERROR, "message sending failed, can't send HANDOVER PERFORMED!\n");
diff --git a/src/osmo-bsc/lb.c b/src/osmo-bsc/lb.c
index e23de93..7c35fa2 100644
--- a/src/osmo-bsc/lb.c
+++ b/src/osmo-bsc/lb.c
@@ -68,7 +68,7 @@
 	LOGP(DRESET, LOGL_INFO, "Sending RESET to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));
 	msg = osmo_bssap_le_enc(&reset);
 
-	rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_UDT_RESET]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_UDT_RESET));
 	return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc->sccp_user, &bsc_gsmnet->smlc->bsc_addr,
 					 &bsc_gsmnet->smlc->smlc_addr, msg);
 }
@@ -90,7 +90,7 @@
 	LOGP(DRESET, LOGL_NOTICE, "Sending RESET ACK to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));
 	msg = osmo_bssap_le_enc(&reset_ack);
 
-	rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK));
 	return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc->sccp_user, &bsc_gsmnet->smlc->bsc_addr,
 					 &bsc_gsmnet->smlc->smlc_addr, msg);
 }
@@ -101,7 +101,7 @@
 	struct osmo_ss7_instance *ss7;
 	struct bssap_le_pdu bssap_le;
 	struct osmo_bssap_le_err *err;
-	struct rate_ctr *ctr = bsc_gsmnet->smlc->ctrs->ctr;
+	struct rate_ctr_group *ctrg = bsc_gsmnet->smlc->ctrs;
 
 	ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu));
 	OSMO_ASSERT(ss7);
@@ -109,13 +109,13 @@
 	if (osmo_sccp_addr_cmp(smlc_addr, &bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_ADDR_T_MASK)) {
 		LOGP(DLCS, LOGL_ERROR, "Rx BSSMAP-LE UnitData from unknown remote address: %s\n",
 		     osmo_sccp_addr_name(ss7, smlc_addr));
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER));
 		return -EINVAL;
 	}
 
 	if (osmo_bssap_le_dec(&bssap_le, &err, msg, msg)) {
 		LOGP(DLCS, LOGL_ERROR, "Rx BSSAP-LE UnitData with error: %s\n", err->logmsg);
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG));
 		return -EINVAL;
 	}
 
@@ -126,17 +126,17 @@
 
 	switch (bssap_le.bssmap_le.msg_type) {
 	case BSSMAP_LE_MSGT_RESET:
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_RESET]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_RESET));
 		LOGP(DLCS, LOGL_NOTICE, "RESET from SMLC: %s\n", osmo_sccp_addr_name(ss7, smlc_addr));
 		return osmo_fsm_inst_dispatch(bsc_gsmnet->smlc->bssmap_reset->fi, BSSMAP_RESET_EV_RX_RESET, NULL);
 
 	case BSSMAP_LE_MSGT_RESET_ACK:
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK));
 		LOGP(DLCS, LOGL_NOTICE, "RESET-ACK from SMLC: %s\n", osmo_sccp_addr_name(ss7, smlc_addr));
 		return osmo_fsm_inst_dispatch(bsc_gsmnet->smlc->bssmap_reset->fi, BSSMAP_RESET_EV_RX_RESET_ACK, NULL);
 
 	default:
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG));
 		LOGP(DLCS, LOGL_ERROR, "Rx unimplemented UDT message type %s\n",
 		     osmo_bssap_le_pdu_to_str_c(OTC_SELECT, &bssap_le));
 		return -EINVAL;
@@ -255,9 +255,9 @@
 	rc = osmo_sccp_tx_conn_req_msg(bsc_gsmnet->smlc->sccp_user, conn_id, &bsc_gsmnet->smlc->bsc_addr,
 				       &bsc_gsmnet->smlc->smlc_addr, msg);
 	if (rc >= 0)
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_SUCCESS]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_SUCCESS));
 	else
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_ERR_SEND]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_ERR_SEND));
 	if (rc >= 0)
 		conn->lcs.lb.state = SUBSCR_SCCP_ST_WAIT_CONN_CONF;
 
@@ -304,9 +304,9 @@
 	LOGPFSMSL(conn->fi, DLCS, LOGL_DEBUG, "Tx %s\n", osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));
 	rc = osmo_sccp_tx_data_msg(bsc_gsmnet->smlc->sccp_user, conn->lcs.lb.conn_id, msg);
 	if (rc >= 0)
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_SUCCESS]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_SUCCESS));
 	else
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_ERR_SEND]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_ERR_SEND));
 
 count_tx:
 	if (rc < 0)
@@ -314,24 +314,24 @@
 
 	switch (bssap_le->bssmap_le.msg_type) {
 	case BSSMAP_LE_MSGT_PERFORM_LOC_REQ:
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST));
 		break;
 	case BSSMAP_LE_MSGT_PERFORM_LOC_ABORT:
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT));
 		break;
 	case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:
 		switch (bssap_le->bssmap_le.conn_oriented_info.apdu.msg_type) {
 		case BSSLAP_MSGT_TA_RESPONSE:
-			rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE));
 			break;
 		case BSSLAP_MSGT_REJECT:
-			rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT));
 			break;
 		case BSSLAP_MSGT_RESET:
-			rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET));
 			break;
 		case BSSLAP_MSGT_ABORT:
-			rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT));
 			break;
 		default:
 			break;
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index a29ddae..48cfbdf 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -1323,9 +1323,9 @@
 	default:
 		ctr = BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN;
 	}
-	rate_ctr_inc(&bts->bts_ctrs->ctr[ctr]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, ctr));
 	if (prev_state != LCHAN_ST_BORKEN)
-		osmo_stat_item_inc(bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1);
+		osmo_stat_item_inc(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_LCHAN_BORKEN), 1);
 
 	/* The actual action besides all the beancounting above */
 	lchan_reset(lchan);
@@ -1339,8 +1339,8 @@
 
 	case LCHAN_EV_RSL_CHAN_ACTIV_ACK:
 		/* A late Chan Activ ACK? Release. */
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK]);
-		osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK));
+		osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_LCHAN_BORKEN), 1);
 		lchan->release.in_error = true;
 		lchan->release.rsl_error_cause = RSL_ERR_INTERWORKING;
 		lchan->release.rr_cause = bsc_gsm48_rr_cause_from_rsl_cause(lchan->release.rsl_error_cause);
@@ -1349,15 +1349,15 @@
 
 	case LCHAN_EV_RSL_CHAN_ACTIV_NACK:
 		/* A late Chan Activ NACK? Ok then, unused. */
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK]);
-		osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK));
+		osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_LCHAN_BORKEN), 1);
 		lchan_fsm_state_chg(LCHAN_ST_UNUSED);
 		return;
 
 	case LCHAN_EV_RSL_RF_CHAN_REL_ACK:
 		/* A late Release ACK? */
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK]);
-		osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK));
+		osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_LCHAN_BORKEN), 1);
 		lchan->release.in_error = true;
 		lchan->release.rsl_error_cause = RSL_ERR_INTERWORKING;
 		lchan->release.rr_cause = bsc_gsm48_rr_cause_from_rsl_cause(lchan->release.rsl_error_cause);
@@ -1603,8 +1603,8 @@
 	{
 		struct gsm_lchan *lchan = lchan_fi_lchan(fi);
 		if (fi->state == LCHAN_ST_BORKEN) {
-			rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_TS_ERROR]);
-			osmo_stat_item_dec(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1);
+			rate_ctr_inc(rate_ctr_group_get_ctr(lchan->ts->trx->bts->bts_ctrs, BTS_CTR_LCHAN_BORKEN_EV_TS_ERROR));
+			osmo_stat_item_dec(osmo_stat_item_group_get_item(lchan->ts->trx->bts->bts_statg, BTS_STAT_LCHAN_BORKEN), 1);
 		}
 		lchan_fail_to(LCHAN_ST_UNUSED, "LCHAN_EV_TS_ERROR");
 		return;
@@ -1713,8 +1713,8 @@
 {
 	struct gsm_lchan *lchan = lchan_fi_lchan(fi);
 	if (lchan->fi->state == LCHAN_ST_BORKEN) {
-		rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_TEARDOWN]);
-		osmo_stat_item_dec(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1);
+		rate_ctr_inc(rate_ctr_group_get_ctr(lchan->ts->trx->bts->bts_ctrs, BTS_CTR_LCHAN_BORKEN_EV_TEARDOWN));
+		osmo_stat_item_dec(osmo_stat_item_group_get_item(lchan->ts->trx->bts->bts_statg, BTS_STAT_LCHAN_BORKEN), 1);
 	}
 	lchan_reset(lchan);
 	if (lchan->last_error) {
diff --git a/src/osmo-bsc/lcs_loc_req.c b/src/osmo-bsc/lcs_loc_req.c
index ee85c91..1a68316 100644
--- a/src/osmo-bsc/lcs_loc_req.c
+++ b/src/osmo-bsc/lcs_loc_req.c
@@ -190,7 +190,7 @@
 {
 	switch (bssmap_le->conn_oriented_info.apdu.msg_type) {
 	case BSSLAP_MSGT_TA_REQUEST:
-		rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST));
 		LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_DEBUG, "rx BSSLAP TA Request\n");
 		/* The TA Request message contains only the message type. */
 		return lcs_ta_req_start(lcs_loc_req);
@@ -206,7 +206,7 @@
 	struct lcs_loc_req *lcs_loc_req = conn->lcs.loc_req;
 	struct bssap_le_pdu bssap_le;
 	struct osmo_bssap_le_err *err;
-	struct rate_ctr *ctr = bsc_gsmnet->smlc->ctrs->ctr;
+	struct rate_ctr_group *ctrg = bsc_gsmnet->smlc->ctrs;
 
 	if (!lcs_loc_req) {
 		LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR,
@@ -216,13 +216,13 @@
 
 	if (osmo_bssap_le_dec(&bssap_le, &err, msg, msg)) {
 		LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Rx BSSAP-LE message with error: %s\n", err->logmsg);
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG));
 		return -EINVAL;
 	}
 
 	if (bssap_le.discr != BSSAP_LE_MSG_DISCR_BSSMAP_LE) {
 		LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Rx BSSAP-LE: discr %d not implemented\n", bssap_le.discr);
-		rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG));
 		return -ENOTSUP;
 	}
 
@@ -231,9 +231,9 @@
 	switch (bssap_le.bssmap_le.msg_type) {
 	case BSSMAP_LE_MSGT_PERFORM_LOC_RESP:
 		if (bssap_le.bssmap_le.perform_loc_resp.location_estimate_present)
-			rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS));
 		else
-			rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE));
 		return osmo_fsm_inst_dispatch(lcs_loc_req->fi, LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE,
 					      &bssap_le.bssmap_le);
 
@@ -457,9 +457,7 @@
 			LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,
 					"Failed to send Perform Location Response (A-interface)\n");
 		else
-			rate_ctr_inc(&lcs_loc_req->conn->sccp.msc->msc_ctrs->ctr[
-				plr.location_estimate_present ? MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS
-				: MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(lcs_loc_req->conn->sccp.msc->msc_ctrs, plr.location_estimate_present ? MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS : MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE));
 	}
 	osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
 }
@@ -498,7 +496,7 @@
 			LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,
 					"Failed to send BSSMAP Perform Location Response (A-interface)\n");
 		else
-			rate_ctr_inc(&lcs_loc_req->conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(lcs_loc_req->conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE));
 	}
 	osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
 }
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 239c2ca..d6048bf 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -343,7 +343,7 @@
 
 int bsc_paging_start(struct bsc_paging_params *params)
 {
-	rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_PAGING_ATTEMPTED));
 
 	if (!params->bsub) {
 		params->bsub = bsc_subscr_find_or_create_by_imsi(bsc_gsmnet->bsc_subscribers, params->imsi.imsi,
@@ -569,7 +569,7 @@
 		return -1;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CIPHER_REJECT]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CIPHER_REJECT));
 	osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
 	return -1;
 }
@@ -650,7 +650,7 @@
 	LOGPFSM(conn->fi, "Tx LCLS CONNECT CTRL ACK (%s)\n",
 		gsm0808_lcls_status_name(lcls_get_status(conn)));
 	resp = gsm0808_create_lcls_conn_ctrl_ack(lcls_get_status(conn));
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_LCLS_CONNECT_CTRL_ACK]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_LCLS_CONNECT_CTRL_ACK));
 	osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
 
 	return 0;
@@ -973,7 +973,7 @@
 	resp = gsm0808_create_assignment_failure(cause, NULL);
 	OSMO_ASSERT(resp);
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_ASSIGMENT_FAILURE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_ASSIGMENT_FAILURE));
 	osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
 	return -1;
 }
@@ -1396,7 +1396,7 @@
 		return -EINVAL;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_HANDOVER_REQUIRED]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_HANDOVER_REQUIRED));
 	rc = gscon_sigtran_send(conn, msg);
 	if (rc) {
 		LOG_HO(conn, LOGL_ERROR, "Cannot send BSSMAP Handover Required message\n");
@@ -1443,7 +1443,7 @@
 		params.aoip_transport_layer = &ss;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_HANDOVER_RQST_ACKNOWLEDGE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_HANDOVER_RQST_ACKNOWLEDGE));
 	LOG_HO(conn, LOGL_DEBUG, "Sending BSSMAP Handover Request Acknowledge\n");
 	msg = gsm0808_create_handover_request_ack2(&params);
 	msgb_free(rr_ho_command);
@@ -1459,7 +1459,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_HANDOVER_DETECT]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_HANDOVER_DETECT));
 	return osmo_bsc_sigtran_send(conn, msg);
 }
 
@@ -1499,7 +1499,7 @@
 		return HO_RESULT_ERROR;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_HANDOVER_COMPLETE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_HANDOVER_COMPLETE));
 	rc = osmo_bsc_sigtran_send(conn, msg);
 	if (rc) {
 		LOG_HO(conn, LOGL_ERROR, "Cannot send BSSMAP Handover Complete message\n");
@@ -1521,7 +1521,7 @@
 		return;
 	}
 
-	rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_HANDOVER_FAILURE]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_HANDOVER_FAILURE));
 	rc = osmo_bsc_sigtran_send(conn, msg);
 	if (rc)
 		LOG_HO(conn, LOGL_ERROR, "Cannot send BSSMAP Handover Failure message (rc=%d %s)\n",
diff --git a/src/osmo-bsc/osmo_bsc_filter.c b/src/osmo-bsc/osmo_bsc_filter.c
index 19cdeee..2b58ccf 100644
--- a/src/osmo-bsc/osmo_bsc_filter.c
+++ b/src/osmo-bsc/osmo_bsc_filter.c
@@ -123,16 +123,16 @@
 		struct rate_ctr_group *bts_ctrs = conn->lchan->ts->trx->bts->bts_ctrs;
 		switch (mtype) {
 		case GSM48_MT_MM_LOC_UPD_ACCEPT:
-			rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_LOCATION_UPDATE_ACCEPT]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_LOCATION_UPDATE_ACCEPT));
 			break;
 		case GSM48_MT_MM_LOC_UPD_REJECT:
-			rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_LOCATION_UPDATE_REJECT]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_LOCATION_UPDATE_REJECT));
 			break;
 		case GSM48_MT_MM_IMSI_DETACH_IND:
-			rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_LOCATION_UPDATE_DETACH]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_LOCATION_UPDATE_DETACH));
 			break;
 		default:
-			rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_LOCATION_UPDATE_UNKNOWN]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_LOCATION_UPDATE_UNKNOWN));
 			break;
 		}
 	}
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
index 3069cc0..14475ff 100644
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ b/src/osmo-bsc/osmo_bsc_main.c
@@ -405,10 +405,10 @@
 		LOG_TRX(trx, DLMI, LOGL_ERROR, "Lost E1 %s link\n", e1inp_signtype_name(isd->link_type));
 
 		if (isd->link_type == E1INP_SIGN_OML) {
-			rate_ctr_inc(&trx->bts->bts_ctrs->ctr[BTS_CTR_BTS_OML_FAIL]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(trx->bts->bts_ctrs, BTS_CTR_BTS_OML_FAIL));
 			all_ts_dispatch_event(trx, TS_EV_OML_DOWN);
 		} else if (isd->link_type == E1INP_SIGN_RSL) {
-			rate_ctr_inc(&trx->bts->bts_ctrs->ctr[BTS_CTR_BTS_RSL_FAIL]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(trx->bts->bts_ctrs, BTS_CTR_BTS_RSL_FAIL));
 			acc_ramp_abort(&trx->bts->acc_ramp);
 			all_ts_dispatch_event(trx, TS_EV_RSL_DOWN);
 			if (trx->nr == 0)
diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c
index 2cb7694..d3c636d 100644
--- a/src/osmo-bsc/osmo_bsc_sigtran.c
+++ b/src/osmo-bsc/osmo_bsc_sigtran.c
@@ -94,7 +94,7 @@
 	if (msc_is_aoip(msc) && msc->use_osmux != OSMUX_USAGE_OFF)
 		_gsm0808_extend_announce_osmux(msg);
 
-	rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_UDT_RESET]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_UDT_RESET));
 	osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
 				  &msc->a.msc_addr, msg);
 }
@@ -114,7 +114,7 @@
 	if (msc_is_aoip(msc) && msc->use_osmux != OSMUX_USAGE_OFF)
 		_gsm0808_extend_announce_osmux(msg);
 
-	rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_UDT_RESET_ACK]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_UDT_RESET_ACK));
 	osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
 				  &msc->a.msc_addr, msg);
 }
@@ -374,26 +374,26 @@
 	if (msg->len >= 3) {
 		switch (msg->data[0]) {
 		case BSSAP_MSG_BSS_MANAGEMENT:
-			rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_BSS_MANAGEMENT]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_BSS_MANAGEMENT));
 			LOGP(DMSC, LOGL_INFO, "Tx MSC: BSSMAP: %s\n",
 			     gsm0808_bssmap_name(msg->data[2]));
 			break;
 		case BSSAP_MSG_DTAP:
-			rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DTAP]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DTAP));
 			LOGP(DMSC, LOGL_INFO, "Tx MSC: DTAP\n");
 			break;
 		default:
-			rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_UNKNOWN]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_UNKNOWN));
 			LOGP(DMSC, LOGL_ERROR, "Tx MSC: unknown message type: 0x%x\n",
 			     msg->data[0]);
 		}
 	} else {
-		rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_SHORT]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_SHORT));
 		LOGP(DMSC, LOGL_ERROR, "Tx MSC: message too short: %u\n", msg->len);
 	}
 
 	if (a_reset_conn_ready(msc) == false) {
-		rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_ERR_CONN_NOT_READY]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_ERR_CONN_NOT_READY));
 		LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
 		msgb_free(msg);
 		return -EINVAL;
@@ -408,9 +408,9 @@
 
 	rc = osmo_sccp_tx_data_msg(msc->a.sccp_user, conn_id, msg);
 	if (rc >= 0)
-		rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_SUCCESS]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_SUCCESS));
 	else
-		rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_ERR_SEND]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_BSSMAP_TX_ERR_SEND));
 
 	return rc;
 }
diff --git a/src/osmo-bsc/paging.c b/src/osmo-bsc/paging.c
index 15aca00..d2dd5ea 100644
--- a/src/osmo-bsc/paging.c
+++ b/src/osmo-bsc/paging.c
@@ -281,7 +281,7 @@
 	     req, bsc_subscr_name(req->bsub));
 
 	/* must be destroyed before calling cbfn, to prevent double free */
-	rate_ctr_inc(&req->bts->bts_ctrs->ctr[BTS_CTR_PAGING_EXPIRED]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(req->bts->bts_ctrs, BTS_CTR_PAGING_EXPIRED));
 
 	/* destroy it now. Do not access req afterwards */
 	paging_remove_request(&req->bts->paging, req);
@@ -331,11 +331,11 @@
 	struct gsm_paging_request *req;
 	unsigned int t3113_timeout_s;
 
-	rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_ATTEMPTED]);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_ATTEMPTED));
 
 	if (paging_pending_request(bts_entry, params->bsub)) {
 		LOG_PAGING_BTS(params, bts, DPAG, LOGL_INFO, "Paging request already pending for this subscriber\n");
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_ALREADY]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_ALREADY));
 		return -EEXIST;
 	}
 
@@ -432,8 +432,8 @@
 	count = paging_request_stop_bts(&paged_from_msc, &reasons, bts, bsub);
 	if (paged_from_msc) {
 		count++;
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_RESPONDED]);
-		rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_RESPONDED]);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_RESPONDED));
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->network->bsc_ctrs, BSC_CTR_PAGING_RESPONDED));
 	}
 
 	llist_for_each_entry(bts_i, &bsc_gsmnet->bts_list, list) {
@@ -522,7 +522,7 @@
 		num_cancelled++;
 	}
 
-	rate_ctr_add(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_MSC_FLUSH], num_cancelled);
+	rate_ctr_add(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_MSC_FLUSH), num_cancelled);
 }
 
 /*! Flush all paging requests issued by \a msc on any BTS in \a net */
diff --git a/src/osmo-bsc/timeslot_fsm.c b/src/osmo-bsc/timeslot_fsm.c
index 001319e..0470972 100644
--- a/src/osmo-bsc/timeslot_fsm.c
+++ b/src/osmo-bsc/timeslot_fsm.c
@@ -383,9 +383,9 @@
 
 	case TS_EV_PDCH_ACT_NACK:
 		if (ts->pchan_on_init == GSM_PCHAN_TCH_F_PDCH)
-			rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_RSL_IPA_NACK]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_RSL_IPA_NACK));
 		else
-			rate_ctr_inc(&bts_ctrs->ctr[BTS_CTR_CHAN_ACT_NACK]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts_ctrs, BTS_CTR_CHAN_ACT_NACK));
 		ts->pdch_act_allowed = false;
 		ts_fsm_error(fi, TS_ST_UNUSED, "Received PDCH activation NACK");
 		return;
@@ -520,7 +520,7 @@
 
 	case TS_EV_PDCH_DEACT_NACK:
 		if (ts->pchan_on_init == GSM_PCHAN_TCH_F_PDCH)
-			rate_ctr_inc(&ts->trx->bts->bts_ctrs->ctr[BTS_CTR_RSL_IPA_NACK]);
+			rate_ctr_inc(rate_ctr_group_get_ctr(ts->trx->bts->bts_ctrs, BTS_CTR_RSL_IPA_NACK));
 		/* For Osmocom style dyn TS, there actually is no NACK, since there is no RF Channel
 		 * Release NACK message in RSL. */
 		ts_fsm_error(fi, TS_ST_BORKEN, "Received PDCH deactivation NACK");
@@ -695,8 +695,8 @@
 	default:
 		ctr = BTS_CTR_TS_BORKEN_FROM_UNKNOWN;
 	}
-	rate_ctr_inc(&bts->bts_ctrs->ctr[ctr]);
-	osmo_stat_item_inc(bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1);
+	rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, ctr));
+	osmo_stat_item_inc(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_TS_BORKEN), 1);
 }
 
 static void ts_fsm_borken(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -720,8 +720,8 @@
 			struct gsm_bts *bts = ts->trx->bts;
 			/* Late PDCH activation ACK/NACK is not a crime.
 			 * Just process them as normal. */
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_TS_BORKEN_EV_PDCH_ACT_ACK_NACK]);
-			osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_TS_BORKEN_EV_PDCH_ACT_ACK_NACK));
+			osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_TS_BORKEN), 1);
 			ts_fsm_wait_pdch_act(fi, event, data);
 			return;
 		}
@@ -733,8 +733,8 @@
 			struct gsm_bts *bts = ts->trx->bts;
 			/* Late PDCH deactivation ACK/NACK is also not a crime.
 			 * Just process them as normal. */
-			rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_TS_BORKEN_EV_PDCH_DEACT_ACK_NACK]);
-			osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1);
+			rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_TS_BORKEN_EV_PDCH_DEACT_ACK_NACK));
+			osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_TS_BORKEN), 1);
 			ts_fsm_wait_pdch_deact(fi, event, data);
 			return;
 		}
@@ -796,8 +796,8 @@
 	struct gsm_bts_trx_ts *ts = ts_fi_ts(fi);
 	struct gsm_bts *bts = ts->trx->bts;
 	if (ts->fi->state == TS_ST_BORKEN) {
-		rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_TS_BORKEN_EV_TEARDOWN]);
-		osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1);
+		rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_TS_BORKEN_EV_TEARDOWN));
+		osmo_stat_item_dec(osmo_stat_item_group_get_item(bts->bts_statg, BTS_STAT_TS_BORKEN), 1);
 	}
 }
 

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/24551
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I0b43f922a595d694ac0aeda80107ef9bf4e755e7
Gerrit-Change-Number: 24551
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210604/6e8bcbc5/attachment.htm>


More information about the gerrit-log mailing list