Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 sysmocom - s.f.m.c. GmbH |
| 3 | * All Rights Reserved |
| 4 | * |
Pau Espin Pedrol | e9ce77b | 2019-06-25 12:29:01 +0200 | [diff] [blame] | 5 | * SPDX-License-Identifier: AGPL-3.0+ |
| 6 | * |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 7 | * Author: Pau Espin Pedrol <pespin@sysmocom.de> |
| 8 | * |
Pau Espin Pedrol | e9ce77b | 2019-06-25 12:29:01 +0200 | [diff] [blame] | 9 | * This program is free software: you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU Affero General Public License as published by |
| 11 | * the Free Software Foundation, either version 3 of the License, or |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
Pau Espin Pedrol | e9ce77b | 2019-06-25 12:29:01 +0200 | [diff] [blame] | 17 | * GNU Affero General Public License for more details. |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 18 | * |
Pau Espin Pedrol | e9ce77b | 2019-06-25 12:29:01 +0200 | [diff] [blame] | 19 | * You should have received a copy of the GNU Affero General Public License |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
Pau Espin Pedrol | e9ce77b | 2019-06-25 12:29:01 +0200 | [diff] [blame] | 21 | * See the COPYING file in the main directory for details. |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 22 | */ |
| 23 | |
| 24 | /* |
| 25 | * rate_ctr API uses several osmocom select loop features, and as a result, |
| 26 | * calls to it must be done through the main thread (the one running the osmocom |
| 27 | * loop in osmo-trx). |
| 28 | * Since read/write from/to SDR is done in separate threads (even read and write |
| 29 | * each use a different thread), we must use some sort of message passing system |
| 30 | * between main thread feeding rate_ctr structures and the Rx/Tx threads |
| 31 | * generating the events. |
| 32 | * The idea is that upon read/write issues, lower layers (SDR APIs) provide us with |
| 33 | * underrun/overrun/droppedPackets information, and in that case we pass that up |
| 34 | * the stack through signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> with signal_cb |
| 35 | * being a pointer to a "struct device_counters" structure, which contains |
| 36 | * device (implementation agnostic) statful counters for different kind of |
| 37 | * statistics. |
| 38 | * That signal is processed here in device_sig_cb, where a copy of the "struct |
| 39 | * device_counters" structure is held and the main thread is instructed through |
| 40 | * a timerfd to update rate_ctr APIs against this copy. All this is done inside |
Martin Hauke | 066fd04 | 2019-10-13 19:08:00 +0200 | [diff] [blame] | 41 | * a mutex to avoid different race conditions (between Rx andTx threads, and |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 42 | * between Rx/Tx and main thread). For the same reason, callers of signal |
| 43 | * <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> (device_sig_cb), that is Rx/Tx threads, |
| 44 | * must do so with PTHREAD_CANCEL_DISABLE, in order to avoid possible deadlocks |
| 45 | * in case the main thread decides to cancel other threads due to a shutdown |
| 46 | * operation (fi SIGKILL received) |
| 47 | */ |
| 48 | |
| 49 | #include <string.h> |
| 50 | #include <stdint.h> |
| 51 | #include <inttypes.h> |
| 52 | #include <netinet/in.h> |
| 53 | #include <arpa/inet.h> |
| 54 | |
| 55 | extern "C" { |
| 56 | #include <osmocom/core/talloc.h> |
| 57 | #include <osmocom/core/utils.h> |
| 58 | #include <osmocom/core/rate_ctr.h> |
| 59 | #include <osmocom/core/select.h> |
| 60 | #include <osmocom/core/stats.h> |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 61 | #include <osmocom/core/timer.h> |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 62 | |
| 63 | #include "osmo_signal.h" |
| 64 | #include "trx_vty.h" |
| 65 | #include "trx_rate_ctr.h" |
| 66 | } |
| 67 | #include "Threads.h" |
| 68 | #include "Logger.h" |
| 69 | |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 70 | /* Used in dev_ctrs_pending, when set it means that channel slot contains unused |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 71 | (non-pending) counter data */ |
| 72 | #define PENDING_CHAN_NONE SIZE_MAX |
| 73 | |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 74 | static void *trx_rate_ctr_ctx; |
| 75 | |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 76 | static struct rate_ctr_group** rate_ctrs; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 77 | static struct device_counters* dev_ctrs_pending; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 78 | static struct trx_counters* trx_ctrs_pending; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 79 | static size_t chan_len; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 80 | static struct osmo_fd dev_rate_ctr_timerfd; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 81 | static struct osmo_fd trx_rate_ctr_timerfd; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 82 | static Mutex dev_rate_ctr_mutex; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 83 | static Mutex trx_rate_ctr_mutex; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 84 | |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 85 | struct osmo_timer_list threshold_timer; |
| 86 | static LLIST_HEAD(threshold_list); |
Pau Espin Pedrol | fb96767 | 2020-06-29 16:44:23 +0200 | [diff] [blame] | 87 | static unsigned int threshold_timer_sched_secs; |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 88 | static bool threshold_initied; |
| 89 | |
| 90 | const struct value_string rate_ctr_intv[] = { |
| 91 | { RATE_CTR_INTV_SEC, "per-second" }, |
| 92 | { RATE_CTR_INTV_MIN, "per-minute" }, |
| 93 | { RATE_CTR_INTV_HOUR, "per-hour" }, |
| 94 | { RATE_CTR_INTV_DAY, "per-day" }, |
| 95 | { 0, NULL } |
| 96 | }; |
| 97 | |
| 98 | const struct value_string trx_chan_ctr_names[] = { |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 99 | { TRX_CTR_DEV_RX_OVERRUNS, "rx_overruns" }, |
| 100 | { TRX_CTR_DEV_TX_UNDERRUNS, "tx_underruns" }, |
| 101 | { TRX_CTR_DEV_RX_DROP_EV, "rx_drop_events" }, |
| 102 | { TRX_CTR_DEV_RX_DROP_SMPL, "rx_drop_samples" }, |
| 103 | { TRX_CTR_DEV_TX_DROP_EV, "tx_drop_events" }, |
| 104 | { TRX_CTR_DEV_TX_DROP_SMPL, "tx_drop_samples" }, |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 105 | { TRX_CTR_TRX_TX_STALE_BURSTS, "tx_stale_bursts" }, |
Pau Espin Pedrol | 1d0c6fe | 2020-07-09 18:09:10 +0200 | [diff] [blame] | 106 | { TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS, "tx_unavailable_bursts" }, |
Pau Espin Pedrol | c0d6fd2 | 2020-07-09 16:51:47 +0200 | [diff] [blame] | 107 | { TRX_CTR_TRX_TRXD_FN_REPEATED, "tx_trxd_fn_repeated" }, |
| 108 | { TRX_CTR_TRX_TRXD_FN_OUTOFORDER, "tx_trxd_fn_outoforder" }, |
| 109 | { TRX_CTR_TRX_TRXD_FN_SKIPPED, "tx_trxd_fn_skipped" }, |
Pau Espin Pedrol | 1d165a0 | 2020-07-27 11:52:42 +0200 | [diff] [blame] | 110 | { TRX_CTR_TRX_RX_EMPTY_BURST, "rx_empty_burst" }, |
| 111 | { TRX_CTR_TRX_RX_CLIPPING, "rx_clipping" }, |
| 112 | { TRX_CTR_TRX_RX_NO_BURST_DETECTED, "rx_no_burst_detected" }, |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 113 | { 0, NULL } |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 114 | }; |
| 115 | |
| 116 | static const struct rate_ctr_desc trx_chan_ctr_desc[] = { |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 117 | [TRX_CTR_DEV_RX_OVERRUNS] = { "device:rx_overruns", "Number of Rx overruns in FIFO queue" }, |
| 118 | [TRX_CTR_DEV_TX_UNDERRUNS] = { "device:tx_underruns", "Number of Tx underruns in FIFO queue" }, |
| 119 | [TRX_CTR_DEV_RX_DROP_EV] = { "device:rx_drop_events", "Number of times Rx samples were dropped by HW" }, |
| 120 | [TRX_CTR_DEV_RX_DROP_SMPL] = { "device:rx_drop_samples", "Number of Rx samples dropped by HW" }, |
| 121 | [TRX_CTR_DEV_TX_DROP_EV] = { "device:tx_drop_events", "Number of times Tx samples were dropped by HW" }, |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 122 | [TRX_CTR_DEV_TX_DROP_SMPL] = { "device:tx_drop_samples", "Number of Tx samples dropped by HW" }, |
| 123 | [TRX_CTR_TRX_TX_STALE_BURSTS] = { "trx:tx_stale_bursts", "Number of Tx burts dropped by TRX due to arriving too late" }, |
Pau Espin Pedrol | 1d0c6fe | 2020-07-09 18:09:10 +0200 | [diff] [blame] | 124 | [TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS] = { "trx:tx_unavailable_bursts","Number of Tx burts unavailable (not enqueued) at the time they should be transmitted" }, |
Pau Espin Pedrol | c0d6fd2 | 2020-07-09 16:51:47 +0200 | [diff] [blame] | 125 | [TRX_CTR_TRX_TRXD_FN_REPEATED] = { "trx:tx_trxd_fn_repeated", "Number of Tx burts received from TRXD with repeated FN" }, |
| 126 | [TRX_CTR_TRX_TRXD_FN_OUTOFORDER] = { "trx:tx_trxd_fn_outoforder","Number of Tx burts received from TRXD with a past FN" }, |
| 127 | [TRX_CTR_TRX_TRXD_FN_SKIPPED] = { "trx:tx_trxd_fn_skipped", "Number of Tx burts potentially skipped due to FN jumps" }, |
Pau Espin Pedrol | 1d165a0 | 2020-07-27 11:52:42 +0200 | [diff] [blame] | 128 | [TRX_CTR_TRX_RX_EMPTY_BURST] = { "trx:rx_empty_burst", "Number of Rx bursts empty" }, |
| 129 | [TRX_CTR_TRX_RX_CLIPPING] = { "trx:rx_clipping", "Number of Rx bursts discarded due to clipping" }, |
| 130 | [TRX_CTR_TRX_RX_NO_BURST_DETECTED] = { "trx:rx_no_burst_detected", "Number of Rx burts discarded due to burst detection error" }, |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 131 | }; |
| 132 | |
| 133 | static const struct rate_ctr_group_desc trx_chan_ctr_group_desc = { |
| 134 | .group_name_prefix = "trx:chan", |
| 135 | .group_description = "osmo-trx statistics", |
| 136 | .class_id = OSMO_STATS_CLASS_GLOBAL, |
| 137 | .num_ctr = ARRAY_SIZE(trx_chan_ctr_desc), |
| 138 | .ctr_desc = trx_chan_ctr_desc, |
| 139 | }; |
| 140 | |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 141 | static int dev_rate_ctr_timerfd_cb(struct osmo_fd *ofd, unsigned int what) { |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 142 | size_t chan; |
| 143 | struct rate_ctr *ctr; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 144 | LOGC(DCTR, INFO) << "Main thread is updating Device counters"; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 145 | dev_rate_ctr_mutex.lock(); |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 146 | for (chan = 0; chan < chan_len; chan++) { |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 147 | if (dev_ctrs_pending[chan].chan == PENDING_CHAN_NONE) |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 148 | continue; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 149 | LOGCHAN(chan, DCTR, DEBUG) << "rate_ctr update"; |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 150 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_RX_OVERRUNS); |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 151 | rate_ctr_add(ctr, dev_ctrs_pending[chan].rx_overruns - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 152 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_TX_UNDERRUNS); |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 153 | rate_ctr_add(ctr, dev_ctrs_pending[chan].tx_underruns - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 154 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_RX_DROP_EV); |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 155 | rate_ctr_add(ctr, dev_ctrs_pending[chan].rx_dropped_events - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 156 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_RX_DROP_SMPL); |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 157 | rate_ctr_add(ctr, dev_ctrs_pending[chan].rx_dropped_samples - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 158 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_TX_DROP_EV); |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 159 | rate_ctr_add(ctr, dev_ctrs_pending[chan].tx_dropped_events - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 160 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_TX_DROP_SMPL); |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 161 | rate_ctr_add(ctr, dev_ctrs_pending[chan].tx_dropped_samples - ctr->current); |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 162 | |
| 163 | /* Mark as done */ |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 164 | dev_ctrs_pending[chan].chan = PENDING_CHAN_NONE; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 165 | } |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 166 | if (osmo_timerfd_disable(&dev_rate_ctr_timerfd) < 0) |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 167 | LOGC(DCTR, ERROR) << "Failed to disable timerfd"; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 168 | dev_rate_ctr_mutex.unlock(); |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 169 | return 0; |
| 170 | } |
| 171 | |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 172 | static int trx_rate_ctr_timerfd_cb(struct osmo_fd *ofd, unsigned int what) { |
| 173 | size_t chan; |
| 174 | struct rate_ctr *ctr; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 175 | LOGC(DCTR, INFO) << "Main thread is updating Transceiver counters"; |
Pau Espin Pedrol | 032c1d8 | 2020-07-10 17:20:45 +0200 | [diff] [blame] | 176 | trx_rate_ctr_mutex.lock(); |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 177 | for (chan = 0; chan < chan_len; chan++) { |
| 178 | if (trx_ctrs_pending[chan].chan == PENDING_CHAN_NONE) |
| 179 | continue; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 180 | LOGCHAN(chan, DCTR, DEBUG) << "rate_ctr update"; |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 181 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TX_STALE_BURSTS); |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 182 | rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_stale_bursts - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 183 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS); |
Pau Espin Pedrol | 1d0c6fe | 2020-07-09 18:09:10 +0200 | [diff] [blame] | 184 | rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_unavailable_bursts - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 185 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TRXD_FN_REPEATED); |
Pau Espin Pedrol | c0d6fd2 | 2020-07-09 16:51:47 +0200 | [diff] [blame] | 186 | rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_trxd_fn_repeated - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 187 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TRXD_FN_OUTOFORDER); |
Pau Espin Pedrol | c0d6fd2 | 2020-07-09 16:51:47 +0200 | [diff] [blame] | 188 | rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_trxd_fn_outoforder - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 189 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TRXD_FN_SKIPPED); |
Pau Espin Pedrol | c0d6fd2 | 2020-07-09 16:51:47 +0200 | [diff] [blame] | 190 | rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_trxd_fn_skipped - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 191 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_RX_EMPTY_BURST); |
Pau Espin Pedrol | 1d165a0 | 2020-07-27 11:52:42 +0200 | [diff] [blame] | 192 | rate_ctr_add(ctr, trx_ctrs_pending[chan].rx_empty_burst - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 193 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_RX_CLIPPING); |
Pau Espin Pedrol | 1d165a0 | 2020-07-27 11:52:42 +0200 | [diff] [blame] | 194 | rate_ctr_add(ctr, trx_ctrs_pending[chan].rx_clipping - ctr->current); |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 195 | ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_RX_NO_BURST_DETECTED); |
Pau Espin Pedrol | 1d165a0 | 2020-07-27 11:52:42 +0200 | [diff] [blame] | 196 | rate_ctr_add(ctr, trx_ctrs_pending[chan].rx_no_burst_detected - ctr->current); |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 197 | /* Mark as done */ |
| 198 | trx_ctrs_pending[chan].chan = PENDING_CHAN_NONE; |
| 199 | } |
| 200 | if (osmo_timerfd_disable(&trx_rate_ctr_timerfd) < 0) |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 201 | LOGC(DCTR, ERROR) << "Failed to disable timerfd"; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 202 | trx_rate_ctr_mutex.unlock(); |
| 203 | return 0; |
| 204 | } |
| 205 | |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 206 | /* Callback function to be called every time we receive a signal from DEVICE */ |
| 207 | static int device_sig_cb(unsigned int subsys, unsigned int signal, |
| 208 | void *handler_data, void *signal_data) |
| 209 | { |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 210 | struct device_counters *dev_ctr; |
| 211 | struct trx_counters *trx_ctr; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 212 | /* Delay sched around 20 ms, in case we receive several calls from several |
| 213 | * channels batched */ |
| 214 | struct timespec next_sched = {.tv_sec = 0, .tv_nsec = 20*1000*1000}; |
| 215 | /* no automatic re-trigger */ |
| 216 | struct timespec intv_sched = {.tv_sec = 0, .tv_nsec = 0}; |
Vadim Yanitskiy | 5e40d92 | 2021-10-25 12:56:06 +0300 | [diff] [blame] | 217 | char err_buf[256]; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 218 | |
| 219 | switch (signal) { |
| 220 | case S_DEVICE_COUNTER_CHANGE: |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 221 | dev_ctr = (struct device_counters *)signal_data; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 222 | LOGCHAN(dev_ctr->chan, DCTR, INFO) << "Received counter change from radioDevice"; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 223 | dev_rate_ctr_mutex.lock(); |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 224 | dev_ctrs_pending[dev_ctr->chan] = *dev_ctr; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 225 | if (osmo_timerfd_schedule(&dev_rate_ctr_timerfd, &next_sched, &intv_sched) < 0) { |
Vadim Yanitskiy | 5e40d92 | 2021-10-25 12:56:06 +0300 | [diff] [blame] | 226 | LOGC(DCTR, ERROR) << "Failed to schedule timerfd: " << errno |
| 227 | << " = "<< strerror_r(errno, err_buf, sizeof(err_buf)); |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 228 | } |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 229 | dev_rate_ctr_mutex.unlock(); |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 230 | break; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 231 | case S_TRX_COUNTER_CHANGE: |
| 232 | trx_ctr = (struct trx_counters *)signal_data; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 233 | LOGCHAN(trx_ctr->chan, DCTR, INFO) << "Received counter change from Transceiver"; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 234 | trx_rate_ctr_mutex.lock(); |
| 235 | trx_ctrs_pending[trx_ctr->chan] = *trx_ctr; |
| 236 | if (osmo_timerfd_schedule(&trx_rate_ctr_timerfd, &next_sched, &intv_sched) < 0) { |
Vadim Yanitskiy | 5e40d92 | 2021-10-25 12:56:06 +0300 | [diff] [blame] | 237 | LOGC(DCTR, ERROR) << "Failed to schedule timerfd: " << errno |
| 238 | << " = "<< strerror_r(errno, err_buf, sizeof(err_buf)); |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 239 | } |
| 240 | trx_rate_ctr_mutex.unlock(); |
| 241 | break; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 242 | default: |
| 243 | break; |
| 244 | } |
| 245 | return 0; |
| 246 | } |
| 247 | |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 248 | /************************************ |
| 249 | * ctr_threshold APIs |
| 250 | ************************************/ |
| 251 | static const char* ctr_threshold_2_vty_str(struct ctr_threshold *ctr) |
| 252 | { |
| 253 | static char buf[256]; |
| 254 | int rc = 0; |
| 255 | rc += snprintf(buf, sizeof(buf), "ctr-error-threshold %s", get_value_string(trx_chan_ctr_names, ctr->ctr_id)); |
| 256 | rc += snprintf(buf + rc, sizeof(buf) - rc, " %d %s", ctr->val, get_value_string(rate_ctr_intv, ctr->intv)); |
| 257 | return buf; |
| 258 | } |
| 259 | |
| 260 | static void threshold_timer_cb(void *data) |
| 261 | { |
| 262 | struct ctr_threshold *ctr_thr; |
| 263 | struct rate_ctr *rate_ctr; |
| 264 | size_t chan; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 265 | LOGC(DCTR, DEBUG) << "threshold_timer_cb fired!"; |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 266 | |
| 267 | llist_for_each_entry(ctr_thr, &threshold_list, list) { |
| 268 | for (chan = 0; chan < chan_len; chan++) { |
Pau Espin Pedrol | 0a03822 | 2021-06-04 17:21:42 +0200 | [diff] [blame] | 269 | rate_ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], ctr_thr->ctr_id); |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 270 | LOGCHAN(chan, DCTR, INFO) << "checking threshold: " << ctr_threshold_2_vty_str(ctr_thr) |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 271 | << " ("<< rate_ctr->intv[ctr_thr->intv].rate << " vs " << ctr_thr->val << ")"; |
| 272 | if (rate_ctr->intv[ctr_thr->intv].rate >= ctr_thr->val) { |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 273 | LOGCHAN(chan, DCTR, FATAL) << "threshold reached, stopping! " << ctr_threshold_2_vty_str(ctr_thr) |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 274 | << " ("<< rate_ctr->intv[ctr_thr->intv].rate << " vs " << ctr_thr->val << ")"; |
| 275 | osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL); |
| 276 | return; |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | osmo_timer_schedule(&threshold_timer, threshold_timer_sched_secs, 0); |
| 281 | } |
| 282 | |
| 283 | static size_t ctr_threshold_2_seconds(struct ctr_threshold *ctr) |
| 284 | { |
| 285 | size_t mult = 0; |
| 286 | switch (ctr->intv) { |
| 287 | case RATE_CTR_INTV_SEC: |
| 288 | mult = 1; |
| 289 | break; |
| 290 | case RATE_CTR_INTV_MIN: |
| 291 | mult = 60; |
| 292 | break; |
| 293 | case RATE_CTR_INTV_HOUR: |
| 294 | mult = 60*60; |
| 295 | break; |
| 296 | case RATE_CTR_INTV_DAY: |
| 297 | mult = 60*60*24; |
| 298 | break; |
| 299 | default: |
| 300 | OSMO_ASSERT(false); |
| 301 | } |
| 302 | return mult; |
| 303 | } |
| 304 | |
| 305 | static void threshold_timer_update_intv() { |
| 306 | struct ctr_threshold *ctr, *min_ctr; |
| 307 | size_t secs, min_secs; |
| 308 | |
| 309 | /* Avoid scheduling timer until itself and other structures are prepared |
| 310 | by trx_rate_ctr_init */ |
| 311 | if (!threshold_initied) |
| 312 | return; |
| 313 | |
| 314 | if (llist_empty(&threshold_list)) { |
| 315 | if (osmo_timer_pending(&threshold_timer)) |
| 316 | osmo_timer_del(&threshold_timer); |
| 317 | return; |
| 318 | } |
| 319 | |
| 320 | min_ctr = llist_first_entry(&threshold_list, struct ctr_threshold, list); |
| 321 | min_secs = ctr_threshold_2_seconds(min_ctr); |
| 322 | |
| 323 | llist_for_each_entry(ctr, &threshold_list, list) { |
| 324 | secs = ctr_threshold_2_seconds(ctr); |
Pau Espin Pedrol | 394053e | 2020-06-29 16:43:25 +0200 | [diff] [blame] | 325 | if (min_secs > secs) |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 326 | min_secs = secs; |
| 327 | } |
| 328 | |
| 329 | |
Pau Espin Pedrol | fb96767 | 2020-06-29 16:44:23 +0200 | [diff] [blame] | 330 | threshold_timer_sched_secs = OSMO_MAX((int)(min_secs / 2 - 1), 1); |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 331 | LOGC(DCTR, INFO) << "New ctr-error-threshold check interval: " |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 332 | << threshold_timer_sched_secs << " seconds"; |
| 333 | osmo_timer_schedule(&threshold_timer, threshold_timer_sched_secs, 0); |
| 334 | } |
| 335 | |
| 336 | /* Init rate_ctr subsystem. Expected to be called during process start by main thread before VTY is ready */ |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 337 | void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx) |
| 338 | { |
| 339 | size_t i; |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 340 | trx_rate_ctr_ctx = ctx; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 341 | chan_len = trx_ctx->cfg.num_chans; |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 342 | dev_ctrs_pending = (struct device_counters*) talloc_zero_size(ctx, chan_len * sizeof(struct device_counters)); |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 343 | trx_ctrs_pending = (struct trx_counters*) talloc_zero_size(ctx, chan_len * sizeof(struct trx_counters)); |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 344 | rate_ctrs = (struct rate_ctr_group**) talloc_zero_size(ctx, chan_len * sizeof(struct rate_ctr_group*)); |
| 345 | |
| 346 | for (i = 0; i < chan_len; i++) { |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 347 | dev_ctrs_pending[i].chan = PENDING_CHAN_NONE; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 348 | trx_ctrs_pending[i].chan = PENDING_CHAN_NONE; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 349 | rate_ctrs[i] = rate_ctr_group_alloc(ctx, &trx_chan_ctr_group_desc, i); |
| 350 | if (!rate_ctrs[i]) { |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 351 | LOGCHAN(i, DCTR, ERROR) << "Failed to allocate rate ctr"; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 352 | exit(1); |
| 353 | } |
| 354 | } |
Pau Espin Pedrol | 6a3a2b8 | 2020-06-29 13:52:26 +0200 | [diff] [blame] | 355 | dev_rate_ctr_timerfd.fd = -1; |
| 356 | if (osmo_timerfd_setup(&dev_rate_ctr_timerfd, dev_rate_ctr_timerfd_cb, NULL) < 0) { |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 357 | LOGC(DCTR, ERROR) << "Failed to setup timerfd"; |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 358 | exit(1); |
| 359 | } |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 360 | trx_rate_ctr_timerfd.fd = -1; |
| 361 | if (osmo_timerfd_setup(&trx_rate_ctr_timerfd, trx_rate_ctr_timerfd_cb, NULL) < 0) { |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 362 | LOGC(DCTR, ERROR) << "Failed to setup timerfd"; |
Pau Espin Pedrol | 92ba59d | 2020-06-29 14:34:59 +0200 | [diff] [blame] | 363 | exit(1); |
| 364 | } |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 365 | osmo_signal_register_handler(SS_DEVICE, device_sig_cb, NULL); |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 366 | |
| 367 | /* Now set up threshold checks */ |
| 368 | threshold_initied = true; |
| 369 | osmo_timer_setup(&threshold_timer, threshold_timer_cb, NULL); |
| 370 | threshold_timer_update_intv(); |
| 371 | } |
| 372 | |
| 373 | void trx_rate_ctr_threshold_add(struct ctr_threshold *ctr) |
| 374 | { |
| 375 | struct ctr_threshold *new_ctr; |
| 376 | |
| 377 | new_ctr = talloc_zero(trx_rate_ctr_ctx, struct ctr_threshold); |
| 378 | *new_ctr = *ctr; |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 379 | LOGC(DCTR, NOTICE) << "Adding new threshold check: " << ctr_threshold_2_vty_str(new_ctr); |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 380 | llist_add(&new_ctr->list, &threshold_list); |
| 381 | threshold_timer_update_intv(); |
| 382 | } |
| 383 | |
| 384 | int trx_rate_ctr_threshold_del(struct ctr_threshold *del_ctr) |
| 385 | { |
| 386 | struct ctr_threshold *ctr; |
| 387 | |
| 388 | llist_for_each_entry(ctr, &threshold_list, list) { |
| 389 | if (ctr->intv != del_ctr->intv || |
| 390 | ctr->ctr_id != del_ctr->ctr_id || |
| 391 | ctr->val != del_ctr->val) |
| 392 | continue; |
| 393 | |
Pau Espin Pedrol | 761da1a | 2020-07-17 18:29:20 +0200 | [diff] [blame] | 394 | LOGC(DCTR, NOTICE) << "Deleting threshold check: " << ctr_threshold_2_vty_str(del_ctr); |
Pau Espin Pedrol | 6a305fe | 2019-05-24 19:58:20 +0200 | [diff] [blame] | 395 | llist_del(&ctr->list); |
| 396 | talloc_free(ctr); |
| 397 | threshold_timer_update_intv(); |
| 398 | return 0; |
| 399 | } |
| 400 | return -1; |
| 401 | } |
| 402 | |
| 403 | void trx_rate_ctr_threshold_write_config(struct vty *vty, char *indent_prefix) |
| 404 | { |
| 405 | struct ctr_threshold *ctr; |
| 406 | |
| 407 | llist_for_each_entry(ctr, &threshold_list, list) { |
| 408 | vty_out(vty, "%s%s%s", indent_prefix, ctr_threshold_2_vty_str(ctr), VTY_NEWLINE); |
| 409 | } |
Pau Espin Pedrol | 4456b6f | 2019-05-24 16:54:19 +0200 | [diff] [blame] | 410 | } |