blob: abf38838a51af48433d4215e876af29c597577cf [file] [log] [blame]
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* rate-counter implementation */
3
4/*
5 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 by On-Waves
7 * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
Erica94c56e2021-09-07 00:10:31 +020025#include <stdatomic.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020026#include <errno.h>
27#include <osmocom/core/stats.h>
Philipp Maier124a3e02021-07-26 11:17:15 +020028#include <osmocom/core/stat_item.h>
Philipp Maier993ea6b2020-08-04 18:26:50 +020029#include <osmocom/mgcp/mgcp_conn.h>
Philipp Maiera065e632021-07-09 13:22:42 +020030#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maier124a3e02021-07-26 11:17:15 +020031#include <osmocom/mgcp/mgcp_protocol.h>
32#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020033#include <osmocom/mgcp/mgcp_ratectr.h>
34
35static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
36 /* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
37 [MGCP_GENERAL_RX_MSGS_TOTAL] = { "mgcp:rx_msgs", "total number of MGCP messages received." },
38 [MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = { "mgcp:rx_msgs_retransmitted", "number of received retransmissions." },
39 [MGCP_GENERAL_RX_MSGS_HANDLED] = { "mgcp:rx_msgs_handled", "number of handled MGCP messages." },
40 [MGCP_GENERAL_RX_MSGS_UNHANDLED] = { "mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages." },
41 [MGCP_GENERAL_RX_FAIL_MSG_PARSE] = { "mgcp:err_rx_msg_parse", "error parsing MGCP message." },
42 [MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] =
43 { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
44};
45
Pau Espin Pedrol663ba5c2022-09-22 21:43:31 +020046static const struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
Philipp Maierc66ab2c2020-06-02 20:55:34 +020047 .group_name_prefix = "mgcp",
48 .group_description = "mgcp general statistics",
49 .class_id = OSMO_STATS_CLASS_GLOBAL,
50 .num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
51 .ctr_desc = mgcp_general_ctr_desc
52};
53
54static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
55 [MGCP_CRCX_SUCCESS] = { "crcx:success", "CRCX command processed successfully." },
56 [MGCP_CRCX_FAIL_BAD_ACTION] = { "crcx:bad_action", "bad action in CRCX command." },
57 [MGCP_CRCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in CRCX command." },
58 [MGCP_CRCX_FAIL_MISSING_CALLID] = { "crcx:missing_callid", "missing CallId in CRCX command." },
59 [MGCP_CRCX_FAIL_INVALID_MODE] = { "crcx:invalid_mode", "invalid connection mode in CRCX command." },
60 [MGCP_CRCX_FAIL_LIMIT_EXCEEDED] = { "crcx:limit_exceeded", "limit of concurrent connections was reached." },
61 [MGCP_CRCX_FAIL_UNKNOWN_CALLID] = { "crcx:unkown_callid", "unknown CallId in CRCX command." },
62 [MGCP_CRCX_FAIL_ALLOC_CONN] = { "crcx:alloc_conn_fail", "connection allocation failure." },
63 [MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
64 { "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
65 [MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
Philipp Maierc66ab2c2020-06-02 20:55:34 +020066 [MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
67 [MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
68 [MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
69 [MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." },
Philipp Maier8d6a1932020-06-18 12:19:31 +020070 [MGCP_CRCX_FAIL_AVAIL] = { "crcx:unavailable", "endpoint unavailable." },
Philipp Maier889fe7f2020-07-06 17:44:12 +020071 [MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
Philipp Maierc66ab2c2020-06-02 20:55:34 +020072};
73
Pau Espin Pedrol663ba5c2022-09-22 21:43:31 +020074static const struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
Philipp Maierc66ab2c2020-06-02 20:55:34 +020075 .group_name_prefix = "crcx",
76 .group_description = "crxc statistics",
77 .class_id = OSMO_STATS_CLASS_GLOBAL,
78 .num_ctr = ARRAY_SIZE(mgcp_crcx_ctr_desc),
79 .ctr_desc = mgcp_crcx_ctr_desc
80};
81
82static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
83 [MGCP_MDCX_SUCCESS] = { "mdcx:success", "MDCX command processed successfully." },
84 [MGCP_MDCX_FAIL_WILDCARD] = { "mdcx:wildcard", "wildcard endpoint names in MDCX commands are unsupported." },
85 [MGCP_MDCX_FAIL_NO_CONN] = { "mdcx:no_conn", "endpoint specified in MDCX command has no active connections." },
86 [MGCP_MDCX_FAIL_INVALID_CALLID] = { "mdcx:callid", "invalid CallId specified in MDCX command." },
87 [MGCP_MDCX_FAIL_INVALID_CONNID] = { "mdcx:connid", "invalid connection ID specified in MDCX command." },
88 [MGCP_MDCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in MDCX command." },
89 [MGCP_MDCX_FAIL_NO_CONNID] = { "mdcx:no_connid", "no connection ID specified in MDCX command." },
90 [MGCP_MDCX_FAIL_CONN_NOT_FOUND] =
91 { "mdcx:conn_not_found", "connection specified in MDCX command does not exist." },
92 [MGCP_MDCX_FAIL_INVALID_MODE] = { "mdcx:invalid_mode", "invalid connection mode in MDCX command." },
93 [MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
94 [MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
95 { "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
96 [MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
Philipp Maier8d6a1932020-06-18 12:19:31 +020097 [MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
Philipp Maierc66ab2c2020-06-02 20:55:34 +020098};
99
Pau Espin Pedrol663ba5c2022-09-22 21:43:31 +0200100static const struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200101 .group_name_prefix = "mdcx",
102 .group_description = "mdcx statistics",
103 .class_id = OSMO_STATS_CLASS_GLOBAL,
104 .num_ctr = ARRAY_SIZE(mgcp_mdcx_ctr_desc),
105 .ctr_desc = mgcp_mdcx_ctr_desc
106};
107
108static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
109 [MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200110 [MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
111 [MGCP_DLCX_FAIL_INVALID_CALLID] =
112 { "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
113 [MGCP_DLCX_FAIL_INVALID_CONNID] =
114 { "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
115 [MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
Philipp Maier8d6a1932020-06-18 12:19:31 +0200116 [MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200117};
118
Pau Espin Pedrol663ba5c2022-09-22 21:43:31 +0200119static const struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200120 .group_name_prefix = "dlcx",
121 .group_description = "dlcx statistics",
122 .class_id = OSMO_STATS_CLASS_GLOBAL,
123 .num_ctr = ARRAY_SIZE(mgcp_dlcx_ctr_desc),
124 .ctr_desc = mgcp_dlcx_ctr_desc
125};
126
Philipp Maier889fe7f2020-07-06 17:44:12 +0200127static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
Philipp Maier97cae472021-07-09 13:26:47 +0200128 [E1_I460_TRAU_RX_FAIL_CTR] = { "e1:rx_fail", "Inbound I.460 TRAU failures." },
129 [E1_I460_TRAU_TX_FAIL_CTR] = { "e1:tx_fail", "Outbound I.460 TRAU failures." },
130 [E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
Philipp Maier889fe7f2020-07-06 17:44:12 +0200131};
132
Pau Espin Pedrol663ba5c2022-09-22 21:43:31 +0200133static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
Philipp Maier889fe7f2020-07-06 17:44:12 +0200134 .group_name_prefix = "e1",
135 .group_description = "e1 statistics",
136 .class_id = OSMO_STATS_CLASS_GLOBAL,
137 .num_ctr = ARRAY_SIZE(e1_rate_ctr_desc),
138 .ctr_desc = e1_rate_ctr_desc
139};
140
Pau Espin Pedrol663ba5c2022-09-22 21:43:31 +0200141static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200142 .group_name_prefix = "all_rtp_conn",
143 .group_description = "aggregated statistics for all rtp connections",
144 .class_id = 1,
145 .num_ctr = ARRAY_SIZE(all_rtp_conn_rate_ctr_desc),
146 .ctr_desc = all_rtp_conn_rate_ctr_desc
147};
148
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200149static const struct rate_ctr_group_desc all_osmux_conn_rate_ctr_group_desc = {
150 .group_name_prefix = "all_osmux_conn",
151 .group_description = "aggregated statistics for all osmux connections",
152 .class_id = 1,
153 .num_ctr = ARRAY_SIZE(all_osmux_conn_rate_ctr_desc),
Pau Espin Pedrolb4a59472022-09-23 18:08:53 +0200154 .ctr_desc = all_osmux_conn_rate_ctr_desc
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200155};
156
Philipp Maiera065e632021-07-09 13:22:42 +0200157/*! allocate global rate counters
158 * (called once at startup).
159 * \param[in] cfg mgw configuration for which the rate counters are allocated.
160 * \returns 0 on success, -EINVAL on failure. */
161int mgcp_ratectr_global_alloc(struct mgcp_config *cfg)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200162{
Philipp Maiera065e632021-07-09 13:22:42 +0200163 struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
Erica94c56e2021-09-07 00:10:31 +0200164 static atomic_uint general_rate_ctr_index = 0;
Philipp Maiera065e632021-07-09 13:22:42 +0200165 char ctr_name[512];
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200166
167 if (ratectr->mgcp_general_ctr_group == NULL) {
168 ratectr->mgcp_general_ctr_group =
Erica94c56e2021-09-07 00:10:31 +0200169 rate_ctr_group_alloc(cfg, &mgcp_general_ctr_group_desc, general_rate_ctr_index++);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200170 if (!ratectr->mgcp_general_ctr_group)
171 return -EINVAL;
Philipp Maiera065e632021-07-09 13:22:42 +0200172 snprintf(ctr_name, sizeof(ctr_name), "%s:general", cfg->domain);
173 rate_ctr_group_set_name(ratectr->mgcp_general_ctr_group, ctr_name);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200174 }
175 return 0;
176}
177
Philipp Maier38533ba2021-07-29 17:38:34 +0200178/*! free global rate counters
179 * (called once at process shutdown).
180 * \param[in] cfg mgw configuration for which the rate counters are allocated. */
181void mgcp_ratectr_global_free(struct mgcp_config *cfg)
182{
183 struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
184
185 if (ratectr->mgcp_general_ctr_group) {
186 rate_ctr_group_free(ratectr->mgcp_general_ctr_group);
187 ratectr->mgcp_general_ctr_group = NULL;
188 }
189}
190
Philipp Maiera065e632021-07-09 13:22:42 +0200191/*! allocate trunk specific rate counters
192 * (called once on trunk initialization).
193 * \param[in] trunk mgw trunk for which the rate counters are allocated.
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200194 * \returns 0 on success, -EINVAL on failure */
Philipp Maiera065e632021-07-09 13:22:42 +0200195int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200196{
Philipp Maiera065e632021-07-09 13:22:42 +0200197 struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
Erica94c56e2021-09-07 00:10:31 +0200198 static atomic_uint crcx_rate_ctr_index = 0;
199 static atomic_uint mdcx_rate_ctr_index = 0;
200 static atomic_uint dlcx_rate_ctr_index = 0;
201 static atomic_uint all_rtp_conn_rate_ctr_index = 0;
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200202 static atomic_uint all_osmux_conn_rate_ctr_index = 0;
Philipp Maiera065e632021-07-09 13:22:42 +0200203 char ctr_name[256];
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200204
205 if (ratectr->mgcp_crcx_ctr_group == NULL) {
Philipp Maiera065e632021-07-09 13:22:42 +0200206 ratectr->mgcp_crcx_ctr_group =
Erica94c56e2021-09-07 00:10:31 +0200207 rate_ctr_group_alloc(trunk, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index++);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200208 if (!ratectr->mgcp_crcx_ctr_group)
209 return -EINVAL;
Philipp Maierd70eef62021-07-19 13:53:28 +0200210 snprintf(ctr_name, sizeof(ctr_name), "%s-%u:crcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
Philipp Maiera065e632021-07-09 13:22:42 +0200211 trunk->trunk_nr);
212 rate_ctr_group_set_name(ratectr->mgcp_crcx_ctr_group, ctr_name);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200213 }
214 if (ratectr->mgcp_mdcx_ctr_group == NULL) {
Philipp Maiera065e632021-07-09 13:22:42 +0200215 ratectr->mgcp_mdcx_ctr_group =
Erica94c56e2021-09-07 00:10:31 +0200216 rate_ctr_group_alloc(trunk, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index++);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200217 if (!ratectr->mgcp_mdcx_ctr_group)
218 return -EINVAL;
Philipp Maierd70eef62021-07-19 13:53:28 +0200219 snprintf(ctr_name, sizeof(ctr_name), "%s-%u:mdcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
Philipp Maiera065e632021-07-09 13:22:42 +0200220 trunk->trunk_nr);
221 rate_ctr_group_set_name(ratectr->mgcp_mdcx_ctr_group, ctr_name);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200222 }
223 if (ratectr->mgcp_dlcx_ctr_group == NULL) {
Philipp Maiera065e632021-07-09 13:22:42 +0200224 ratectr->mgcp_dlcx_ctr_group =
Erica94c56e2021-09-07 00:10:31 +0200225 rate_ctr_group_alloc(trunk, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index++);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200226 if (!ratectr->mgcp_dlcx_ctr_group)
227 return -EINVAL;
Philipp Maierd70eef62021-07-19 13:53:28 +0200228 snprintf(ctr_name, sizeof(ctr_name), "%s-%u:dlcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
Philipp Maiera065e632021-07-09 13:22:42 +0200229 trunk->trunk_nr);
230 rate_ctr_group_set_name(ratectr->mgcp_dlcx_ctr_group, ctr_name);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200231 }
232 if (ratectr->all_rtp_conn_stats == NULL) {
Philipp Maiera065e632021-07-09 13:22:42 +0200233 ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(trunk, &all_rtp_conn_rate_ctr_group_desc,
Erica94c56e2021-09-07 00:10:31 +0200234 all_rtp_conn_rate_ctr_index++);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200235 if (!ratectr->all_rtp_conn_stats)
236 return -EINVAL;
Philipp Maierd70eef62021-07-19 13:53:28 +0200237 snprintf(ctr_name, sizeof(ctr_name), "%s-%u:rtp_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
Philipp Maiera065e632021-07-09 13:22:42 +0200238 trunk->trunk_nr);
239 rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200240 }
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200241 if (ratectr->all_osmux_conn_stats == NULL) {
242 ratectr->all_osmux_conn_stats = rate_ctr_group_alloc(trunk, &all_osmux_conn_rate_ctr_group_desc,
243 all_osmux_conn_rate_ctr_index++);
244 if (!ratectr->all_osmux_conn_stats)
245 return -EINVAL;
246 snprintf(ctr_name, sizeof(ctr_name), "%s-%u:osmux_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
247 trunk->trunk_nr);
248 rate_ctr_group_set_name(ratectr->all_osmux_conn_stats, ctr_name);
249 }
Philipp Maiera065e632021-07-09 13:22:42 +0200250
251 /* E1 specific */
252 if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
Erica94c56e2021-09-07 00:10:31 +0200253 ratectr->e1_stats = rate_ctr_group_alloc(trunk, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index++);
Philipp Maier889fe7f2020-07-06 17:44:12 +0200254 if (!ratectr->e1_stats)
255 return -EINVAL;
Philipp Maierd70eef62021-07-19 13:53:28 +0200256 snprintf(ctr_name, sizeof(ctr_name), "%s-%u:e1", mgcp_trunk_type_strs_str(trunk->trunk_type),
Philipp Maiera065e632021-07-09 13:22:42 +0200257 trunk->trunk_nr);
258 rate_ctr_group_set_name(ratectr->e1_stats, ctr_name);
Philipp Maier889fe7f2020-07-06 17:44:12 +0200259 }
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200260 return 0;
261}
Philipp Maier124a3e02021-07-26 11:17:15 +0200262
Philipp Maier38533ba2021-07-29 17:38:34 +0200263/*! free trunk specific rate counters
264 * (called once when trunk is freed).
265 * \param[in] trunk mgw trunk on which the rate counters are allocated. */
266void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
267{
268 struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
269
270 if (ratectr->mgcp_crcx_ctr_group) {
271 rate_ctr_group_free(ratectr->mgcp_crcx_ctr_group);
272 ratectr->mgcp_crcx_ctr_group = NULL;
273 }
274 if (ratectr->mgcp_mdcx_ctr_group) {
275 rate_ctr_group_free(ratectr->mgcp_mdcx_ctr_group);
276 ratectr->mgcp_mdcx_ctr_group = NULL;
277 }
278 if (ratectr->mgcp_dlcx_ctr_group) {
279 rate_ctr_group_free(ratectr->mgcp_dlcx_ctr_group);
280 ratectr->mgcp_dlcx_ctr_group = NULL;
281 }
282 if (ratectr->all_rtp_conn_stats) {
283 rate_ctr_group_free(ratectr->all_rtp_conn_stats);
284 ratectr->all_rtp_conn_stats = NULL;
285 }
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200286 if (ratectr->all_osmux_conn_stats) {
287 rate_ctr_group_free(ratectr->all_osmux_conn_stats);
288 ratectr->all_osmux_conn_stats = NULL;
289 }
Philipp Maier38533ba2021-07-29 17:38:34 +0200290
291 /* E1 specific */
292 if (ratectr->e1_stats) {
293 rate_ctr_group_free(ratectr->e1_stats);
294 ratectr->e1_stats = NULL;
295 }
296}
297
Philipp Maier124a3e02021-07-26 11:17:15 +0200298const struct osmo_stat_item_desc trunk_stat_desc[] = {
299 [TRUNK_STAT_ENDPOINTS_TOTAL] = { "endpoints:total",
300 "Number of endpoints that exist on the trunk",
301 "", 60, 0 },
302 [TRUNK_STAT_ENDPOINTS_USED] = { "endpoints:used",
303 "Number of endpoints in use",
304 "", 60, 0 },
305};
306
307const struct osmo_stat_item_group_desc trunk_statg_desc = {
308 .group_name_prefix = "trunk",
309 .group_description = "mgw trunk",
310 .class_id = OSMO_STATS_CLASS_GLOBAL,
311 .num_items = ARRAY_SIZE(trunk_stat_desc),
312 .item_desc = trunk_stat_desc,
313};
314
Philipp Maier124a3e02021-07-26 11:17:15 +0200315/*! allocate trunk specific stat items
316 * (called once on trunk initialization).
317 * \param[in] trunk for which the stat items are allocated.
318 * \returns 0 on success, -EINVAL on failure. */
319int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk)
320{
321 struct mgcp_stat_trunk *stats = &trunk->stats;
322 static unsigned int common_stat_index = 0;
323 char stat_name[256];
324
325 stats->common = osmo_stat_item_group_alloc(trunk, &trunk_statg_desc, common_stat_index);
326 if (!stats->common)
327 return -EINVAL;
328 snprintf(stat_name, sizeof(stat_name), "%s-%u:common", mgcp_trunk_type_strs_str(trunk->trunk_type),
329 trunk->trunk_nr);
330 osmo_stat_item_group_set_name(stats->common, stat_name);
Philipp Maier124a3e02021-07-26 11:17:15 +0200331 common_stat_index++;
332
333 return 0;
334}
Philipp Maier38533ba2021-07-29 17:38:34 +0200335
336/*! free trunk specific stat items
337 * (called once when trunk is freed).
338 * \param[in] trunk on which the stat items are allocated. */
339void mgcp_stat_trunk_free(struct mgcp_trunk *trunk)
340{
341 struct mgcp_stat_trunk *stats = &trunk->stats;
342
343 if (stats->common) {
344 osmo_stat_item_group_free(stats->common);
345 stats->common = NULL;
346 }
347}