From 9f9ce9b9cfb03392f6f00a0c495a5ca24f05bf5a Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Tue, 6 Feb 2018 17:15:34 +0100 Subject: initial acc ramping implementation (untested) Change-Id: I2b1868765346c7aba966cecd7b8db9aae9b047bb --- include/osmocom/bsc/acc_ramp.h | 59 ++++++++++++++++-- include/osmocom/bsc/gsm_data_shared.h | 1 + src/libbsc/chan_alloc.c | 6 +- src/libcommon/acc_ramp.c | 110 +++++++++++++++++++++++++++++++--- src/libcommon/gsm_data.c | 2 +- src/libcommon/gsm_data_shared.c | 2 + 6 files changed, 163 insertions(+), 17 deletions(-) diff --git a/include/osmocom/bsc/acc_ramp.h b/include/osmocom/bsc/acc_ramp.h index ad31f8f56..39f10ccad 100644 --- a/include/osmocom/bsc/acc_ramp.h +++ b/include/osmocom/bsc/acc_ramp.h @@ -44,10 +44,12 @@ enum acc_ramp_step_interval { }; struct acc_ramp { + struct gsm_bts *bts; /* backpointer to BTS using this ACC ramp */ + /* - * Bitmasks which keep track of access control classes that are currently - * denied access to this BTS. These masks modulate bits from octets 2 and 3 - * of the RACH Control Parameters (see 3GPP 44.018 10.5.2.29). + * Bitmasks which keep track of access control classes that are currently denied + * access. These masks should be used to modulate bits from octets 2 and 3 of + * the RACH Control Parameters (see 3GPP 44.018 10.5.2.29). * While a bit in these masks is set, the corresponding ACC is barred. * Note that t2 contains bits for classes 11-15 which should always be allowed, * and a bit which denies emergency calls for all ACCs from 0-9 inclusive. @@ -74,8 +76,55 @@ struct acc_ramp { struct osmo_timer_list step_timer; }; -void acc_ramp_init(struct acc_ramp *acc_ramp); +/* + * Initialize an acc_ramp data structure. + * Storage for this structure must be provided by the caller. + * The BTS which uses this ACC ramp must be provided as well to allow for automatic + * scaling of the timeout imterval based on BTS channel load average. + * All ACCs are allowed by default. Call acc_ramp_start() next to initiate the ramping process. + */ +void acc_ramp_init(struct acc_ramp *acc_ramp, struct gsm_bts *bts); + +/* Change the ramping step size. Returns negative on error (step_size out of range), else zero. */ +int acc_ramp_set_step_size(struct acc_ramp *acc_ramp, enum acc_ramp_step_size step_size); + +/* + * Change the ramping step interval to a fixed value. Unless this function is called, + * the interval is automatically scaled to the BTS channel load average. + */ +int acc_ramp_set_step_interval(struct acc_ramp *acc_ramp, unsigned int step_interval); + +/* + * Clear a previously set fixed ramping step interval, so that the interval + * is again automatically scaled to the BTS channel load average. + */ +void acc_ramp_set_step_interval_dynamic(struct acc_ramp *acc_ramp); + +/* + * Begin the ramping process. This initially sets all ACCs to denied, and then + * performs at least one ramping step to allow 'step_size' ACCs. + * If 'step_size' is ACC_RAMP_STEP_SIZE_MAX, all ACCs will be allowed immediately, + * i.e. ACC ramping becomes a no-op. + */ void acc_ramp_start(struct acc_ramp *acc_ramp); -void acc_ramp_stop(struct acc_ramp *acc_ramp); + +/* Abort the ramping process. If the process has already finished, this function has no effect. */ +void acc_ramp_abort(struct acc_ramp *acc_ramp); + +/* + * Return bitmasks which correspond to access control classes which are currently + * denied access. Ramping is only concerned with those bits which control access + * for ACCs 0-9, and any of the other bits will always be set to zero in these masks, i.e. + * it is safe to OR these bitmasks with the corresponding fields in struct gsm48_rach_control. + */ +static inline uint8_t acc_ramp_get_barred_t2(struct acc_ramp *acc_ramp) +{ + return (acc_ramp->barred_t2 & 0x03); +}; + +static inline uint8_t acc_ramp_get_barred_t3(struct acc_ramp *acc_ramp) +{ + return acc_ramp->barred_t3; +} #endif /* _ACC_RAMP_H_ */ diff --git a/include/osmocom/bsc/gsm_data_shared.h b/include/osmocom/bsc/gsm_data_shared.h index cf93b620b..9fa6d8318 100644 --- a/include/osmocom/bsc/gsm_data_shared.h +++ b/include/osmocom/bsc/gsm_data_shared.h @@ -819,6 +819,7 @@ struct gsm_bts { /* Periodic channel load measurements are used to maintain T3122. */ struct load_counter chan_load_samples[7]; int chan_load_samples_idx; + uint8_t chan_load_avg; /* current channel load average in percent (0 - 100). */ }; diff --git a/src/libbsc/chan_alloc.c b/src/libbsc/chan_alloc.c index 500ad5958..40cca93d8 100644 --- a/src/libbsc/chan_alloc.c +++ b/src/libbsc/chan_alloc.c @@ -656,8 +656,10 @@ bts_update_t3122_chan_load(struct gsm_bts *bts) 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); - osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_LOAD_AVERAGE], - (load & 0xffffff00) >> 8); + bts->chan_load_avg = ((load & 0xffffff00) >> 8); + if (bts->chan_load_avg > 100) /* sanity check; should not happen */ + bts->chan_load_avg = 100; + osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_LOAD_AVERAGE], bts->chan_load_avg); /* Calculate new T3122 wait indicator. */ wait_ind = ((used / total) * max_wait_ind); diff --git a/src/libcommon/acc_ramp.c b/src/libcommon/acc_ramp.c index c8574be2a..124ce8b00 100644 --- a/src/libcommon/acc_ramp.c +++ b/src/libcommon/acc_ramp.c @@ -17,31 +17,123 @@ * */ +#include +#include + +#include #include +#include -static void acc_ramp_timer_step(void *data) +static void deny_all_accs(struct acc_ramp *acc_ramp) { - struct acc_ramp *acc_ramp = data; + acc_ramp->barred_t2 = 0x03; /* AC8, AC9 barred */ + acc_ramp->barred_t3 = 0xff; /* AC0 - AC7 barred */ } -void acc_ramp_init(struct acc_ramp *acc_ramp) +static void allow_all_accs(struct acc_ramp *acc_ramp) { - acc_ramp->barred_t2 = 0x03; /* AC8, AC9 barred */ - acc_ramp->barred_t3 = 0xff; /* AC0 - AC7 barred */ + acc_ramp->barred_t2 = 0x00; /* AC8, AC9 allowed */ + acc_ramp->barred_t3 = 0x00; /* AC0 - AC7 allowed */ +} + +static unsigned int get_next_step_interval(struct acc_ramp *acc_ramp) +{ + struct gsm_bts *bts = acc_ramp->bts; + + if (acc_ramp->step_interval_is_fixed) + return acc_ramp->step_interval_sec; + + if (bts->chan_load_avg == 0) { + acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MIN; + } else { + /* Scale the step interval to current channel load average. */ + uint64_t load = (bts->chan_load_avg << 8); /* convert to fixed-point */ + acc_ramp->step_interval_sec = ((load * ACC_RAMP_STEP_INTERVAL_MAX) / 100) >> 8; + if (acc_ramp->step_interval_sec < ACC_RAMP_STEP_SIZE_MIN) + acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MIN; + else if (acc_ramp->step_interval_sec > ACC_RAMP_STEP_INTERVAL_MAX) + acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MAX; + } + + LOGP(DRLL, LOGL_DEBUG, "(bts=%d) ACC ramp interval set to %u sec based on %u%% load average\n", + bts->nr, acc_ramp->step_interval_sec, bts->chan_load_avg); + return acc_ramp->step_interval_sec; +} + +static void acc_ramping_step(void *data) +{ + struct acc_ramp *acc_ramp = data; + int i; + + /* Shortcut in case we only do one ramping step. */ + if (acc_ramp->step_size == ACC_RAMP_STEP_SIZE_MAX) { + allow_all_accs(acc_ramp); + return; + } + /* Allow 'step_size' ACCs, starting from ACC0. ACC9 will be allowed last. */ + for (i = 0; i < acc_ramp->step_size; i++) { + int c = ffs(acc_ramp->barred_t3); + if (c <= 0) { + c = ffs(acc_ramp->barred_t2); + if (c > 0 && c <= 2) + acc_ramp->barred_t2 &= ~(1 << (c - 1)); + return; + } + acc_ramp->barred_t3 &= ~(1 << (c - 1)); + } + + /* If we have not allowed all ACCs yet, schedule another ramping step. */ + if (acc_ramp_get_barred_t2(acc_ramp) != 0x00 || + acc_ramp_get_barred_t3(acc_ramp) != 0x00) + osmo_timer_schedule(&acc_ramp->step_timer, get_next_step_interval(acc_ramp), 0); +} + +void acc_ramp_init(struct acc_ramp *acc_ramp, struct gsm_bts *bts) +{ + acc_ramp->bts = bts; + allow_all_accs(acc_ramp); acc_ramp->step_size = ACC_RAMP_STEP_SIZE_DEFAULT; acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_DEFAULT; acc_ramp->step_interval_is_fixed = false; - osmo_timer_setup(&acc_ramp->step_timer, acc_ramp_timer_step, acc_ramp); + osmo_timer_setup(&acc_ramp->step_timer, acc_ramping_step, acc_ramp); +} + +int acc_ramp_set_step_size(struct acc_ramp *acc_ramp, enum acc_ramp_step_size step_size) +{ + if (step_size < ACC_RAMP_STEP_SIZE_MIN || step_size > ACC_RAMP_STEP_SIZE_MAX) + return -ERANGE; + + acc_ramp->step_size = step_size; + return 0; +} + +int acc_ramp_set_step_interval(struct acc_ramp *acc_ramp, unsigned int step_interval) +{ + if (step_interval < ACC_RAMP_STEP_INTERVAL_MIN || step_interval > ACC_RAMP_STEP_INTERVAL_MAX) + return -ERANGE; + + acc_ramp->step_interval_sec = step_interval; + acc_ramp->step_interval_is_fixed = true; + return 0; +} + +void acc_ramp_set_step_interval_dynamic(struct acc_ramp *acc_ramp) +{ + acc_ramp->step_interval_is_fixed = false; } void acc_ramp_start(struct acc_ramp *acc_ramp) { - acc_ramp_stop(acc_ramp); - osmo_timer_schedule(&acc_ramp->step_timer, acc_ramp->step_interval_sec, 0); + /* Abort any previously running ramping process. */ + acc_ramp_abort(acc_ramp); + + /* Set all ACCs to denied and start ramping up. */ + deny_all_accs(acc_ramp); + acc_ramping_step(acc_ramp); } -void acc_ramp_stop(struct acc_ramp *acc_ramp) +void acc_ramp_abort(struct acc_ramp *acc_ramp) { if (osmo_timer_pending(&acc_ramp->step_timer)) osmo_timer_del(&acc_ramp->step_timer); diff --git a/src/libcommon/gsm_data.c b/src/libcommon/gsm_data.c index 443481b54..7774c3b2e 100644 --- a/src/libcommon/gsm_data.c +++ b/src/libcommon/gsm_data.c @@ -261,7 +261,7 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ bts->si_common.chan_desc.t3212 = net->t3212; /* Use network's current value */ gsm_bts_set_radio_link_timeout(bts, 32); /* Use RADIO LINK TIMEOUT of 32 */ - acc_ramp_init(&bts->acc_ramp); + acc_ramp_init(&bts->acc_ramp, bts); llist_add_tail(&bts->list, &net->bts_list); diff --git a/src/libcommon/gsm_data_shared.c b/src/libcommon/gsm_data_shared.c index 57bf77d06..246e7d79e 100644 --- a/src/libcommon/gsm_data_shared.c +++ b/src/libcommon/gsm_data_shared.c @@ -396,6 +396,8 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, uint8_t bts_num) /* timer overrides */ bts->T3122 = 0; /* not overriden by default */ + bts->chan_load_avg = 0; + return bts; } -- cgit v1.2.3