fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmo-trx/+/43633?usp=email )
(
2 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: proxy: check for PC clock skew ......................................................................
proxy: check for PC clock skew
This replicates the clock skew detection logic that exists in osmo-bts-trx (see trx_fn_timer_cb()).
Change-Id: I256ff6a4f4a05ea5507b5d9395a946672ff4e306 Related: OS#6672 --- M proxy/src/clck_gen.c 1 file changed, 37 insertions(+), 0 deletions(-)
Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified fixeria: Looks good to me, approved
diff --git a/proxy/src/clck_gen.c b/proxy/src/clck_gen.c index ff6c64c..39abc6c 100644 --- a/proxy/src/clck_gen.c +++ b/proxy/src/clck_gen.c @@ -27,9 +27,12 @@ #include <unistd.h> #include <stdint.h> #include <stdlib.h> +#include <time.h> +#include <inttypes.h>
#include <osmocom/core/linuxlist.h> #include <osmocom/core/select.h> +#include <osmocom/core/timer_compat.h> #include <osmocom/gsm/gsm0502.h>
#include <osmocom/trx/ep.h> @@ -43,27 +46,59 @@ /*! Default "IND CLOCK" period, in frames */ #define CLCK_GEN_IND_PERIOD 102
+/*! Maximum number of 'missed' frame periods we can tolerate before assuming + * the PC clock skewed (e.g. someone changed the system time, or the process + * got stuck/suspended for a while). */ +#define CLCK_GEN_MAX_FN_SKEW 50 + struct clck_gen { struct osmo_fd timerfd; uint32_t fn; bool running; int start_fn; /*!< CLCK_GEN_START_FN_RANDOM, or a fixed FN */ uint32_t ind_period; /*!< send "IND CLOCK" every N frames */ + struct timespec last_tick; /*!< CLOCK_MONOTONIC time of the last timer_cb() */ };
+/*! Number of micro-seconds elapsed between \a last and \a now */ +static int64_t compute_elapsed_us(const struct timespec *last, const struct timespec *now) +{ + struct timespec elapsed; + + timespecsub(now, last, &elapsed); + return (int64_t)(elapsed.tv_sec * 1000000) + (elapsed.tv_nsec / 1000); +} + static struct clck_gen g_clck_gen = { .start_fn = CLCK_GEN_START_FN_RANDOM, .ind_period = CLCK_GEN_IND_PERIOD, };
+static void clck_gen_stop(struct clck_gen *gen); + static int clck_gen_timer_cb(struct osmo_fd *ofd, unsigned int what) { struct clck_gen *gen = ofd->data; + struct timespec tv_now; uint64_t expire_count; + int64_t elapsed_us;
if (read(ofd->fd, &expire_count, sizeof(expire_count)) != sizeof(expire_count)) return 0;
+ /* check for PC clock skew (system time change, process stalled/suspended, ...) */ + clock_gettime(CLOCK_MONOTONIC, &tv_now); + elapsed_us = compute_elapsed_us(&gen->last_tick, &tv_now); + gen->last_tick = tv_now; + if (elapsed_us > GSM_TDMA_FN_DURATION_uS * CLCK_GEN_MAX_FN_SKEW || elapsed_us < 0) { + LOGP(DTRXC, LOGL_FATAL, + "PC clock skew too high (elapsed %" PRId64 " us): " + "stopping the TDMA clock generator\n", + elapsed_us); + clck_gen_stop(gen); + return 0; + } + while (expire_count-- > 0) { const struct proxy_trx *trx;
@@ -100,6 +135,8 @@ else gen->fn = (uint32_t)gen->start_fn;
+ clock_gettime(CLOCK_MONOTONIC, &gen->last_tick); + if (osmo_timerfd_schedule(&gen->timerfd, &first, &interval) < 0) { LOGP(DTRXC, LOGL_ERROR, "Failed to start the TDMA clock generator\n"); return;