2019-05-24 14:54:19 +00:00
/*
* Copyright ( C ) 2019 sysmocom - s . f . m . c . GmbH
* All Rights Reserved
*
2019-06-25 10:29:01 +00:00
* SPDX - License - Identifier : AGPL - 3.0 +
*
2019-05-24 14:54:19 +00:00
* Author : Pau Espin Pedrol < pespin @ sysmocom . de >
*
2019-06-25 10:29:01 +00:00
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
2019-05-24 14:54:19 +00:00
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2019-06-25 10:29:01 +00:00
* GNU Affero General Public License for more details .
2019-05-24 14:54:19 +00:00
*
2019-06-25 10:29:01 +00:00
* You should have received a copy of the GNU Affero General Public License
2019-05-24 14:54:19 +00:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2019-06-25 10:29:01 +00:00
* See the COPYING file in the main directory for details .
2019-05-24 14:54:19 +00:00
*/
/*
* rate_ctr API uses several osmocom select loop features , and as a result ,
* calls to it must be done through the main thread ( the one running the osmocom
* loop in osmo - trx ) .
* Since read / write from / to SDR is done in separate threads ( even read and write
* each use a different thread ) , we must use some sort of message passing system
* between main thread feeding rate_ctr structures and the Rx / Tx threads
* generating the events .
* The idea is that upon read / write issues , lower layers ( SDR APIs ) provide us with
* underrun / overrun / droppedPackets information , and in that case we pass that up
* the stack through signal < SS_DEVICE , S_DEVICE_COUNTER_CHANGE > with signal_cb
* being a pointer to a " struct device_counters " structure , which contains
* device ( implementation agnostic ) statful counters for different kind of
* statistics .
* That signal is processed here in device_sig_cb , where a copy of the " struct
* device_counters " structure is held and the main thread is instructed through
* a timerfd to update rate_ctr APIs against this copy . All this is done inside
2019-10-13 17:08:00 +00:00
* a mutex to avoid different race conditions ( between Rx andTx threads , and
2019-05-24 14:54:19 +00:00
* between Rx / Tx and main thread ) . For the same reason , callers of signal
* < SS_DEVICE , S_DEVICE_COUNTER_CHANGE > ( device_sig_cb ) , that is Rx / Tx threads ,
* must do so with PTHREAD_CANCEL_DISABLE , in order to avoid possible deadlocks
* in case the main thread decides to cancel other threads due to a shutdown
* operation ( fi SIGKILL received )
*/
# include <string.h>
# include <stdint.h>
# include <inttypes.h>
# include <netinet/in.h>
# include <arpa/inet.h>
extern " C " {
# include <osmocom/core/talloc.h>
# include <osmocom/core/utils.h>
# include <osmocom/core/rate_ctr.h>
# include <osmocom/core/select.h>
# include <osmocom/core/stats.h>
2019-05-24 17:58:20 +00:00
# include <osmocom/core/timer.h>
2019-05-24 14:54:19 +00:00
# include "osmo_signal.h"
# include "trx_vty.h"
# include "trx_rate_ctr.h"
}
# include "Threads.h"
# include "Logger.h"
2020-06-29 11:52:26 +00:00
/* Used in dev_ctrs_pending, when set it means that channel slot contains unused
2019-05-24 14:54:19 +00:00
( non - pending ) counter data */
# define PENDING_CHAN_NONE SIZE_MAX
2019-05-24 17:58:20 +00:00
static void * trx_rate_ctr_ctx ;
2019-05-24 14:54:19 +00:00
static struct rate_ctr_group * * rate_ctrs ;
2020-06-29 11:52:26 +00:00
static struct device_counters * dev_ctrs_pending ;
2020-06-29 12:34:59 +00:00
static struct trx_counters * trx_ctrs_pending ;
2019-05-24 14:54:19 +00:00
static size_t chan_len ;
2020-06-29 11:52:26 +00:00
static struct osmo_fd dev_rate_ctr_timerfd ;
2020-06-29 12:34:59 +00:00
static struct osmo_fd trx_rate_ctr_timerfd ;
2020-06-29 11:52:26 +00:00
static Mutex dev_rate_ctr_mutex ;
2020-06-29 12:34:59 +00:00
static Mutex trx_rate_ctr_mutex ;
2019-05-24 14:54:19 +00:00
2019-05-24 17:58:20 +00:00
struct osmo_timer_list threshold_timer ;
static LLIST_HEAD ( threshold_list ) ;
2020-06-29 14:44:23 +00:00
static unsigned int threshold_timer_sched_secs ;
2019-05-24 17:58:20 +00:00
static bool threshold_initied ;
const struct value_string rate_ctr_intv [ ] = {
{ RATE_CTR_INTV_SEC , " per-second " } ,
{ RATE_CTR_INTV_MIN , " per-minute " } ,
{ RATE_CTR_INTV_HOUR , " per-hour " } ,
{ RATE_CTR_INTV_DAY , " per-day " } ,
{ 0 , NULL }
} ;
const struct value_string trx_chan_ctr_names [ ] = {
2020-06-29 11:52:26 +00:00
{ TRX_CTR_DEV_RX_OVERRUNS , " rx_overruns " } ,
{ TRX_CTR_DEV_TX_UNDERRUNS , " tx_underruns " } ,
{ TRX_CTR_DEV_RX_DROP_EV , " rx_drop_events " } ,
{ TRX_CTR_DEV_RX_DROP_SMPL , " rx_drop_samples " } ,
{ TRX_CTR_DEV_TX_DROP_EV , " tx_drop_events " } ,
{ TRX_CTR_DEV_TX_DROP_SMPL , " tx_drop_samples " } ,
2020-06-29 12:34:59 +00:00
{ TRX_CTR_TRX_TX_STALE_BURSTS , " tx_stale_bursts " } ,
2020-07-09 16:09:10 +00:00
{ TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS , " tx_unavailable_bursts " } ,
2020-07-09 14:51:47 +00:00
{ TRX_CTR_TRX_TRXD_FN_REPEATED , " tx_trxd_fn_repeated " } ,
{ TRX_CTR_TRX_TRXD_FN_OUTOFORDER , " tx_trxd_fn_outoforder " } ,
{ TRX_CTR_TRX_TRXD_FN_SKIPPED , " tx_trxd_fn_skipped " } ,
2020-07-27 09:52:42 +00:00
{ TRX_CTR_TRX_RX_EMPTY_BURST , " rx_empty_burst " } ,
{ TRX_CTR_TRX_RX_CLIPPING , " rx_clipping " } ,
{ TRX_CTR_TRX_RX_NO_BURST_DETECTED , " rx_no_burst_detected " } ,
2019-05-24 17:58:20 +00:00
{ 0 , NULL }
2019-05-24 14:54:19 +00:00
} ;
static const struct rate_ctr_desc trx_chan_ctr_desc [ ] = {
2020-06-29 11:52:26 +00:00
[ TRX_CTR_DEV_RX_OVERRUNS ] = { " device:rx_overruns " , " Number of Rx overruns in FIFO queue " } ,
[ TRX_CTR_DEV_TX_UNDERRUNS ] = { " device:tx_underruns " , " Number of Tx underruns in FIFO queue " } ,
[ TRX_CTR_DEV_RX_DROP_EV ] = { " device:rx_drop_events " , " Number of times Rx samples were dropped by HW " } ,
[ TRX_CTR_DEV_RX_DROP_SMPL ] = { " device:rx_drop_samples " , " Number of Rx samples dropped by HW " } ,
[ TRX_CTR_DEV_TX_DROP_EV ] = { " device:tx_drop_events " , " Number of times Tx samples were dropped by HW " } ,
2020-06-29 12:34:59 +00:00
[ TRX_CTR_DEV_TX_DROP_SMPL ] = { " device:tx_drop_samples " , " Number of Tx samples dropped by HW " } ,
[ TRX_CTR_TRX_TX_STALE_BURSTS ] = { " trx:tx_stale_bursts " , " Number of Tx burts dropped by TRX due to arriving too late " } ,
2020-07-09 16:09:10 +00:00
[ TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS ] = { " trx:tx_unavailable_bursts " , " Number of Tx burts unavailable (not enqueued) at the time they should be transmitted " } ,
2020-07-09 14:51:47 +00:00
[ TRX_CTR_TRX_TRXD_FN_REPEATED ] = { " trx:tx_trxd_fn_repeated " , " Number of Tx burts received from TRXD with repeated FN " } ,
[ TRX_CTR_TRX_TRXD_FN_OUTOFORDER ] = { " trx:tx_trxd_fn_outoforder " , " Number of Tx burts received from TRXD with a past FN " } ,
[ TRX_CTR_TRX_TRXD_FN_SKIPPED ] = { " trx:tx_trxd_fn_skipped " , " Number of Tx burts potentially skipped due to FN jumps " } ,
2020-07-27 09:52:42 +00:00
[ TRX_CTR_TRX_RX_EMPTY_BURST ] = { " trx:rx_empty_burst " , " Number of Rx bursts empty " } ,
[ TRX_CTR_TRX_RX_CLIPPING ] = { " trx:rx_clipping " , " Number of Rx bursts discarded due to clipping " } ,
[ TRX_CTR_TRX_RX_NO_BURST_DETECTED ] = { " trx:rx_no_burst_detected " , " Number of Rx burts discarded due to burst detection error " } ,
2019-05-24 14:54:19 +00:00
} ;
static const struct rate_ctr_group_desc trx_chan_ctr_group_desc = {
. group_name_prefix = " trx:chan " ,
. group_description = " osmo-trx statistics " ,
. class_id = OSMO_STATS_CLASS_GLOBAL ,
. num_ctr = ARRAY_SIZE ( trx_chan_ctr_desc ) ,
. ctr_desc = trx_chan_ctr_desc ,
} ;
2020-06-29 11:52:26 +00:00
static int dev_rate_ctr_timerfd_cb ( struct osmo_fd * ofd , unsigned int what ) {
2019-05-24 14:54:19 +00:00
size_t chan ;
struct rate_ctr * ctr ;
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , INFO ) < < " Main thread is updating Device counters " ;
2020-06-29 11:52:26 +00:00
dev_rate_ctr_mutex . lock ( ) ;
2019-05-24 14:54:19 +00:00
for ( chan = 0 ; chan < chan_len ; chan + + ) {
2020-06-29 11:52:26 +00:00
if ( dev_ctrs_pending [ chan ] . chan = = PENDING_CHAN_NONE )
2019-05-24 14:54:19 +00:00
continue ;
2020-07-17 16:29:20 +00:00
LOGCHAN ( chan , DCTR , DEBUG ) < < " rate_ctr update " ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_DEV_RX_OVERRUNS ) ;
2020-06-29 11:52:26 +00:00
rate_ctr_add ( ctr , dev_ctrs_pending [ chan ] . rx_overruns - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_DEV_TX_UNDERRUNS ) ;
2020-06-29 11:52:26 +00:00
rate_ctr_add ( ctr , dev_ctrs_pending [ chan ] . tx_underruns - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_DEV_RX_DROP_EV ) ;
2020-06-29 11:52:26 +00:00
rate_ctr_add ( ctr , dev_ctrs_pending [ chan ] . rx_dropped_events - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_DEV_RX_DROP_SMPL ) ;
2020-06-29 11:52:26 +00:00
rate_ctr_add ( ctr , dev_ctrs_pending [ chan ] . rx_dropped_samples - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_DEV_TX_DROP_EV ) ;
2020-06-29 11:52:26 +00:00
rate_ctr_add ( ctr , dev_ctrs_pending [ chan ] . tx_dropped_events - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_DEV_TX_DROP_SMPL ) ;
2020-06-29 11:52:26 +00:00
rate_ctr_add ( ctr , dev_ctrs_pending [ chan ] . tx_dropped_samples - ctr - > current ) ;
2019-05-24 14:54:19 +00:00
/* Mark as done */
2020-06-29 11:52:26 +00:00
dev_ctrs_pending [ chan ] . chan = PENDING_CHAN_NONE ;
2019-05-24 14:54:19 +00:00
}
2020-06-29 11:52:26 +00:00
if ( osmo_timerfd_disable ( & dev_rate_ctr_timerfd ) < 0 )
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , ERROR ) < < " Failed to disable timerfd " ;
2020-06-29 11:52:26 +00:00
dev_rate_ctr_mutex . unlock ( ) ;
2019-05-24 14:54:19 +00:00
return 0 ;
}
2020-06-29 12:34:59 +00:00
static int trx_rate_ctr_timerfd_cb ( struct osmo_fd * ofd , unsigned int what ) {
size_t chan ;
struct rate_ctr * ctr ;
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , INFO ) < < " Main thread is updating Transceiver counters " ;
2020-07-10 15:20:45 +00:00
trx_rate_ctr_mutex . lock ( ) ;
2020-06-29 12:34:59 +00:00
for ( chan = 0 ; chan < chan_len ; chan + + ) {
if ( trx_ctrs_pending [ chan ] . chan = = PENDING_CHAN_NONE )
continue ;
2020-07-17 16:29:20 +00:00
LOGCHAN ( chan , DCTR , DEBUG ) < < " rate_ctr update " ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_TX_STALE_BURSTS ) ;
2020-06-29 12:34:59 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . tx_stale_bursts - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS ) ;
2020-07-09 16:09:10 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . tx_unavailable_bursts - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_TRXD_FN_REPEATED ) ;
2020-07-09 14:51:47 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . tx_trxd_fn_repeated - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_TRXD_FN_OUTOFORDER ) ;
2020-07-09 14:51:47 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . tx_trxd_fn_outoforder - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_TRXD_FN_SKIPPED ) ;
2020-07-09 14:51:47 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . tx_trxd_fn_skipped - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_RX_EMPTY_BURST ) ;
2020-07-27 09:52:42 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . rx_empty_burst - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_RX_CLIPPING ) ;
2020-07-27 09:52:42 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . rx_clipping - ctr - > current ) ;
2021-06-04 15:21:42 +00:00
ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , TRX_CTR_TRX_RX_NO_BURST_DETECTED ) ;
2020-07-27 09:52:42 +00:00
rate_ctr_add ( ctr , trx_ctrs_pending [ chan ] . rx_no_burst_detected - ctr - > current ) ;
2020-06-29 12:34:59 +00:00
/* Mark as done */
trx_ctrs_pending [ chan ] . chan = PENDING_CHAN_NONE ;
}
if ( osmo_timerfd_disable ( & trx_rate_ctr_timerfd ) < 0 )
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , ERROR ) < < " Failed to disable timerfd " ;
2020-06-29 12:34:59 +00:00
trx_rate_ctr_mutex . unlock ( ) ;
return 0 ;
}
2019-05-24 14:54:19 +00:00
/* Callback function to be called every time we receive a signal from DEVICE */
static int device_sig_cb ( unsigned int subsys , unsigned int signal ,
void * handler_data , void * signal_data )
{
2020-06-29 12:34:59 +00:00
struct device_counters * dev_ctr ;
struct trx_counters * trx_ctr ;
2019-05-24 14:54:19 +00:00
/* Delay sched around 20 ms, in case we receive several calls from several
* channels batched */
struct timespec next_sched = { . tv_sec = 0 , . tv_nsec = 20 * 1000 * 1000 } ;
/* no automatic re-trigger */
struct timespec intv_sched = { . tv_sec = 0 , . tv_nsec = 0 } ;
switch ( signal ) {
case S_DEVICE_COUNTER_CHANGE :
2020-06-29 12:34:59 +00:00
dev_ctr = ( struct device_counters * ) signal_data ;
2020-07-17 16:29:20 +00:00
LOGCHAN ( dev_ctr - > chan , DCTR , INFO ) < < " Received counter change from radioDevice " ;
2020-06-29 11:52:26 +00:00
dev_rate_ctr_mutex . lock ( ) ;
2020-06-29 12:34:59 +00:00
dev_ctrs_pending [ dev_ctr - > chan ] = * dev_ctr ;
2020-06-29 11:52:26 +00:00
if ( osmo_timerfd_schedule ( & dev_rate_ctr_timerfd , & next_sched , & intv_sched ) < 0 ) {
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , ERROR ) < < " Failed to schedule timerfd: " < < errno < < " = " < < strerror ( errno ) ;
2019-05-24 14:54:19 +00:00
}
2020-06-29 11:52:26 +00:00
dev_rate_ctr_mutex . unlock ( ) ;
2019-05-24 14:54:19 +00:00
break ;
2020-06-29 12:34:59 +00:00
case S_TRX_COUNTER_CHANGE :
trx_ctr = ( struct trx_counters * ) signal_data ;
2020-07-17 16:29:20 +00:00
LOGCHAN ( trx_ctr - > chan , DCTR , INFO ) < < " Received counter change from Transceiver " ;
2020-06-29 12:34:59 +00:00
trx_rate_ctr_mutex . lock ( ) ;
trx_ctrs_pending [ trx_ctr - > chan ] = * trx_ctr ;
if ( osmo_timerfd_schedule ( & trx_rate_ctr_timerfd , & next_sched , & intv_sched ) < 0 ) {
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , ERROR ) < < " Failed to schedule timerfd: " < < errno < < " = " < < strerror ( errno ) ;
2020-06-29 12:34:59 +00:00
}
trx_rate_ctr_mutex . unlock ( ) ;
break ;
2019-05-24 14:54:19 +00:00
default :
break ;
}
return 0 ;
}
2019-05-24 17:58:20 +00:00
/************************************
* ctr_threshold APIs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const char * ctr_threshold_2_vty_str ( struct ctr_threshold * ctr )
{
static char buf [ 256 ] ;
int rc = 0 ;
rc + = snprintf ( buf , sizeof ( buf ) , " ctr-error-threshold %s " , get_value_string ( trx_chan_ctr_names , ctr - > ctr_id ) ) ;
rc + = snprintf ( buf + rc , sizeof ( buf ) - rc , " %d %s " , ctr - > val , get_value_string ( rate_ctr_intv , ctr - > intv ) ) ;
return buf ;
}
static void threshold_timer_cb ( void * data )
{
struct ctr_threshold * ctr_thr ;
struct rate_ctr * rate_ctr ;
size_t chan ;
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , DEBUG ) < < " threshold_timer_cb fired! " ;
2019-05-24 17:58:20 +00:00
llist_for_each_entry ( ctr_thr , & threshold_list , list ) {
for ( chan = 0 ; chan < chan_len ; chan + + ) {
2021-06-04 15:21:42 +00:00
rate_ctr = rate_ctr_group_get_ctr ( rate_ctrs [ chan ] , ctr_thr - > ctr_id ) ;
2020-07-17 16:29:20 +00:00
LOGCHAN ( chan , DCTR , INFO ) < < " checking threshold: " < < ctr_threshold_2_vty_str ( ctr_thr )
2019-05-24 17:58:20 +00:00
< < " ( " < < rate_ctr - > intv [ ctr_thr - > intv ] . rate < < " vs " < < ctr_thr - > val < < " ) " ;
if ( rate_ctr - > intv [ ctr_thr - > intv ] . rate > = ctr_thr - > val ) {
2020-07-17 16:29:20 +00:00
LOGCHAN ( chan , DCTR , FATAL ) < < " threshold reached, stopping! " < < ctr_threshold_2_vty_str ( ctr_thr )
2019-05-24 17:58:20 +00:00
< < " ( " < < rate_ctr - > intv [ ctr_thr - > intv ] . rate < < " vs " < < ctr_thr - > val < < " ) " ;
osmo_signal_dispatch ( SS_MAIN , S_MAIN_STOP_REQUIRED , NULL ) ;
return ;
}
}
}
osmo_timer_schedule ( & threshold_timer , threshold_timer_sched_secs , 0 ) ;
}
static size_t ctr_threshold_2_seconds ( struct ctr_threshold * ctr )
{
size_t mult = 0 ;
switch ( ctr - > intv ) {
case RATE_CTR_INTV_SEC :
mult = 1 ;
break ;
case RATE_CTR_INTV_MIN :
mult = 60 ;
break ;
case RATE_CTR_INTV_HOUR :
mult = 60 * 60 ;
break ;
case RATE_CTR_INTV_DAY :
mult = 60 * 60 * 24 ;
break ;
default :
OSMO_ASSERT ( false ) ;
}
return mult ;
}
static void threshold_timer_update_intv ( ) {
struct ctr_threshold * ctr , * min_ctr ;
size_t secs , min_secs ;
/* Avoid scheduling timer until itself and other structures are prepared
by trx_rate_ctr_init */
if ( ! threshold_initied )
return ;
if ( llist_empty ( & threshold_list ) ) {
if ( osmo_timer_pending ( & threshold_timer ) )
osmo_timer_del ( & threshold_timer ) ;
return ;
}
min_ctr = llist_first_entry ( & threshold_list , struct ctr_threshold , list ) ;
min_secs = ctr_threshold_2_seconds ( min_ctr ) ;
llist_for_each_entry ( ctr , & threshold_list , list ) {
secs = ctr_threshold_2_seconds ( ctr ) ;
2020-06-29 14:43:25 +00:00
if ( min_secs > secs )
2019-05-24 17:58:20 +00:00
min_secs = secs ;
}
2020-06-29 14:44:23 +00:00
threshold_timer_sched_secs = OSMO_MAX ( ( int ) ( min_secs / 2 - 1 ) , 1 ) ;
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , INFO ) < < " New ctr-error-threshold check interval: "
2019-05-24 17:58:20 +00:00
< < threshold_timer_sched_secs < < " seconds " ;
osmo_timer_schedule ( & threshold_timer , threshold_timer_sched_secs , 0 ) ;
}
/* Init rate_ctr subsystem. Expected to be called during process start by main thread before VTY is ready */
2019-05-24 14:54:19 +00:00
void trx_rate_ctr_init ( void * ctx , struct trx_ctx * trx_ctx )
{
size_t i ;
2019-05-24 17:58:20 +00:00
trx_rate_ctr_ctx = ctx ;
2019-05-24 14:54:19 +00:00
chan_len = trx_ctx - > cfg . num_chans ;
2020-06-29 11:52:26 +00:00
dev_ctrs_pending = ( struct device_counters * ) talloc_zero_size ( ctx , chan_len * sizeof ( struct device_counters ) ) ;
2020-06-29 12:34:59 +00:00
trx_ctrs_pending = ( struct trx_counters * ) talloc_zero_size ( ctx , chan_len * sizeof ( struct trx_counters ) ) ;
2019-05-24 14:54:19 +00:00
rate_ctrs = ( struct rate_ctr_group * * ) talloc_zero_size ( ctx , chan_len * sizeof ( struct rate_ctr_group * ) ) ;
for ( i = 0 ; i < chan_len ; i + + ) {
2020-06-29 11:52:26 +00:00
dev_ctrs_pending [ i ] . chan = PENDING_CHAN_NONE ;
2020-06-29 12:34:59 +00:00
trx_ctrs_pending [ i ] . chan = PENDING_CHAN_NONE ;
2019-05-24 14:54:19 +00:00
rate_ctrs [ i ] = rate_ctr_group_alloc ( ctx , & trx_chan_ctr_group_desc , i ) ;
if ( ! rate_ctrs [ i ] ) {
2020-07-17 16:29:20 +00:00
LOGCHAN ( i , DCTR , ERROR ) < < " Failed to allocate rate ctr " ;
2019-05-24 14:54:19 +00:00
exit ( 1 ) ;
}
}
2020-06-29 11:52:26 +00:00
dev_rate_ctr_timerfd . fd = - 1 ;
if ( osmo_timerfd_setup ( & dev_rate_ctr_timerfd , dev_rate_ctr_timerfd_cb , NULL ) < 0 ) {
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , ERROR ) < < " Failed to setup timerfd " ;
2019-05-24 14:54:19 +00:00
exit ( 1 ) ;
}
2020-06-29 12:34:59 +00:00
trx_rate_ctr_timerfd . fd = - 1 ;
if ( osmo_timerfd_setup ( & trx_rate_ctr_timerfd , trx_rate_ctr_timerfd_cb , NULL ) < 0 ) {
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , ERROR ) < < " Failed to setup timerfd " ;
2020-06-29 12:34:59 +00:00
exit ( 1 ) ;
}
2019-05-24 14:54:19 +00:00
osmo_signal_register_handler ( SS_DEVICE , device_sig_cb , NULL ) ;
2019-05-24 17:58:20 +00:00
/* Now set up threshold checks */
threshold_initied = true ;
osmo_timer_setup ( & threshold_timer , threshold_timer_cb , NULL ) ;
threshold_timer_update_intv ( ) ;
}
void trx_rate_ctr_threshold_add ( struct ctr_threshold * ctr )
{
struct ctr_threshold * new_ctr ;
new_ctr = talloc_zero ( trx_rate_ctr_ctx , struct ctr_threshold ) ;
* new_ctr = * ctr ;
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , NOTICE ) < < " Adding new threshold check: " < < ctr_threshold_2_vty_str ( new_ctr ) ;
2019-05-24 17:58:20 +00:00
llist_add ( & new_ctr - > list , & threshold_list ) ;
threshold_timer_update_intv ( ) ;
}
int trx_rate_ctr_threshold_del ( struct ctr_threshold * del_ctr )
{
struct ctr_threshold * ctr ;
llist_for_each_entry ( ctr , & threshold_list , list ) {
if ( ctr - > intv ! = del_ctr - > intv | |
ctr - > ctr_id ! = del_ctr - > ctr_id | |
ctr - > val ! = del_ctr - > val )
continue ;
2020-07-17 16:29:20 +00:00
LOGC ( DCTR , NOTICE ) < < " Deleting threshold check: " < < ctr_threshold_2_vty_str ( del_ctr ) ;
2019-05-24 17:58:20 +00:00
llist_del ( & ctr - > list ) ;
talloc_free ( ctr ) ;
threshold_timer_update_intv ( ) ;
return 0 ;
}
return - 1 ;
}
void trx_rate_ctr_threshold_write_config ( struct vty * vty , char * indent_prefix )
{
struct ctr_threshold * ctr ;
llist_for_each_entry ( ctr , & threshold_list , list ) {
vty_out ( vty , " %s%s%s " , indent_prefix , ctr_threshold_2_vty_str ( ctr ) , VTY_NEWLINE ) ;
}
2019-05-24 14:54:19 +00:00
}