aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCiaby <ciaby@rhizomatica.org>2014-12-22 14:54:23 +0100
committerCiaby <ciaby@rhizomatica.org>2014-12-22 14:54:23 +0100
commit1e12f3777ae7e659d82d8c0f390e612b146c3e9f (patch)
tree39aee1501203980b98bf28e9c6eccf0ed96de278
parentd73fb3af49ef646dc215488ec43b1bf57e9a22a6 (diff)
parent22fd3cd0de098de3816d687e41d42fe551412a33 (diff)
Merge branch 'master' into ciaby/rhizomatica-queueciaby/rhizomatica-queue
-rw-r--r--openbsc/include/openbsc/gsm_data.h6
-rw-r--r--openbsc/include/openbsc/gsm_data_shared.h3
-rw-r--r--openbsc/src/libbsc/bsc_vty.c63
-rw-r--r--openbsc/src/libbsc/bts_ipaccess_nanobts.c23
-rw-r--r--openbsc/src/libbsc/handover_logic.c31
-rw-r--r--openbsc/src/libcommon/gsm_data.c58
6 files changed, 170 insertions, 14 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index e237ea2a6..ae6757d7d 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -436,4 +436,10 @@ 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);
+int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other);
+
#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<<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 9fa03bfe6..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. */
@@ -590,6 +606,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/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c
index 817e72cfc..d04b3d6ea 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;
@@ -130,6 +137,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;
@@ -173,9 +181,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 */
@@ -190,8 +196,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 */
@@ -238,8 +243,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? */
@@ -286,9 +290,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;
}
@@ -297,6 +299,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) {
@@ -306,15 +309,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;
}
diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c
index 03e9b85e2..7cb1d3814 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);
+}
+
+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;
+}