diff options
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/chan_alloc.h | 6 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 3 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_data_shared.h | 13 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_rsl.c | 38 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_init.c | 2 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_vty.c | 2 | ||||
-rw-r--r-- | openbsc/src/libbsc/chan_alloc.c | 75 | ||||
-rw-r--r-- | openbsc/src/libbsc/net_init.c | 24 | ||||
-rw-r--r-- | openbsc/src/libcommon/gsm_data_shared.c | 3 | ||||
-rw-r--r-- | openbsc/tests/channel/Makefile.am | 5 | ||||
-rw-r--r-- | openbsc/tests/channel/channel_test.c | 11 |
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; |