lynxis lazus has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-bsc/+/29788 )


Change subject: Add BTS ramping to prevent mass configuration of BTS at the 
same time
......................................................................

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 <[email protected]>
+ *
+ * Author: Alexander Couzens <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Author: Alexander Couzens <[email protected]>
+ *
+ * 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 https://gerrit.osmocom.org/c/osmo-bsc/+/29788
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Id56dde6d58f3d0d20352f6c306598d2cccc6345d
Gerrit-Change-Number: 29788
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <[email protected]>
Gerrit-MessageType: newchange

Reply via email to