From c22930e24b8d61cecb1fa7c46fd5dc96355d4978 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 17 Dec 2014 14:46:17 +0100 Subject: bts: Add some simple dependency between different BTS E.g. for the sysmoBTS2050 we have the requirement that the first board connects before the second due clocking. The easiest point to enforce this is the BSC. Add a simple bitmask based system to allow to express dependencies for IP based systems. --- openbsc/include/openbsc/gsm_data.h | 5 +++ openbsc/include/openbsc/gsm_data_shared.h | 3 ++ openbsc/src/libbsc/bsc_vty.c | 63 +++++++++++++++++++++++++++++++ openbsc/src/libbsc/bts_ipaccess_nanobts.c | 7 ++++ openbsc/src/libcommon/gsm_data.c | 58 ++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index e237ea2a6..89db48b05 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -436,4 +436,9 @@ extern const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1]; int bsc_base_ctrl_cmds_install(void); int msc_ctrl_cmds_install(void); +/* dependency handling */ +void bts_depend_mark(struct gsm_bts *bts, int dep); +void bts_depend_clear(struct gsm_bts *bts, int dep); +int bts_depend_check(struct gsm_bts *bts); + #endif /* _GSM_DATA_H */ diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 001a526bf..5d84969ae 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -720,6 +720,9 @@ struct gsm_bts { /* supported codecs beside FR */ struct bts_codec_conf codec; + + /* BTS dependencies bit field */ + uint32_t depends_on[256/(8*4)]; #endif /* ROLE_BSC */ void *role; }; diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 08f9a8e50..d6d66c638 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -650,6 +650,23 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " %sforce-combined-si%s", bts->force_combined_si ? "" : "no ", VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(bts->depends_on); ++i) { + int j; + + if (bts->depends_on[i] == 0) + continue; + + for (j = 0; j < sizeof(bts->depends_on[i]) * 8; ++j) { + int bts_nr; + + if ((bts->depends_on[i] & (1<depends_on[i]) * 8) + j; + vty_out(vty, " depends-on-bts %d%s", bts_nr, VTY_NEWLINE); + } + } + config_write_bts_model(vty, bts); } @@ -2772,6 +2789,50 @@ DEFUN(cfg_bts_codec4, cfg_bts_codec4_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_depends_on, cfg_bts_depends_on_cmd, + "depends-on-bts <0-255>", + "This BTS can only be started if another one is up\n" "BTS Number\n") +{ + struct gsm_bts *bts = vty->index; + struct gsm_bts *other_bts; + int dep = atoi(argv[0]); + + + if (!is_ipaccess_bts(bts)) { + vty_out(vty, "This feature is only available for IP systems.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + other_bts = gsm_bts_num(bts->network, dep); + if (!other_bts || !is_ipaccess_bts(other_bts)) { + vty_out(vty, "This feature is only available for IP systems.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (dep >= bts->nr) { + vty_out(vty, "%%Need to depend on an already declared unit.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + bts_depend_mark(bts, dep); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_no_depends_on, cfg_bts_no_depends_on_cmd, + "depeneds-on-bts <0-255>", + NO_STR "This BTS can only be started if another one is up\n" + "BTS Number\n") +{ + struct gsm_bts *bts = vty->index; + int dep = atoi(argv[0]); + + bts_depend_clear(bts, dep); + return CMD_SUCCESS; +} + #define TRX_TEXT "Radio Transceiver\n" /* per TRX configuration */ @@ -3383,6 +3444,8 @@ int bsc_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_codec2_cmd); install_element(BTS_NODE, &cfg_bts_codec3_cmd); install_element(BTS_NODE, &cfg_bts_codec4_cmd); + install_element(BTS_NODE, &cfg_bts_depends_on_cmd); + install_element(BTS_NODE, &cfg_bts_no_depends_on_cmd); install_element(BTS_NODE, &cfg_trx_cmd); install_node(&trx_node, dummy_config_write); diff --git a/openbsc/src/libbsc/bts_ipaccess_nanobts.c b/openbsc/src/libbsc/bts_ipaccess_nanobts.c index 9fa03bfe6..825a22e2a 100644 --- a/openbsc/src/libbsc/bts_ipaccess_nanobts.c +++ b/openbsc/src/libbsc/bts_ipaccess_nanobts.c @@ -590,6 +590,13 @@ ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line, /* remove old OML signal link for this BTS. */ ipaccess_drop_oml(bts); + if (!bts_depend_check(bts)) { + LOGP(DLINP, LOGL_NOTICE, + "Dependency not full-filled for %u/%u/%u\n", + dev->site_id, dev->bts_id, dev->trx_id); + return NULL; + } + /* create new OML link. */ sign_link = bts->oml_link = e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1], diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 03e9b85e2..73041fcec 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -364,3 +364,61 @@ int gsm_parse_reg(void *ctx, regex_t *reg, char **str, int argc, const char **ar return ret; } +/* Assume there are only 256 possible bts */ +osmo_static_assert(sizeof(((struct gsm_bts *) 0)->nr) == 1, _bts_nr_is_256); +static void depends_calc_index_bit(int bts_nr, int *idx, int *bit) +{ + *idx = bts_nr / (8 * 4); + *bit = bts_nr % (8 * 4); +} + +void bts_depend_mark(struct gsm_bts *bts, int dep) +{ + int idx, bit; + depends_calc_index_bit(dep, &idx, &bit); + + bts->depends_on[idx] |= 1 << bit; +} + +void bts_depend_clear(struct gsm_bts *bts, int dep) +{ + int idx, bit; + depends_calc_index_bit(dep, &idx, &bit); + + bts->depends_on[idx] &= ~(1 << bit); +} + +static int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other) +{ + int idx, bit; + depends_calc_index_bit(other->nr, &idx, &bit); + + /* Check if there is a depends bit */ + return (base->depends_on[idx] & (1 << bit)) > 0; +} + +static int bts_is_online(struct gsm_bts *bts) +{ + /* TODO: support E1 BTS too */ + if (!is_ipaccess_bts(bts)) + return 1; + + if (!bts->oml_link) + return 0; + + return bts->mo.nm_state.operational == NM_OPSTATE_ENABLED; +} + +int bts_depend_check(struct gsm_bts *bts) +{ + struct gsm_bts *other_bts; + + llist_for_each_entry(other_bts, &bts->network->bts_list, list) { + if (!bts_depend_is_depedency(bts, other_bts)) + continue; + if (bts_is_online(other_bts)) + continue; + return 0; + } + return 1; +} -- cgit v1.2.3 From f7e23c5ff7d28c985d6c1e6d1dc0b9e8f5895a30 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 17 Dec 2014 15:44:32 +0100 Subject: bts: When one link drops.. check what needs to be dropped In case a BTS is dropped, iterate over the list of BTS and check if a dependency is now missing and then drop the BTS. This check could lead to check of 256*256 checks (e.g. all BTS on each other in the chain and the master is being dropped). The performance aspect of it doesn't matter for our usecase. We expect to have pairs of BTS right now. --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/libbsc/bts_ipaccess_nanobts.c | 16 ++++++++++++++++ openbsc/src/libcommon/gsm_data.c | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 89db48b05..ae6757d7d 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -440,5 +440,6 @@ int msc_ctrl_cmds_install(void); void bts_depend_mark(struct gsm_bts *bts, int dep); void bts_depend_clear(struct gsm_bts *bts, int dep); int bts_depend_check(struct gsm_bts *bts); +int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other); #endif /* _GSM_DATA_H */ diff --git a/openbsc/src/libbsc/bts_ipaccess_nanobts.c b/openbsc/src/libbsc/bts_ipaccess_nanobts.c index 825a22e2a..9e1b3c2cb 100644 --- a/openbsc/src/libbsc/bts_ipaccess_nanobts.c +++ b/openbsc/src/libbsc/bts_ipaccess_nanobts.c @@ -551,6 +551,7 @@ void ipaccess_drop_rsl(struct gsm_bts_trx *trx) void ipaccess_drop_oml(struct gsm_bts *bts) { + struct gsm_bts *rdep_bts; struct gsm_bts_trx *trx; if (!bts->oml_link) @@ -564,6 +565,21 @@ void ipaccess_drop_oml(struct gsm_bts *bts) ipaccess_drop_rsl(trx); bts->ip_access.flags = 0; + + /* + * Go through the list and see if we are the depndency of a BTS + * and then drop the BTS. This can lead to some recursion but it + * should be fine in userspace. + * The oml_link is serving as recursion anchor for us and + * it is set to NULL some lines above. + */ + llist_for_each_entry(rdep_bts, &bts->network->bts_list, list) { + if (!bts_depend_is_depedency(rdep_bts, bts)) + continue; + LOGP(DLINP, LOGL_NOTICE, "Dropping BTS(%u) due BTS(%u).\n", + rdep_bts->nr, bts->nr); + ipaccess_drop_oml(rdep_bts); + } } /* This function is called once the OML/RSL link becomes up. */ diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 73041fcec..7cb1d3814 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -388,7 +388,7 @@ void bts_depend_clear(struct gsm_bts *bts, int dep) bts->depends_on[idx] &= ~(1 << bit); } -static int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other) +int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other) { int idx, bit; depends_calc_index_bit(other->nr, &idx, &bit); -- cgit v1.2.3 From d30ed6b6f2d8eb56a035354694d12f4395103edc Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 17 Dec 2014 21:21:36 +0100 Subject: ho: Make sure the timer is always stopped In case of a ho_chan_activ_nack (sent due another bug inside both sysmobts and openbsc) the code would not stop the timer but free the datastructure. This can lead to a clear segfault when the timer has expired. Create a "free" function which is responsible to detach the handover structure, stop the timer (which is idempotent) and free the structure. --- openbsc/src/libbsc/handover_logic.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 22f9883fd..9284f7ee3 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -54,6 +54,13 @@ struct bsc_handover { static LLIST_HEAD(bsc_handovers); +static void handover_free(struct bsc_handover *ho) +{ + osmo_timer_del(&ho->T3103); + llist_del(&ho->list); + talloc_free(ho); +} + static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan) { struct bsc_handover *ho; @@ -169,9 +176,7 @@ void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan) if (free_lchan) lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); - osmo_timer_del(&ho->T3103); - llist_del(&ho->list); - talloc_free(ho); + handover_free(ho); } /* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */ @@ -186,8 +191,7 @@ static void ho_T3103_cb(void *_ho) ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); - llist_del(&ho->list); - talloc_free(ho); + handover_free(ho); } /* RSL has acknowledged activation of the new lchan */ @@ -234,8 +238,7 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) new_lchan->conn->ho_lchan = NULL; new_lchan->conn = NULL; - llist_del(&ho->list); - talloc_free(ho); + handover_free(ho); /* FIXME: maybe we should try to allocate a new LCHAN here? */ @@ -282,9 +285,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE); lchan_release(ho->old_lchan, 0, RSL_REL_LOCAL_END); - llist_del(&ho->list); - talloc_free(ho); - + handover_free(ho); return 0; } @@ -293,6 +294,7 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) { struct gsm_network *net = old_lchan->ts->trx->bts->network; struct bsc_handover *ho; + struct gsm_lchan *new_lchan; ho = bsc_ho_by_old_lchan(old_lchan); if (!ho) { @@ -302,15 +304,15 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) osmo_counter_inc(net->stats.handover.failed); - osmo_timer_del(&ho->T3103); - llist_del(&ho->list); + new_lchan = ho->new_lchan; /* release the channel and forget about it */ ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; - lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); + handover_free(ho); + + lchan_release(new_lchan, 0, RSL_REL_LOCAL_END); - talloc_free(ho); return 0; } -- cgit v1.2.3 From 22fd3cd0de098de3816d687e41d42fe551412a33 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 18 Dec 2014 18:31:54 +0100 Subject: ho: Copy the multirate config to the new lchan The new lchan will be in speech mode already but for AMR we will need to provide a working multirate config in the channel activation, otherwise the channel act might be nacked. Copy the config from the current lchan into the new lchan. The abis code simply added the mrconf if the speech mode was amr. Before this commit the invalidate mrconf with all zeroes was copied/sent. --- openbsc/src/libbsc/handover_logic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 9284f7ee3..ff6e99346 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -133,6 +133,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) new_lchan->bs_power = old_lchan->bs_power; new_lchan->rsl_cmode = old_lchan->rsl_cmode; new_lchan->tch_mode = old_lchan->tch_mode; + new_lchan->mr_conf = old_lchan->mr_conf; new_lchan->conn = old_lchan->conn; new_lchan->conn->ho_lchan = new_lchan; -- cgit v1.2.3