lynxis lazus has uploaded this change for review.

View Change

Add BTS ramping to prevent mass configuration of BTS at the same time

Prevent BSC overloading in the event of too many BTS try to connect.
E.g. a network outage between the BSC and BTS.
The BSC will accept incoming OML connection, but will delay sending
any BSC originated messages.

Change-Id: Id56dde6d58f3d0d20352f6c306598d2cccc6345d
---
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/gsm_data.h
A include/osmocom/bsc/nm_bts_ramp.h
M include/osmocom/bsc/nm_common_fsm.h
M src/osmo-bsc/Makefile.am
M src/osmo-bsc/bsc_vty.c
M src/osmo-bsc/bts.c
M src/osmo-bsc/bts_ipaccess_nanobts.c
M src/osmo-bsc/bts_vty.c
M src/osmo-bsc/net_init.c
M src/osmo-bsc/nm_bb_transc_fsm.c
M src/osmo-bsc/nm_bts_fsm.c
A src/osmo-bsc/nm_bts_ramp.c
M src/osmo-bsc/nm_bts_sm_fsm.c
M src/osmo-bsc/nm_channel_fsm.c
M src/osmo-bsc/nm_gprs_cell_fsm.c
M src/osmo-bsc/nm_gprs_nse_fsm.c
M src/osmo-bsc/nm_gprs_nsvc_fsm.c
M src/osmo-bsc/nm_rcarrier_fsm.c
M src/osmo-bsc/osmo_bsc_main.c
20 files changed, 449 insertions(+), 14 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/88/29788/1
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index b690652..86f73c0 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -18,6 +18,7 @@
#include "osmocom/bsc/bts_sm.h"
#include "osmocom/bsc/abis_om2000.h"
#include "osmocom/bsc/paging.h"
+#include "osmocom/bsc/nm_bts_ramp.h"

enum bts_counter_id {
BTS_CTR_CHREQ_TOTAL,
@@ -662,6 +663,11 @@

struct chan_counts chan_counts;
struct all_allocated all_allocated;
+
+ struct {
+ enum bts_ramp_state state;
+ struct llist_head list;
+ } bts_ramp;
};

#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 481eae4..2ab0c1d 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -956,6 +956,15 @@
/* Don't refuse to start with mutually exclusive codec settings */
bool allow_unusable_timeslots;

+ struct {
+ unsigned count;
+ unsigned max_bts;
+
+ struct llist_head head;
+ struct osmo_timer_list timer;
+ unsigned int seconds;
+ } bts_ramp;
+
uint8_t nri_bitlen;
struct osmo_nri_ranges *null_nri_ranges;

diff --git a/include/osmocom/bsc/nm_bts_ramp.h b/include/osmocom/bsc/nm_bts_ramp.h
new file mode 100644
index 0000000..d260afa
--- /dev/null
+++ b/include/osmocom/bsc/nm_bts_ramp.h
@@ -0,0 +1,69 @@
+/* (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * Author: Alexander Couzens <acouzens@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct gsm_bts;
+struct gsm_network;
+
+enum bts_ramp_state {
+ BTS_RAMP_INIT, /** initial state */
+ BTS_RAMP_WAIT, /** BTS has to wait, too many BTS configuring */
+ BTS_RAMP_GO, /** BTS is allowed to configure */
+};
+
+bool bts_ramp_active(struct gsm_network *net);
+void bts_ramp_init_bts(struct gsm_bts *bts);
+void bts_ramp_init_network(struct gsm_network *net);
+
+/*!
+ * \brief bts_ramp_activate enable the bts ramping feature
+ * \param net a pointer to the gsm network
+ * \param max_bts allow how many bts to provision
+ * \param seconds how long the \param max_bts limits the bts
+ */
+void bts_ramp_activate(struct gsm_network *net, unsigned int max_bts, unsigned int seconds);
+void bts_ramp_deactivate(struct gsm_network *net);
+
+/*!
+ * \brief bts_ramp_wait called by the bts to check if it should wait
+ * \param bts pointer to the bts
+ * \return true if the bts should wait
+ */
+bool bts_ramp_wait(struct gsm_bts *bts);
+
+const char *bts_ramp_get_state_str(struct gsm_bts *bts);
+
+/*!
+ * \brief bts_ramp_remove a bts from the ramp waiting list
+ * \param bts pointer to the bts
+ */
+void bts_ramp_remove(struct gsm_bts *bts);
+
+/*!
+ * \brief bts_ramp_unblock_bts
+ * \param bts pointer to the bts
+ * \return 0 on success, -EINVAL when the BTS is not waiting.
+ */
+int bts_ramp_unblock_bts(struct gsm_bts *bts);
diff --git a/include/osmocom/bsc/nm_common_fsm.h b/include/osmocom/bsc/nm_common_fsm.h
index b41d24a..20126fc 100644
--- a/include/osmocom/bsc/nm_common_fsm.h
+++ b/include/osmocom/bsc/nm_common_fsm.h
@@ -38,6 +38,7 @@
NM_EV_OPSTART_ACK,
NM_EV_OPSTART_NACK,
NM_EV_OML_DOWN,
+ NM_EV_RAMP_GO, /* BTS ramp allow to continue to configure */
NM_EV_FORCE_LOCK, /* Only supported by RadioCarrier so far */
NM_EV_FEATURE_NEGOTIATED, /* Sent by BTS to NSVC MO */
NM_EV_RSL_CONNECT_ACK, /* Sent by BTS to BBTRANSC MO */
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index 40381fe..baf4c91 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -88,6 +88,7 @@
nm_bb_transc_fsm.c \
nm_bts_sm_fsm.c \
nm_bts_fsm.c \
+ nm_bts_ramp.c \
nm_gprs_cell_fsm.c \
nm_gprs_nse_fsm.c \
nm_gprs_nsvc_fsm.c \
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index 61a1559..755c375 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -44,6 +44,7 @@
#include <osmocom/bsc/abis_nm.h>
#include <osmocom/bsc/abis_om2000.h>
#include <osmocom/bsc/chan_alloc.h>
+#include <osmocom/bsc/nm_bts_ramp.h>
#include <osmocom/bsc/system_information.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/paging.h>
@@ -1279,6 +1280,38 @@
return CMD_SUCCESS;
}

+DEFUN(allow_bts_conf, allow_bts_conf_cmd,
+ "allow-bts-configuration <0-65535>",
+ "Unblock and allow to configure a BTS if kept back by BTS ramping\n"
+ BTS_NR_STR)
+{
+ struct gsm_network *gsmnet;
+ struct gsm_bts *bts;
+ unsigned int bts_nr;
+
+ gsmnet = gsmnet_from_vty(vty);
+
+ bts_nr = atoi(argv[0]);
+ if (bts_nr >= gsmnet->num_bts) {
+ vty_out(vty, "%% BTS number must be between 0 and %d. It was %d.%s",
+ gsmnet->num_bts, bts_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts = gsm_bts_num(gsmnet, bts_nr);
+ if (!bts) {
+ vty_out(vty, "%% BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bts_ramp_unblock_bts(bts)) {
+ vty_out(vty, "%% The BTS is not blocked by BTS ramping.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN(restart_bts, restart_bts_cmd,
"restart-bts <0-65535>",
"Restart ip.access nanoBTS through OML\n"
@@ -2622,6 +2655,10 @@
vty_out(vty, " bsc-auto-rf-off %d%s",
bsc_gsmnet->auto_off_timeout, VTY_NEWLINE);

+ if (bsc_gsmnet->bts_ramp.max_bts > 0)
+ vty_out(vty, " bts ramp limit %d within %d seconds%s",
+ bsc_gsmnet->bts_ramp.max_bts, bsc_gsmnet->bts_ramp.seconds, VTY_NEWLINE);
+
return CMD_SUCCESS;
}

@@ -3045,6 +3082,46 @@
return CMD_SUCCESS;
}

+DEFUN_ATTR(cfg_bsc_bts_ramp,
+ cfg_bsc_bts_ramp_cmd,
+ "bts ramp limit <0-999> within <0-999> seconds",
+ "Set BTS ramping to limit the number of BTS which configure within a time window.\n"
+ "Set BTS ramping to limit the number of BTS which configure within a time window.\n"
+ "Set BTS ramping to limit the number of BTS which configure within a time window.\n"
+ "Number of BTS\n"
+ "Set BTS ramping to limit the number of BTS which configure within a time window.\n"
+ "Number of seconds\n"
+ "Set BTS ramping to limit the number of BTS which configure within a time window.\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_network *net = gsmnet_from_vty(vty);
+
+ int max_bts = atoi(argv[0]);
+ int seconds = atoi(argv[1]);
+
+ if (max_bts == 0)
+ bts_ramp_deactivate(net);
+ else
+ bts_ramp_activate(net, max_bts, seconds);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bsc_no_bts_ramp,
+ cfg_bsc_no_bts_ramp_cmd,
+ "no bts ramp limit",
+ NO_STR
+ "Disable BTS ramping and configure all waiting BTS.\n"
+ "Disable BTS ramping and configure all waiting BTS.\n"
+ "Disable BTS ramping and configure all waiting BTS.\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_network *net = gsmnet_from_vty(vty);
+
+ bts_ramp_deactivate(net);
+ return CMD_SUCCESS;
+}
+
DEFUN(show_statistics,
show_statistics_cmd,
"show statistics",
@@ -3459,6 +3536,7 @@

install_element(ENABLE_NODE, &drop_bts_cmd);
install_element(ENABLE_NODE, &restart_bts_cmd);
+ install_element(ENABLE_NODE, &allow_bts_conf_cmd);
install_element(ENABLE_NODE, &bts_resend_sysinfo_cmd);
install_element(ENABLE_NODE, &bts_resend_power_ctrl_params_cmd);
install_element(ENABLE_NODE, &bts_c0_power_red_cmd);
@@ -3499,6 +3577,8 @@
install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd);
install_element(BSC_NODE, &cfg_net_bsc_missing_msc_ussd_cmd);
install_element(BSC_NODE, &cfg_net_bsc_no_missing_msc_text_cmd);
+ install_element(BSC_NODE, &cfg_bsc_bts_ramp_cmd);
+ install_element(BSC_NODE, &cfg_bsc_no_bts_ramp_cmd);

install_node(&msc_node, config_write_msc);
install_element(MSC_NODE, &cfg_net_bsc_ncc_cmd);
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index b7d3c3c..ea0b0d6 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -145,6 +145,7 @@
static int gsm_bts_talloc_destructor(struct gsm_bts *bts)
{
paging_destructor(bts);
+ bts_ramp_remove(bts);

osmo_timer_del(&bts->cbch_timer);

diff --git a/src/osmo-bsc/bts_ipaccess_nanobts.c b/src/osmo-bsc/bts_ipaccess_nanobts.c
index 624aabc..3e58c3e 100644
--- a/src/osmo-bsc/bts_ipaccess_nanobts.c
+++ b/src/osmo-bsc/bts_ipaccess_nanobts.c
@@ -619,6 +619,8 @@
e1inp_sign_link_destroy(bts->osmo_link);
bts->osmo_link = NULL;

+ bts_ramp_remove(bts);
+
/* we have issues reconnecting RSL, drop everything. */
llist_for_each_entry(trx, &bts->trx_list, list) {
ipaccess_drop_rsl(trx, "OML link drop");
diff --git a/src/osmo-bsc/bts_vty.c b/src/osmo-bsc/bts_vty.c
index 2348b87..966745a 100644
--- a/src/osmo-bsc/bts_vty.c
+++ b/src/osmo-bsc/bts_vty.c
@@ -3984,6 +3984,8 @@
vty_out(vty, " OML Link: ");
e1isl_dump_vty_tcp(vty, bts->oml_link);
vty_out(vty, " OML Link state: %s", get_model_oml_status(bts));
+ if (bts_ramp_active(bts->network))
+ vty_out(vty, " BTS Ramping: %s", bts_ramp_get_state_str(bts));
sec = bts_uptime(bts);
if (sec)
vty_out(vty, " %llu days %llu hours %llu min. %llu sec.",
diff --git a/src/osmo-bsc/net_init.c b/src/osmo-bsc/net_init.c
index 8a8c0a6..e95e305 100644
--- a/src/osmo-bsc/net_init.c
+++ b/src/osmo-bsc/net_init.c
@@ -25,6 +25,7 @@
#include <osmocom/bsc/handover_cfg.h>
#include <osmocom/bsc/chan_alloc.h>
#include <osmocom/bsc/neighbor_ident.h>
+#include <osmocom/bsc/nm_bts_ramp.h>

static struct osmo_tdef gsm_network_T_defs[] = {
{ .T=4, .default_val=5, .desc="Timeout to receive BSSMAP RESET ACKNOWLEDGE from the MSC" },
@@ -124,5 +125,7 @@
net->null_nri_ranges = osmo_nri_ranges_alloc(net);
net->nri_bitlen = OSMO_NRI_BITLEN_DEFAULT;

+ bts_ramp_init_network(net);
+
return net;
}
diff --git a/src/osmo-bsc/nm_bb_transc_fsm.c b/src/osmo-bsc/nm_bb_transc_fsm.c
index 3a8786b..a637758 100644
--- a/src/osmo-bsc/nm_bb_transc_fsm.c
+++ b/src/osmo-bsc/nm_bb_transc_fsm.c
@@ -105,6 +105,9 @@
{
struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);

+ if (bts_ramp_wait(trx->bts))
+ return;
+
/* Request TRX-level attributes */
if (!bb_transc->mo.get_attr_sent && !bb_transc->mo.get_attr_rep_received) {
bb_transc->mo.get_attr_sent = true;
@@ -339,6 +342,10 @@
nm_bb_transc_fsm_state_chg(fi, NM_BB_TRANSC_ST_OP_DISABLED_NOTINSTALLED);
}
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_BB_TRANSC_ST_OP_ENABLED)
+ configure_loop(bb_transc, &bb_transc->mo.nm_state, fi->state == NM_BB_TRANSC_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -405,7 +412,8 @@
.allstate_event_mask =
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_bts_fsm.c b/src/osmo-bsc/nm_bts_fsm.c
index 1b71323..eb221ff 100644
--- a/src/osmo-bsc/nm_bts_fsm.c
+++ b/src/osmo-bsc/nm_bts_fsm.c
@@ -88,10 +88,16 @@
}
}

-static void configure_loop(struct gsm_bts *bts, const struct gsm_nm_state *state, bool allow_opstart)
+static void configure_loop(
+ struct gsm_bts *bts,
+ const struct gsm_nm_state *state,
+ bool allow_opstart)
{
struct msgb *msgb;

+ if (bts_ramp_wait(bts))
+ return;
+
/* Request generic BTS-level attributes */
if (!bts->mo.get_attr_sent && !bts->mo.get_attr_rep_received) {
bts->mo.get_attr_sent = true;
@@ -320,6 +326,10 @@
if (fi->state != NM_BTS_ST_OP_DISABLED_NOTINSTALLED)
nm_bts_fsm_state_chg(fi, NM_BTS_ST_OP_DISABLED_NOTINSTALLED);
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_BTS_ST_OP_ENABLED)
+ configure_loop(bts, &bts->mo.nm_state, fi->state == NM_BTS_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -384,7 +394,8 @@
.allstate_event_mask =
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_bts_ramp.c b/src/osmo-bsc/nm_bts_ramp.c
new file mode 100644
index 0000000..94d0a67
--- /dev/null
+++ b/src/osmo-bsc/nm_bts_ramp.c
@@ -0,0 +1,174 @@
+/* (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * Author: Alexander Couzens <acouzens@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdbool.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/bts_sm.h>
+#include <osmocom/bsc/nm_bts_ramp.h>
+#include <osmocom/bsc/nm_common_fsm.h>
+
+
+static void _bts_ramp_unblock_bts(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+
+ llist_del(&bts->bts_ramp.list);
+ bts->bts_ramp.state = BTS_RAMP_GO;
+
+ /* inform all MOs */
+ osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_RAMP_GO, NULL);
+ osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_RAMP_GO, NULL);
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_RAMP_GO, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_RAMP_GO, NULL);
+ for (unsigned long i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_RAMP_GO, NULL);
+ }
+ }
+
+ /* GPRS MOs */
+ osmo_fsm_inst_dispatch(bts->site_mgr->gprs.nse.mo.fi, NM_EV_RAMP_GO, NULL);
+ for (unsigned long i = 0; i < ARRAY_SIZE(bts->site_mgr->gprs.nsvc); i++)
+ osmo_fsm_inst_dispatch(bts->site_mgr->gprs.nsvc[i].mo.fi, NM_EV_RAMP_GO, NULL);
+ osmo_fsm_inst_dispatch(bts->gprs.cell.mo.fi, NM_EV_RAMP_GO, NULL);
+}
+
+int bts_ramp_unblock_bts(struct gsm_bts *bts)
+{
+ if (llist_entry_empty(&bts->bts_ramp.list))
+ return -EINVAL;
+
+ _bts_ramp_unblock_bts(bts);
+ return 0;
+}
+
+
+/*!
+ * \brief bts_ramp_timer_cb timer callback and called by bts_ramp_deactivate
+ * \param _net pointer to struct gsm_network
+ */
+static void bts_ramp_timer_cb(void *_net)
+{
+ struct gsm_network *net = (struct gsm_network *) _net;
+ struct gsm_bts *bts, *n;
+ net->bts_ramp.count = 0;
+
+ llist_for_each_entry_safe(bts, n, &net->bts_ramp.head, bts_ramp.list) {
+ net->bts_ramp.count++;
+ _bts_ramp_unblock_bts(bts);
+ LOG_BTS(bts, DNM, LOGL_INFO, "Unblock BTS %d from BTS ramping.\n", bts->nr);
+ if (bts_ramp_active(net) &&
+ net->bts_ramp.count >= net->bts_ramp.max_bts)
+ break;
+ }
+
+ if (net->bts_ramp.max_bts > 0)
+ osmo_timer_schedule(&net->bts_ramp.timer, net->bts_ramp.seconds, 0);
+}
+
+const struct value_string bts_ramp_state_values[] = {
+ { BTS_RAMP_INIT, "Initial" },
+ { BTS_RAMP_WAIT, "Waiting" },
+ { BTS_RAMP_GO, "Go" },
+ { 0, NULL },
+};
+
+const char *bts_ramp_get_state_str(struct gsm_bts *bts)
+{
+ return get_value_string_or_null(bts_ramp_state_values, bts->bts_ramp.state);
+}
+
+void bts_ramp_activate(struct gsm_network *net, unsigned int max_bts, unsigned int seconds)
+{
+ net->bts_ramp.max_bts = max_bts;
+ net->bts_ramp.seconds = seconds;
+ osmo_timer_schedule(&net->bts_ramp.timer, seconds, 0);
+}
+
+void bts_ramp_deactivate(struct gsm_network *net)
+{
+ net->bts_ramp.max_bts = 0;
+ /* clear bts list */
+ bts_ramp_timer_cb(net);
+ osmo_timer_del(&net->bts_ramp.timer);
+}
+
+bool bts_ramp_active(struct gsm_network *net)
+{
+ return net->bts_ramp.max_bts > 0;
+}
+
+bool bts_ramp_wait(struct gsm_bts *bts)
+{
+ struct gsm_network *net = bts->network;
+
+ if (!bts_ramp_active(net))
+ return false;
+
+ switch (bts->bts_ramp.state) {
+ case BTS_RAMP_INIT:
+ break;
+ case BTS_RAMP_WAIT:
+ return true;
+ case BTS_RAMP_GO:
+ return false;
+ }
+
+ if (net->bts_ramp.count < net->bts_ramp.max_bts) {
+ OSMO_ASSERT(llist_entry_empty(&bts->bts_ramp.list));
+ LOG_BTS(bts, DNM, LOGL_INFO,
+ "BTS %d can configure without waiting for BTS ramping.\n", bts->nr);
+
+ net->bts_ramp.count++;
+ bts->bts_ramp.state = BTS_RAMP_GO;
+ return false;
+ }
+
+ bts->bts_ramp.state = BTS_RAMP_WAIT;
+ llist_add_tail(&bts->bts_ramp.list, &net->bts_ramp.head);
+ LOGP(DNM, LOGL_INFO, "BTS %d will wait for BTS ramping.\n", bts->nr);
+
+ return true;
+}
+
+void bts_ramp_init_network(struct gsm_network *net)
+{
+ INIT_LLIST_HEAD(&net->bts_ramp.head);
+ osmo_timer_setup(&net->bts_ramp.timer, bts_ramp_timer_cb, net);
+}
+
+void bts_ramp_init_bts(struct gsm_bts *bts)
+{
+ bts->bts_ramp.state = BTS_RAMP_INIT;
+}
+
+void bts_ramp_remove(struct gsm_bts *bts)
+{
+ if (!llist_entry_empty(&bts->bts_ramp.list))
+ llist_del(&bts->bts_ramp.list);
+}
diff --git a/src/osmo-bsc/nm_bts_sm_fsm.c b/src/osmo-bsc/nm_bts_sm_fsm.c
index 03bf43c..59f0999 100644
--- a/src/osmo-bsc/nm_bts_sm_fsm.c
+++ b/src/osmo-bsc/nm_bts_sm_fsm.c
@@ -99,6 +99,20 @@
}
}

+static void configure_loop(struct gsm_bts_sm *site_mgr)
+{
+ struct gsm_bts *bts = gsm_bts_sm_get_bts(site_mgr);
+
+ if (bts_ramp_wait(bts))
+ return;
+
+ if (!site_mgr->mo.opstart_sent) {
+ site_mgr->mo.opstart_sent = true;
+ abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
+ }
+}
+
+
static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nm_statechg_signal_data *nsd;
@@ -132,11 +146,8 @@
static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
- struct gsm_bts *bts = gsm_bts_sm_get_bts(site_mgr);
- if (!site_mgr->mo.opstart_sent) {
- site_mgr->mo.opstart_sent = true;
- abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
- }
+
+ configure_loop(site_mgr);
}

static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -144,7 +155,16 @@
struct nm_statechg_signal_data *nsd;
const struct gsm_nm_state *new_state;

+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+ struct gsm_bts *bts = gsm_bts_sm_get_bts(site_mgr);
+
switch (event) {
+ case NM_EV_RAMP_GO:
+ if (!site_mgr->mo.opstart_sent) {
+ site_mgr->mo.opstart_sent = true;
+ abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
+ }
+ break;
case NM_EV_STATE_CHG_REP:
nsd = (struct nm_statechg_signal_data *)data;
new_state = &nsd->new_state;
@@ -170,6 +190,7 @@
OSMO_ASSERT(0);
}
}
+
static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nm_statechg_signal_data *nsd;
@@ -215,6 +236,10 @@
if (fi->state != NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED)
nm_bts_sm_fsm_state_chg(fi, NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED);
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_BTS_SM_ST_OP_ENABLED)
+ configure_loop(site_mgr);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -273,7 +298,8 @@
.allstate_event_mask =
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_channel_fsm.c b/src/osmo-bsc/nm_channel_fsm.c
index c3146a4..093152e 100644
--- a/src/osmo-bsc/nm_channel_fsm.c
+++ b/src/osmo-bsc/nm_channel_fsm.c
@@ -92,6 +92,9 @@
enum abis_nm_chan_comb ccomb;
struct gsm_bts_trx *trx = ts->trx;

+ if (bts_ramp_wait(ts->trx->bts))
+ return;
+
if (!ts->mo.set_attr_sent && !ts->mo.set_attr_ack_received) {
ts->mo.set_attr_sent = true;
ccomb = abis_nm_chcomb4pchan(ts->pchan_from_config);
@@ -276,6 +279,10 @@
if (fi->state != NM_CHAN_ST_OP_DISABLED_NOTINSTALLED)
nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_NOTINSTALLED);
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_CHAN_ST_OP_ENABLED)
+ configure_loop(ts, &ts->mo.nm_state, fi->state == NM_CHAN_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -338,7 +345,8 @@
.allstate_event_mask =
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_gprs_cell_fsm.c b/src/osmo-bsc/nm_gprs_cell_fsm.c
index aabfc0b..cee537b 100644
--- a/src/osmo-bsc/nm_gprs_cell_fsm.c
+++ b/src/osmo-bsc/nm_gprs_cell_fsm.c
@@ -94,6 +94,9 @@
if (bts->gprs.mode == BTS_GPRS_NONE)
return;

+ if (bts_ramp_wait(bts))
+ return;
+
if (!cell->mo.set_attr_sent && !cell->mo.set_attr_ack_received) {
cell->mo.set_attr_sent = true;
msgb = nanobts_gen_set_cell_attr(bts);
@@ -294,6 +297,10 @@
if (fi->state != NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED)
nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED);
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_GPRS_CELL_ST_OP_ENABLED)
+ configure_loop(cell, &cell->mo.nm_state, fi->state == NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -357,7 +364,8 @@
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
X(NM_EV_FORCE_LOCK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_gprs_nse_fsm.c b/src/osmo-bsc/nm_gprs_nse_fsm.c
index 49908ce..ae68a6b 100644
--- a/src/osmo-bsc/nm_gprs_nse_fsm.c
+++ b/src/osmo-bsc/nm_gprs_nse_fsm.c
@@ -93,6 +93,9 @@
struct gsm_bts_sm *bts_sm = container_of(nse, struct gsm_bts_sm, gprs.nse);
struct gsm_bts *bts = gsm_bts_sm_get_bts(bts_sm);

+ if (bts_ramp_wait(bts))
+ return;
+
if (!nse->mo.set_attr_sent && !nse->mo.set_attr_ack_received) {
nse->mo.set_attr_sent = true;
msgb = nanobts_gen_set_nse_attr(bts_sm);
@@ -296,6 +299,10 @@
if (fi->state != NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED)
nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED);
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_GPRS_NSE_ST_OP_ENABLED)
+ configure_loop(nse, &nse->mo.nm_state, fi->state == NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -359,7 +366,8 @@
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
X(NM_EV_FORCE_LOCK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_gprs_nsvc_fsm.c b/src/osmo-bsc/nm_gprs_nsvc_fsm.c
index 29eed5c..5e649b4 100644
--- a/src/osmo-bsc/nm_gprs_nsvc_fsm.c
+++ b/src/osmo-bsc/nm_gprs_nsvc_fsm.c
@@ -97,6 +97,9 @@
if (nsvc->bts->gprs.mode == BTS_GPRS_NONE)
return;

+ if (bts_ramp_wait(nsvc->bts))
+ return;
+
/* We need to know BTS features in order to know if we can set IPv6 addresses */
if (gsm_bts_features_negotiated(nsvc->bts) && !nsvc->mo.set_attr_sent &&
!nsvc->mo.set_attr_ack_received) {
@@ -305,6 +308,10 @@
if (fi->state != NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED)
nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED);
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_GPRS_NSVC_ST_OP_ENABLED)
+ configure_loop(nsvc, &nsvc->mo.nm_state, fi->state == NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -370,7 +377,8 @@
.allstate_event_mask =
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/nm_rcarrier_fsm.c b/src/osmo-bsc/nm_rcarrier_fsm.c
index c8b95ad..04d0c41 100644
--- a/src/osmo-bsc/nm_rcarrier_fsm.c
+++ b/src/osmo-bsc/nm_rcarrier_fsm.c
@@ -100,6 +100,9 @@
{
struct msgb *msgb;

+ if (bts_ramp_wait(trx->bts))
+ return;
+
if (!trx->mo.set_attr_sent && !trx->mo.set_attr_ack_received) {
trx->mo.set_attr_sent = true;
msgb = nanobts_gen_set_radio_attr(trx->bts, trx);
@@ -317,6 +320,10 @@
nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED);
}
break;
+ case NM_EV_RAMP_GO:
+ if (fi->state != NM_BTS_ST_OP_ENABLED)
+ configure_loop(trx, &trx->mo.nm_state, fi->state == NM_RCARRIER_ST_OP_DISABLED_OFFLINE);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -380,7 +387,8 @@
X(NM_EV_OPSTART_ACK) |
X(NM_EV_OPSTART_NACK) |
X(NM_EV_FORCE_LOCK) |
- X(NM_EV_OML_DOWN),
+ X(NM_EV_OML_DOWN) |
+ X(NM_EV_RAMP_GO),
.allstate_action = st_op_allstate,
.event_names = nm_fsm_event_names,
.log_subsys = DNM,
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
index 920693f..fd630a0 100644
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ b/src/osmo-bsc/osmo_bsc_main.c
@@ -401,6 +401,8 @@
bts->si_common.chan_desc.ccch_conf = (n << 1);
}

+ bts_ramp_init_bts(bts);
+
/* ACC ramping is initialized from vty/config */

/* Initialize the BTS state */

To view, visit change 29788. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Id56dde6d58f3d0d20352f6c306598d2cccc6345d
Gerrit-Change-Number: 29788
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <lynxis@fe80.eu>
Gerrit-MessageType: newchange