aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libbsc/chan_alloc.c
diff options
context:
space:
mode:
authorStefan Sperling <ssperling@sysmocom.de>2018-03-14 20:15:24 +0100
committerStefan Sperling <ssperling@sysmocom.de>2018-03-14 20:59:37 +0100
commit99805db3c30f5d9b1f6913407545a75ab41d7065 (patch)
treef24628322628f3fbd34255cf9c8fd23f42c7ab92 /openbsc/src/libbsc/chan_alloc.c
parent55d172617c2b6df3abdd430bf5751ddbd4420551 (diff)
Make "waiting indicator" of IMMEDIATE ASSIGN REJECT dynamic.
The IMMEDIATE ASSIGN REJECT message contains a wait indicator which tells an MS requesting a channel to wait for a specified amount of time before trying to request a channel again, i.e. the wait indicator controls the T3122 timeout value in the MS. Previously, the wait indicator was fixed to 10 seconds. This is not sufficient if there are a lot of MS requesting channels because the MS will retry too soon. Instead of using a fixed value, maintain a dynamic wait indicator value based on average channel load. The load (used vs. available channels on a BTS) is sampled once per second, and once 8 samples have been collected we update a BTS-specific T3122 wait indicator based on the measured load. While the wait indicator could go up to 255 seconds, this initial implementation keeps it in the range from 10 to 128 seconds. Further experimentation and testing will show whether higher wait indicator values are desirable, if the sampling rate needs to change, or if the function mapping the load measurement to a wait indicator value should change (currently we map the load average linearly into the range [10, 128] inclusive). Port of osmo-bsc commit 6cee893a0f2c4e53155a2631aff12a5f615b973d Change-Id: Id9df0e790ece8108212b2ddf718cf2953f5b9bd4 Related: OS#2592
Diffstat (limited to 'openbsc/src/libbsc/chan_alloc.c')
-rw-r--r--openbsc/src/libbsc/chan_alloc.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c
index 33b79a0b2..cf6b708fa 100644
--- a/openbsc/src/libbsc/chan_alloc.c
+++ b/openbsc/src/libbsc/chan_alloc.c
@@ -541,3 +541,78 @@ void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
bts_chan_load(pl, bts);
}
+/* Update T3122 wait indicator based on samples of BTS channel load. */
+void
+bts_update_t3122_chan_load(struct gsm_bts *bts)
+{
+ struct pchan_load pl;
+ uint64_t used = 0;
+ uint32_t total = 0;
+ uint64_t load;
+ uint64_t wait_ind;
+ static const uint8_t min_wait_ind = GSM_T3122_DEFAULT;
+ static const uint8_t max_wait_ind = 128; /* max wait ~2 minutes */
+ int i;
+
+ /* Sum up current load across all channels. */
+ memset(&pl, 0, sizeof(pl));
+ bts_chan_load(&pl, bts);
+ for (i = 0; i < ARRAY_SIZE(pl.pchan); i++) {
+ struct load_counter *lc = &pl.pchan[i];
+
+ /* Ignore samples too large for fixed-point calculations (shouldn't happen). */
+ if (lc->used > UINT16_MAX || lc->total > UINT16_MAX) {
+ LOGP(DRLL, LOGL_NOTICE, "(bts=%d) numbers in channel load sample "
+ "too large (used=%u / total=%u)\n", bts->nr, lc->used, lc->total);
+ continue;
+ }
+
+ used += lc->used;
+ total += lc->total;
+ }
+
+ /* Check for invalid samples (shouldn't happen). */
+ if (total == 0 || used > total) {
+ LOGP(DRLL, LOGL_NOTICE, "(bts=%d) bogus channel load sample (used=%lu / total=%u)\n",
+ bts->nr, used, total);
+ bts->T3122 = 0; /* disable override of network-wide default value */
+ bts->chan_load_samples_idx = 0; /* invalidate other samples collected so far */
+ return;
+ }
+
+ /* If we haven't got enough samples yet, store measurement for later use. */
+ if (bts->chan_load_samples_idx < ARRAY_SIZE(bts->chan_load_samples)) {
+ struct load_counter *sample = &bts->chan_load_samples[bts->chan_load_samples_idx++];
+ sample->total = (unsigned int)total;
+ sample->used = (unsigned int)used;
+ return;
+ }
+
+ /* We have enough samples and will overwrite our current samples later. */
+ bts->chan_load_samples_idx = 0;
+
+ /* Add all previous samples to the current sample. */
+ for (i = 0; i < ARRAY_SIZE(bts->chan_load_samples); i++) {
+ struct load_counter *sample = &bts->chan_load_samples[i];
+ total += sample->total;
+ used += sample->used;
+ }
+
+ used <<= 8; /* convert to fixed-point */
+
+ /* Log channel load average. */
+ load = ((used / total) * 100);
+ LOGP(DRLL, LOGL_DEBUG, "(bts=%d) channel load average is %lu.%.2lu%%\n",
+ bts->nr, (load & 0xffffff00) >> 8, (load & 0xff) / 10);
+
+ /* Calculate new T3122 wait indicator. */
+ wait_ind = ((used / total) * max_wait_ind);
+ wait_ind >>= 8; /* convert from fixed-point to integer */
+ if (wait_ind < min_wait_ind)
+ wait_ind = min_wait_ind;
+ else if (wait_ind > max_wait_ind)
+ wait_ind = max_wait_ind;
+
+ LOGP(DRLL, LOGL_DEBUG, "(bts=%d) T3122 wait indicator set to %lu seconds\n", bts->nr, wait_ind);
+ bts->T3122 = (uint8_t)wait_ind;
+}