blob: c66ce6b73a1f6eda981d42903da8496a24ba9c00 [file] [log] [blame]
Philipp Maier87bd9be2017-08-22 16:35:41 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The statistics generator */
3
4/*
5 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 by On-Waves
7 * (C) 2017 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
Philipp Maier87bd9be2017-08-22 16:35:41 +020025#include <limits.h>
Philipp Maierbca0ef62018-07-09 17:20:51 +020026#include <inttypes.h>
Philipp Maier993ea6b2020-08-04 18:26:50 +020027#include <osmocom/mgcp/mgcp_protocol.h>
28#include <osmocom/mgcp/mgcp_conn.h>
29#include <osmocom/mgcp/mgcp_stat.h>
30#include <osmocom/mgcp/mgcp_endp.h>
Ericfbf78d12021-08-23 22:31:39 +020031#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020032
33/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
Ericf936e102021-09-11 02:02:00 +020034#if defined(__has_attribute)
35#if __has_attribute(no_sanitize)
Pau Espin Pedrola0b69f12021-09-16 13:30:18 +020036__attribute__((no_sanitize("undefined")))
Ericf936e102021-09-11 02:02:00 +020037#endif
38#endif
Philipp Maiercede2a42018-07-03 14:14:21 +020039void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
Philipp Maier87bd9be2017-08-22 16:35:41 +020040{
Philipp Maiercede2a42018-07-03 14:14:21 +020041 struct mgcp_rtp_state *state = &conn->state;
Pau Espin Pedroldaf5bce2022-09-22 19:14:24 +020042 struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +020043
Harald Welte49e3d5a2017-12-25 09:47:57 +010044 *expected = state->stats.cycles + state->stats.max_seq;
45 *expected = *expected - state->stats.base_seq + 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +020046
Harald Welte49e3d5a2017-12-25 09:47:57 +010047 if (!state->stats.initialized) {
Philipp Maier87bd9be2017-08-22 16:35:41 +020048 *expected = 0;
49 *loss = 0;
50 return;
51 }
52
53 /*
54 * Make sure the sign is correct and use the biggest
55 * positive/negative number that fits.
56 */
Philipp Maiercede2a42018-07-03 14:14:21 +020057 *loss = *expected - packets_rx->current;
58 if (*expected < packets_rx->current) {
Philipp Maier87bd9be2017-08-22 16:35:41 +020059 if (*loss > 0)
60 *loss = INT_MIN;
61 } else {
62 if (*loss < 0)
63 *loss = INT_MAX;
64 }
65}
66
67/* Helper function for mgcp_format_stats_rtp() to calculate jitter */
68uint32_t calc_jitter(struct mgcp_rtp_state *state)
69{
Harald Welte49e3d5a2017-12-25 09:47:57 +010070 if (!state->stats.initialized)
Philipp Maier87bd9be2017-08-22 16:35:41 +020071 return 0;
Harald Welte49e3d5a2017-12-25 09:47:57 +010072 return state->stats.jitter >> 4;
Philipp Maier87bd9be2017-08-22 16:35:41 +020073}
74
75/* Generate statistics for an RTP connection */
76static void mgcp_format_stats_rtp(char *str, size_t str_len,
77 struct mgcp_conn_rtp *conn)
78{
79 uint32_t expected, jitter;
80 int ploss;
81 int nchars;
82
Pau Espin Pedroldaf5bce2022-09-22 19:14:24 +020083 struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
84 struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
85 struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
86 struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +020087
88 calc_loss(conn, &expected, &ploss);
Philipp Maier87bd9be2017-08-22 16:35:41 +020089 jitter = calc_jitter(&conn->state);
90
91 nchars = snprintf(str, str_len,
Philipp Maierbca0ef62018-07-09 17:20:51 +020092 "\r\nP: PS=%" PRIu64 ", OS=%" PRIu64 ", PR=%" PRIu64 ", OR=%" PRIu64 ", PL=%d, JI=%u",
Philipp Maiercede2a42018-07-03 14:14:21 +020093 packets_tx->current, octets_tx->current,
94 packets_rx->current, octets_rx->current,
Philipp Maier87bd9be2017-08-22 16:35:41 +020095 ploss, jitter);
96 if (nchars < 0 || nchars >= str_len)
97 goto truncate;
98
99 str += nchars;
100 str_len -= nchars;
101
Pau Espin Pedrol36413c02022-10-12 17:58:17 +0200102 if (conn->conn->endp->trunk->cfg->osmux.usage != OSMUX_USAGE_OFF) {
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100103 /* Error Counter */
104 nchars = snprintf(str, str_len,
Philipp Maierbca0ef62018-07-09 17:20:51 +0200105 "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
Philipp Maier9e1d1642018-05-09 16:26:34 +0200106 conn->state.in_stream.err_ts_ctr->current,
107 conn->state.out_stream.err_ts_ctr->current);
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100108 if (nchars < 0 || nchars >= str_len)
109 goto truncate;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200110
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100111 str += nchars;
112 str_len -= nchars;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200113
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100114 if (conn->osmux.state == OSMUX_STATE_ENABLED) {
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200115 struct rate_ctr *osmux_chunks_rx, *osmux_octets_rx;
116 osmux_chunks_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_CHUNKS_RX_CTR);
117 osmux_octets_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_OCTETS_RX_CTR);
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100118 snprintf(str, str_len,
Pau Espin Pedrol582c2bf2022-09-22 17:53:44 +0200119 "\r\nX-Osmux-ST: CR=%" PRIu64 ", BR=%" PRIu64,
120 osmux_chunks_rx->current, osmux_octets_rx->current);
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100121 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200122 }
123
124truncate:
125 str[str_len - 1] = '\0';
126}
127
128/*! format statistics into an mgcp parameter string.
129 * \param[out] str resulting string
130 * \param[in] str_len length of the string buffer
131 * \param[in] conn connection to evaluate */
132void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
133{
134 memset(str, 0, str_len);
135 if (!conn)
136 return;
137
138 /* NOTE: At the moment we only support generating statistics for
139 * RTP connections. However, in the future we may also want to
140 * generate statistics for other connection types as well. Lets
141 * keep this option open: */
142 switch (conn->type) {
143 case MGCP_CONN_TYPE_RTP:
144 mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
145 break;
146 default:
147 break;
148 }
149}