aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
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
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')
-rw-r--r--openbsc/include/openbsc/chan_alloc.h6
-rw-r--r--openbsc/include/openbsc/gsm_data.h3
-rw-r--r--openbsc/include/openbsc/gsm_data_shared.h13
-rw-r--r--openbsc/src/libbsc/abis_rsl.c38
-rw-r--r--openbsc/src/libbsc/bsc_init.c2
-rw-r--r--openbsc/src/libbsc/bsc_vty.c2
-rw-r--r--openbsc/src/libbsc/chan_alloc.c75
-rw-r--r--openbsc/src/libbsc/net_init.c24
-rw-r--r--openbsc/src/libcommon/gsm_data_shared.c3
-rw-r--r--openbsc/tests/channel/Makefile.am5
-rw-r--r--openbsc/tests/channel/channel_test.c11
11 files changed, 153 insertions, 29 deletions
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index 78242e5b7..0ba3f9669 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -37,17 +37,13 @@ void lchan_reset(struct gsm_lchan *lchan);
/* Release the given lchan */
int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode release_mode);
-struct load_counter {
- unsigned int total;
- unsigned int used;
-};
-
struct pchan_load {
struct load_counter pchan[_GSM_PCHAN_MAX];
};
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts);
void network_chan_load(struct pchan_load *pl, struct gsm_network *net);
+void bts_update_t3122_chan_load(struct gsm_bts *bts);
int trx_is_usable(struct gsm_bts_trx *trx);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 39c7458ca..b12c4edc3 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -372,6 +372,9 @@ struct gsm_network {
/* timer to expire old location updates */
struct osmo_timer_list subscr_expire_timer;
+ /* Timer for periodic channel load measurements to maintain each BTS's T3122. */
+ struct osmo_timer_list t3122_chan_load_timer;
+
/* Radio Resource Location Protocol (TS 04.31) */
struct {
enum rrlp_mode mode;
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index 30feedcab..a78e2eb7a 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -674,6 +674,12 @@ struct bts_location {
double height;
};
+/* Channel load counter */
+struct load_counter {
+ unsigned int total;
+ unsigned int used;
+};
+
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
@@ -901,6 +907,13 @@ struct gsm_bts {
char *pcu_sock_path;
struct pcu_sock_state *pcu_state;
+ /* BTS-specific overrides for timer values from struct gsm_network. */
+ uint8_t T3122; /* ASSIGMENT REJECT wait indication */
+
+ /* Periodic channel load measurements are used to maintain T3122. */
+ struct load_counter chan_load_samples[7];
+ int chan_load_samples_idx;
+
#endif /* ROLE_BSC */
void *role;
};
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c
index 0ce27484c..f05344a05 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -1744,8 +1744,7 @@ static void t3109_expired(void *data)
/* Format an IMM ASS REJ according to 04.08 Chapter 9.1.20 */
static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
- unsigned int num_req_refs,
- struct gsm48_req_ref *rqd_refs,
+ struct gsm48_req_ref *rqd_ref,
uint8_t wait_ind)
{
uint8_t buf[GSM_MACBLOCK_LEN];
@@ -1757,25 +1756,22 @@ static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
iar->msg_type = GSM48_MT_RR_IMM_ASS_REJ;
iar->page_mode = GSM48_PM_SAME;
- memcpy(&iar->req_ref1, &rqd_refs[0], sizeof(iar->req_ref1));
+ /*
+ * Set all request references and wait indications to the same value.
+ * 3GPP TS 44.018 v4.5.0 release 4 (section 9.1.20.2) requires that
+ * we duplicate reference and wait indication to fill the message.
+ * The BTS will aggregate up to 4 of our ASS REJ messages if possible.
+ */
+ memcpy(&iar->req_ref1, rqd_ref, sizeof(iar->req_ref1));
iar->wait_ind1 = wait_ind;
- if (num_req_refs >= 2)
- memcpy(&iar->req_ref2, &rqd_refs[1], sizeof(iar->req_ref2));
- else
- memcpy(&iar->req_ref2, &rqd_refs[0], sizeof(iar->req_ref2));
+ memcpy(&iar->req_ref2, rqd_ref, sizeof(iar->req_ref2));
iar->wait_ind2 = wait_ind;
- if (num_req_refs >= 3)
- memcpy(&iar->req_ref3, &rqd_refs[2], sizeof(iar->req_ref3));
- else
- memcpy(&iar->req_ref3, &rqd_refs[0], sizeof(iar->req_ref3));
+ memcpy(&iar->req_ref3, rqd_ref, sizeof(iar->req_ref3));
iar->wait_ind3 = wait_ind;
- if (num_req_refs >= 4)
- memcpy(&iar->req_ref4, &rqd_refs[3], sizeof(iar->req_ref4));
- else
- memcpy(&iar->req_ref4, &rqd_refs[0], sizeof(iar->req_ref4));
+ memcpy(&iar->req_ref4, rqd_ref, sizeof(iar->req_ref4));
iar->wait_ind4 = wait_ind;
/* we need to subtract 1 byte from sizeof(*iar) since ia includes the l2_plen field */
@@ -1870,12 +1866,18 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
/* check availability / allocate channel */
lchan = lchan_alloc(bts, lctype, is_lu);
if (!lchan) {
+ uint8_t wait_ind;
LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]);
- /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */
- if (bts->network->T3122)
- rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff);
+ if (bts->T3122)
+ wait_ind = bts->T3122;
+ else if (bts->network->T3122)
+ wait_ind = bts->network->T3122 & 0xff;
+ else
+ wait_ind = GSM_T3122_DEFAULT;
+ /* The BTS will gather multiple CHAN RQD and reject up to 4 MS at the same time. */
+ rsl_send_imm_ass_rej(bts, rqd_ref, wait_ind);
return 0;
}
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 36531d2d8..4cfe20a04 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -507,6 +507,8 @@ static int bootstrap_bts(struct gsm_bts *bts)
bts->si_common.ncc_permitted = 0xff;
+ bts->chan_load_samples_idx = 0;
+
/* Initialize the BTS state */
gsm_bts_mo_reset(bts);
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 3daa262c4..fd77fabb0 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -1597,7 +1597,7 @@ DECLARE_TIMER(3113, "Set the time to try paging a subscriber")
DECLARE_TIMER(3115, "Currently not used")
DECLARE_TIMER(3117, "Currently not used")
DECLARE_TIMER(3119, "Currently not used")
-DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT")
+DECLARE_TIMER(3122, "Default waiting time (seconds) after IMM ASS REJECT")
DECLARE_TIMER(3141, "Currently not used")
DEFUN_DEPRECATED(cfg_net_dtx,
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;
+}
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 9d5431964..08e2bd6c3 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -20,6 +20,22 @@
#include <openbsc/common_cs.h>
#include <openbsc/osmo_bsc.h>
#include <openbsc/bsc_msc_data.h>
+#include <openbsc/chan_alloc.h>
+
+/* XXX hard-coded for now */
+#define T3122_CHAN_LOAD_SAMPLE_INTERVAL 1 /* in seconds */
+
+static void update_t3122_chan_load_timer(void *data)
+{
+ struct gsm_network *net = data;
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list)
+ bts_update_t3122_chan_load(bts);
+
+ /* Keep this timer ticking. */
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+}
struct gsm_network *bsc_network_init(void *ctx,
uint16_t country_code,
@@ -66,6 +82,14 @@ struct gsm_network *bsc_network_init(void *ctx,
INIT_LLIST_HEAD(&net->bts_list);
+ /*
+ * At present all BTS in the network share one channel load timeout.
+ * If this becomes a problem for networks with a lot of BTS, this
+ * code could be refactored to run the timeout individually per BTS.
+ */
+ osmo_timer_setup(&net->t3122_chan_load_timer, update_t3122_chan_load_timer, net);
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+
/* init statistics */
net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0);
if (!net->bsc_ctrs) {
diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c
index 26962730a..a1d7a50b4 100644
--- a/openbsc/src/libcommon/gsm_data_shared.c
+++ b/openbsc/src/libcommon/gsm_data_shared.c
@@ -364,6 +364,9 @@ struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
/* si handling */
bts->bcch_change_mark = 1;
+ /* timer overrides */
+ bts->T3122 = 0; /* not overriden by default */
+
return bts;
}
diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am
index ca470ace4..5fec00af4 100644
--- a/openbsc/tests/channel/Makefile.am
+++ b/openbsc/tests/channel/Makefile.am
@@ -23,6 +23,10 @@ channel_test_SOURCES = \
channel_test.c \
$(NULL)
+channel_test_LDFLAGS = \
+ -Wl,--wrap=paging_request \
+ $(NULL)
+
channel_test_LDADD = \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
@@ -30,6 +34,7 @@ channel_test_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
$(LIBCRYPTO_LIBS) \
-ldbi \
$(NULL)
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index 049786be7..428182f1e 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -48,8 +48,10 @@ static int subscr_cb(unsigned int hook, unsigned int event, struct msgb *msg, vo
return 0;
}
-/* mock object for testing, directly invoke the cb... maybe later through the timer */
-int paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
+/* override, requires '-Wl,--wrap=paging_request'.
+/ mock object for testing, directly invoke the cb... maybe later through the timer */
+int __real_paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data);
+int __wrap_paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
{
s_data = data;
s_cbfn = cbfn;
@@ -160,13 +162,12 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
}
-void _abis_nm_sendmsg() {}
void sms_alloc() {}
void sms_free() {}
-void gsm_net_update_ctype(struct gsm_network *network) {}
void gsm48_secure_channel() {}
-void paging_request_stop() {}
void vty_out() {}
+void switch_trau_mux() {}
+void rtp_socket_free() {}
struct tlv_definition nm_att_tlvdef;