From: Holger Hans Peter Freyther holger@moiji-mobile.com
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 e237ea2..89db48b 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 001a526..5d84969 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 08f9a8e..d6d66c6 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<<j)) == 0) + continue; + + bts_nr = (i * sizeof(bts->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 9fa03bf..825a22e 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 03e9b85..73041fc 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; +}
From: Holger Hans Peter Freyther holger@moiji-mobile.com
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 89db48b..ae6757d 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 825a22e..9e1b3c2 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 73041fc..7cb1d38 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);