diff options
Diffstat (limited to 'src/osmo-bsc/osmo_bsc_main.c')
-rw-r--r-- | src/osmo-bsc/osmo_bsc_main.c | 460 |
1 files changed, 258 insertions, 202 deletions
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c index 7eaa18ffd..5ad13ca34 100644 --- a/src/osmo-bsc/osmo_bsc_main.c +++ b/src/osmo-bsc/osmo_bsc_main.c @@ -57,6 +57,7 @@ #include <osmocom/vty/cpu_sched_vty.h> #include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h> +#include <osmocom/mgcp_client/mgcp_client_pool.h> #include <osmocom/abis/abis.h> #include <osmocom/bsc/abis_om2000.h> @@ -67,8 +68,10 @@ #include <osmocom/bsc/codec_pref.h> #include <osmocom/bsc/system_information.h> #include <osmocom/bsc/bts.h> +#include <osmocom/bsc/bsc_stats.h> #include <osmocom/mgcp_client/mgcp_client.h> +#include <osmocom/mgcp_client/mgcp_client_pool.h> #include <osmocom/sigtran/xua_msg.h> @@ -84,19 +87,18 @@ #include "../../bscconfig.h" -struct gsm_network *bsc_gsmnet = 0; static const char *config_file = "osmo-bsc.cfg"; static const char *rf_ctrl = NULL; static int daemonize = 0; -static void print_usage() +static void print_usage(void) { printf("Usage: osmo-bsc\n"); } -static void print_help() +static void print_help(void) { - printf(" Some useful help...\n"); + printf("Some useful options:\n"); printf(" -h --help This text.\n"); printf(" -D --daemonize Fork the process into a background daemon.\n"); printf(" -d --debug option --debug=DRLL:DMM:DRR:DRSL:DNM enable debugging.\n"); @@ -104,11 +106,37 @@ static void print_help() printf(" -T --timestamp Print a timestamp in the debug output.\n"); printf(" -V --version Print the version of OsmoBSC.\n"); printf(" -c --config-file filename The config file to use.\n"); - printf(" -l --local IP The local address of the MGCP.\n"); printf(" -e --log-level number Set a global loglevel.\n"); printf(" -r --rf-ctl NAME A unix domain socket to listen for cmds.\n"); - printf(" -t --testmode A special mode to provoke failures at the MSC.\n"); - printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n"); + + printf("\nVTY reference generation:\n"); + printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"); + printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n"); +} + +static void handle_long_options(const char *prog_name, const int long_option) +{ + static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT; + + switch (long_option) { + case 1: + vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg); + if (vty_ref_mode < 0) { + fprintf(stderr, "%s: Unknown VTY reference generation " + "mode '%s'\n", prog_name, optarg); + exit(2); + } + break; + case 2: + fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n", + get_value_string(vty_ref_gen_mode_names, vty_ref_mode), + get_value_string(vty_ref_gen_mode_desc, vty_ref_mode)); + vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode); + exit(0); + default: + fprintf(stderr, "%s: error parsing cmdline options\n", prog_name); + exit(2); + } } static void handle_options(int argc, char **argv) @@ -124,15 +152,14 @@ static void handle_options(int argc, char **argv) {"disable-color", 0, 0, 's'}, {"timestamp", 0, 0, 'T'}, {"version", 0, 0, 'V' }, - {"local", 1, 0, 'l'}, {"log-level", 1, 0, 'e'}, {"rf-ctl", 1, 0, 'r'}, - {"testmode", 0, 0, 't'}, - {"vty-ref-xml", 0, &long_option, 1}, + {"vty-ref-mode", 1, &long_option, 1}, + {"vty-ref-xml", 0, &long_option, 2}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hd:DsTVc:e:r:t", + c = getopt_long(argc, argv, "hd:DsTVc:e:r:", long_options, &option_index); if (c == -1) break; @@ -143,14 +170,8 @@ static void handle_options(int argc, char **argv) print_help(); exit(0); case 0: - switch (long_option) { - case 1: - vty_dump_xml_ref(stdout); - exit(0); - default: - fprintf(stderr, "error parsing cmdline options\n"); - exit(2); - } + handle_long_options(argv[0], long_option); + break; case 's': log_set_use_color(osmo_stderr_target, 0); break; @@ -233,14 +254,14 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal, } /* Produce a MA as specified in 10.5.2.21 */ -static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts) +static void generate_ma_for_ts(struct gsm_bts_trx_ts *ts) { /* we have three bitvecs: the per-timeslot ARFCNs, the cell chan ARFCNs * and the MA */ + const size_t num_cell_arfcns = ts->trx->bts->si_common.cell_chan_num; const struct bitvec *cell_chan = &ts->trx->bts->si_common.cell_alloc; const struct bitvec *ts_arfcn = &ts->hopping.arfcns; struct bitvec *ma = &ts->hopping.ma; - unsigned int num_cell_arfcns; int i; /* re-set the MA to all-zero */ @@ -248,14 +269,7 @@ static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts) memset(ma->data, 0, ma->data_len); if (!ts->hopping.enabled) - return 0; - - /* count the number of ARFCNs in the cell channel allocation */ - num_cell_arfcns = 0; - for (i = 0; i < 1024; i++) { - if (bitvec_get_bit_pos(cell_chan, i)) - num_cell_arfcns++; - } + return; /* pad it to octet-aligned number of bits */ ts->hopping.ma_len = OSMO_BYTES_FOR_BITS(num_cell_arfcns); @@ -280,13 +294,26 @@ static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts) else bitvec_set_bit_pos(ma, ma->cur_bit, 0); } +} - return 0; +static void generate_ma_for_bts(struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + unsigned int tn; + + OSMO_ASSERT(bts->si_common.cell_chan_num > 0); + OSMO_ASSERT(bts->si_common.cell_chan_num <= 64); + + llist_for_each_entry(trx, &bts->trx_list, list) { + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + generate_ma_for_ts(&trx->ts[tn]); + } } static void bootstrap_rsl(struct gsm_bts_trx *trx) { unsigned int i; + int rc; LOG_TRX(trx, DRSL, LOGL_NOTICE, "bootstrapping RSL " "on ARFCN %u using MCC-MNC %s LAC=%u CID=%u BSIC=%u\n", @@ -317,29 +344,73 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx) rsl_nokia_si_end(trx); } + if (trx->bts->model->power_ctrl_send_def_params != NULL) { + rc = trx->bts->model->power_ctrl_send_def_params(trx); + if (rc) { + LOG_TRX(trx, DRSL, LOGL_ERROR, "Failed to send default " + "MS/BS Power control parameters (rc=%d)\n", rc); + /* TODO: should we drop RSL connection here? */ + } + } + for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { struct gsm_bts_trx_ts *ts = &trx->ts[i]; - generate_ma_for_ts(ts); OSMO_ASSERT(ts->fi); osmo_fsm_inst_dispatch(ts->fi, TS_EV_RSL_READY, NULL); } - /* Start CBCH transmit timer if CBCH is present */ - if (trx->nr == 0 && gsm_bts_get_cbch(trx->bts)) - bts_cbch_timer_schedule(trx->bts); - /* Drop all expired channel requests in the list */ abis_rsl_chan_rqd_queue_flush(trx->bts); } -static void all_ts_dispatch_event(struct gsm_bts_trx *trx, uint32_t event) +struct osmo_timer_list update_connection_stats_timer; + +/* Periodically call bsc_update_connection_stats() to keep stat items updated. + * It would be nicer to trigger this only when OML or RSL state is seen to flip. I tried hard to find all code paths + * that should call this and failed to get accurate results; this trivial timer covers all of them. */ +static void update_connection_stats_cb(void *data) +{ + bsc_update_connection_stats(bsc_gsmnet); + osmo_timer_setup(&update_connection_stats_timer, update_connection_stats_cb, NULL); + osmo_timer_schedule(&update_connection_stats_timer, 1, 0); +} + +static void bootstrap_bts(struct gsm_bts *bts) { - int ts_i; - for (ts_i = 0; ts_i < ARRAY_SIZE(trx->ts); ts_i++) { - struct gsm_bts_trx_ts *ts = &trx->ts[ts_i]; - if (ts->fi) - osmo_fsm_inst_dispatch(ts->fi, event, 0); + unsigned int n = 0; + + /* Control Channel Description is set from vty/config */ + + /* Determine the value of CCCH_CONF. Is TS0/C0 combined? */ + if (bts->c0->ts[0].pchan_from_config != GSM_PCHAN_CCCH) { + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; + + /* Limit reserved block to 2 on combined channel according to + 3GPP TS 44.018 Table 10.5.2.11.1 */ + if (bts->si_common.chan_desc.bs_ag_blks_res > 2) { + LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, " + "reducing BS-AG-BLKS-RES value %d -> 2\n", + bts->si_common.chan_desc.bs_ag_blks_res); + bts->si_common.chan_desc.bs_ag_blks_res = 2; + } + } else { /* Non-combined TS0/C0 configuration */ + /* There can be additional CCCHs on even timeslot numbers */ + n += (bts->c0->ts[2].pchan_from_config == GSM_PCHAN_CCCH); + n += (bts->c0->ts[4].pchan_from_config == GSM_PCHAN_CCCH); + n += (bts->c0->ts[6].pchan_from_config == GSM_PCHAN_CCCH); + bts->si_common.chan_desc.ccch_conf = (n << 1); } + + bts_setup_ramp_init_bts(bts); + + /* ACC ramping is initialized from vty/config */ + + /* Initialize the BTS state */ + gsm_bts_sm_mo_reset(bts->site_mgr); + + /* Generate Mobile Allocation bit-masks for all timeslots. + * This needs to be done here, because it's used for TS configuration. */ + generate_ma_for_bts(bts); } /* Callback function to be called every time we receive a signal from INPUT */ @@ -348,13 +419,7 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal, { struct input_signal_data *isd = signal_data; struct gsm_bts_trx *trx = isd->trx; - /* N. B: we rely on attribute order when parsing response in abis_nm_rx_get_attr_resp() */ - const uint8_t bts_attr[] = { NM_ATT_MANUF_ID, NM_ATT_SW_CONFIG, }; - const uint8_t trx_attr[] = { NM_ATT_MANUF_STATE, NM_ATT_SW_CONFIG, }; - - /* we should not request more attributes than we're ready to handle */ - OSMO_ASSERT(sizeof(bts_attr) < MAX_BTS_ATTR); - OSMO_ASSERT(sizeof(trx_attr) < MAX_BTS_ATTR); + int rc; if (subsys != SS_L_INPUT) return -EINVAL; @@ -364,44 +429,43 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_L_INP_TEI_UP: if (isd->link_type == E1INP_SIGN_OML) { - /* TODO: this is required for the Nokia BTS, hopping is configured - during OML, other MA is not set. */ - struct gsm_bts_trx *cur_trx; - uint8_t ca[20]; - /* has to be called before generate_ma_for_ts to - set bts->si_common.cell_alloc */ - generate_cell_chan_list(ca, trx->bts); - - /* Request generic BTS-level attributes */ - abis_nm_get_attr(trx->bts, NM_OC_BTS, 0xFF, 0xFF, 0xFF, bts_attr, sizeof(bts_attr)); - - llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) { - int i; - /* Request TRX-level attributes */ - abis_nm_get_attr(cur_trx->bts, NM_OC_BASEB_TRANSC, 0, cur_trx->nr, 0xFF, - trx_attr, sizeof(trx_attr)); - for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++) - generate_ma_for_ts(&cur_trx->ts[i]); + /* Check parameters and apply vty config dependent parameters */ + rc = gsm_bts_check_cfg(trx->bts); + if (rc < 0) { + LOGP(DNM, LOGL_ERROR, "(bts=%u) Error in BTS configuration -- cannot bootstrap BTS\n", + trx->bts->nr); + return rc; } + bootstrap_bts(trx->bts); } - if (isd->link_type == E1INP_SIGN_RSL) + if (isd->link_type == E1INP_SIGN_RSL) { + rc = gsm_bts_check_cfg(trx->bts); + if (rc < 0) { + LOGP(DNM, LOGL_ERROR, "(bts=%u) Error in BTS configuration -- cannot bootstrap RSL\n", + trx->bts->nr); + return rc; + } bootstrap_rsl(trx); + } break; case S_L_INP_TEI_DN: LOG_TRX(trx, DLMI, LOGL_ERROR, "Lost E1 %s link\n", e1inp_signtype_name(isd->link_type)); if (isd->link_type == E1INP_SIGN_OML) { - rate_ctr_inc(&trx->bts->bts_ctrs->ctr[BTS_CTR_BTS_OML_FAIL]); - all_ts_dispatch_event(trx, TS_EV_OML_DOWN); + rate_ctr_inc(rate_ctr_group_get_ctr(trx->bts->bts_ctrs, BTS_CTR_BTS_OML_FAIL)); + /* ip.access BTS models have a single global A-bis/OML link for all + * transceivers, so once it's lost we need to notify them all. */ + if (is_ipaccess_bts(trx->bts)) + gsm_bts_all_ts_dispatch(trx->bts, TS_EV_OML_DOWN, NULL); + else /* Other BTS models (e.g. Ericsson) have per-TRX OML links */ + gsm_trx_all_ts_dispatch(trx, TS_EV_OML_DOWN, NULL); } else if (isd->link_type == E1INP_SIGN_RSL) { - rate_ctr_inc(&trx->bts->bts_ctrs->ctr[BTS_CTR_BTS_RSL_FAIL]); + rate_ctr_inc(rate_ctr_group_get_ctr(trx->bts->bts_ctrs, BTS_CTR_BTS_RSL_FAIL)); acc_ramp_abort(&trx->bts->acc_ramp); - all_ts_dispatch_event(trx, TS_EV_RSL_DOWN); - if (trx->nr == 0) - osmo_timer_del(&trx->bts->cbch_timer); + gsm_trx_all_ts_dispatch(trx, TS_EV_RSL_DOWN, NULL); } - gsm_bts_mo_reset(trx->bts); + gsm_bts_sm_mo_reset(trx->bts->site_mgr); abis_nm_clear_queue(trx->bts); break; @@ -412,105 +476,6 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal, return 0; } -static int bootstrap_bts(struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - unsigned int n = 0; - - if (!bts->model) - return -EFAULT; - - if (bts->model->start && !bts->model->started) { - int ret = bts->model->start(bts->network); - if (ret < 0) - return ret; - - bts->model->started = true; - } - - /* FIXME: What about secondary TRX of a BTS? What about a BTS that has TRX - * in different bands? Why is 'band' a parameter of the BTS and not of the TRX? */ - switch (bts->band) { - case GSM_BAND_1800: - if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { - LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n"); - return -EINVAL; - } - break; - case GSM_BAND_1900: - if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) { - LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n"); - return -EINVAL; - } - break; - case GSM_BAND_900: - if ((bts->c0->arfcn > 124 && bts->c0->arfcn < 955) || - bts->c0->arfcn > 1023) { - LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 0-124, 955-1023.\n"); - return -EINVAL; - } - break; - case GSM_BAND_850: - if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) { - LOGP(DNM, LOGL_ERROR, "GSM850 channel must be between 128-251.\n"); - return -EINVAL; - } - break; - default: - LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n"); - return -EINVAL; - } - - /* Verify the physical channel mapping */ - llist_for_each_entry(trx, &bts->trx_list, list) { - if (!trx_has_valid_pchan_config(trx)) { - LOGP(DNM, LOGL_ERROR, "TRX %u has invalid timeslot " - "configuration\n", trx->nr); - return -EINVAL; - } - } - - /* Control Channel Description is set from vty/config */ - - /* Indicate R99 MSC in SI3 */ - bts->si_common.chan_desc.mscr = 1; - - /* Determine the value of CCCH_CONF. Is TS0/C0 combined? */ - if (bts->c0->ts[0].pchan_from_config != GSM_PCHAN_CCCH) { - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; - - /* Limit reserved block to 2 on combined channel according to - 3GPP TS 44.018 Table 10.5.2.11.1 */ - if (bts->si_common.chan_desc.bs_ag_blks_res > 2) { - LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, " - "reducing BS-AG-BLKS-RES value %d -> 2\n", - bts->si_common.chan_desc.bs_ag_blks_res); - bts->si_common.chan_desc.bs_ag_blks_res = 2; - } - } else { /* Non-combined TS0/C0 configuration */ - /* There can be additional CCCHs on even timeslot numbers */ - n += (bts->c0->ts[2].pchan_from_config == GSM_PCHAN_CCCH); - n += (bts->c0->ts[4].pchan_from_config == GSM_PCHAN_CCCH); - n += (bts->c0->ts[6].pchan_from_config == GSM_PCHAN_CCCH); - bts->si_common.chan_desc.ccch_conf = (n << 1); - } - - bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ - - bts->si_common.cell_sel_par.acs = 0; - - bts->si_common.ncc_permitted = 0xff; - - bts->chan_load_samples_idx = 0; - - /* ACC ramping is initialized from vty/config */ - - /* Initialize the BTS state */ - gsm_bts_mo_reset(bts); - - return 0; -} - static int bsc_network_configure(const char *config_file) { struct gsm_bts *bts; @@ -523,8 +488,7 @@ static int bsc_network_configure(const char *config_file) } /* start telnet after reading config for vty_get_bind_addr() */ - rc = telnet_init_dynif(tall_bsc_ctx, bsc_gsmnet, vty_get_bind_addr(), - OSMO_VTY_PORT_NITB_BSC); + rc = telnet_init_default(tall_bsc_ctx, bsc_gsmnet, OSMO_VTY_PORT_NITB_BSC); if (rc < 0) return rc; @@ -532,11 +496,12 @@ static int bsc_network_configure(const char *config_file) osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL); llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) { - rc = bootstrap_bts(bts); + rc = gsm_bts_check_cfg(bts); if (rc < 0) { - LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n"); + LOGP(DNM, LOGL_FATAL, "(bts=%u) cannot bootstrap BTS, invalid BTS configuration\n", bts->nr); return rc; } + bootstrap_bts(bts); rc = e1_reconfig_bts(bts); if (rc < 0) { LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n"); @@ -554,6 +519,11 @@ static int bsc_vty_go_parent(struct vty *vty) vty->node = CONFIG_NODE; vty->index = NULL; break; + case MGW_NODE: + vty->node = GSMNET_NODE; + vty->index = bsc_gsmnet; + vty->index_sub = NULL; + break; case BTS_NODE: vty->node = GSMNET_NODE; { @@ -563,6 +533,21 @@ static int bsc_vty_go_parent(struct vty *vty) vty->index_sub = NULL; } break; + case POWER_CTRL_NODE: + vty->node = BTS_NODE; + { + const struct gsm_power_ctrl_params *cp = vty->index; + struct gsm_bts *bts; + + if (cp->dir == GSM_PWR_CTRL_DIR_UL) + bts = container_of(cp, struct gsm_bts, ms_power_ctrl); + else + bts = container_of(cp, struct gsm_bts, bs_power_ctrl); + + vty->index_sub = &bts->description; + vty->index = bts; + } + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -578,7 +563,6 @@ static int bsc_vty_go_parent(struct vty *vty) /* set vty->index correctly ! */ struct gsm_bts_trx_ts *ts = vty->index; vty->index = ts->trx; - vty->index_sub = &ts->trx->description; } break; case OML_NODE: @@ -636,7 +620,9 @@ static struct vty_app_info vty_info = { .copyright = "Copyright (C) 2008-2018 Harald Welte, Holger Freyther\r\n" "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n" - "Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n\r\n" + "Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n" + "Copyright (C) 2013-2022 sysmocom - s.f.m.c. GmbH\r\n" + "\r\n" "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n" "This is free software: you are free to change and redistribute it.\r\n" "There is NO WARRANTY, to the extent permitted by law.\r\n", @@ -650,30 +636,44 @@ static struct vty_app_info vty_info = { "This command applies on A-bis RSL link (re)establishment", [BSC_VTY_ATTR_NEW_LCHAN] = \ "This command applies for newly created lchans", + [BSC_VTY_ATTR_VENDOR_SPECIFIC] = \ + "This command/parameter is BTS vendor specific", }, .usr_attr_letters = { [BSC_VTY_ATTR_RESTART_ABIS_OML_LINK] = 'o', [BSC_VTY_ATTR_RESTART_ABIS_RSL_LINK] = 'r', [BSC_VTY_ATTR_NEW_LCHAN] = 'l', + [BSC_VTY_ATTR_VENDOR_SPECIFIC] = 'v', }, }; extern int bsc_shutdown_net(struct gsm_network *net); -static void signal_handler(int signal) +static void signal_handler(int signum) { - fprintf(stdout, "signal %u received\n", signal); + fprintf(stdout, "signal %u received\n", signum); - switch (signal) { + switch (signum) { case SIGINT: case SIGTERM: + /* If SIGTERM was already sent before, just terminate immediately. */ + if (osmo_select_shutdown_requested()) + exit(-1); bsc_shutdown_net(bsc_gsmnet); osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); - sleep(3); - exit(0); + osmo_select_shutdown_request(); break; case SIGABRT: - /* in case of abort, we want to obtain a talloc report - * and then return to the caller, who will abort the process */ + /* in case of abort, we want to obtain a talloc report and + * then run default SIGABRT handler, who will generate coredump + * and abort the process. abort() should do this for us after we + * return, but program wouldn't exit if an external SIGABRT is + * received. + */ + talloc_report(tall_vty_ctx, stderr); + talloc_report_full(tall_bsc_ctx, stderr); + signal(SIGABRT, SIG_DFL); + raise(SIGABRT); + break; case SIGUSR1: talloc_report(tall_vty_ctx, stderr); talloc_report_full(tall_bsc_ctx, stderr); @@ -800,6 +800,12 @@ static const struct log_info_cat osmo_bsc_categories[] = { .description = "RESET/ACK on A and Lb interfaces", .enabled = 1, .loglevel = LOGL_NOTICE, }, + [DLOOP] = { + .name = "DLOOP", + .description = "Control loops", + .color = "\033[0;34m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, }; static int filter_fn(const struct log_context *ctx, struct log_target *tar) @@ -824,7 +830,41 @@ const struct log_info log_info = { extern void *tall_paging_ctx; extern void *tall_fle_ctx; extern void *tall_tqe_ctx; -extern void *tall_ctr_ctx; + +static int bsc_mgw_setup(void) +{ + struct mgcp_client *mgcp_client_single; + unsigned int pool_members_initalized; + + /* Initialize MGW pool. This initalizes and connects all MGCP clients that are currently configured in + * the pool. Adding additional MGCP clients to the pool is possible but the user has to configure and + * (re)connect them manually from the VTY. */ + pool_members_initalized = mgcp_client_pool_connect(bsc_gsmnet->mgw.mgw_pool); + if (pool_members_initalized) { + LOGP(DNM, LOGL_NOTICE, + "MGW pool with %u pool members configured, (ignoring MGW configuration in VTY node 'msc').\n", + pool_members_initalized); + return 0; + } + + /* Initialize and connect a single MGCP client. This MGCP client will appear as the one and only pool + * member if there is no MGW pool configured. */ + LOGP(DNM, LOGL_NOTICE, "No MGW pool configured, using MGW configuration in VTY node 'msc'\n"); + mgcp_client_single = mgcp_client_init(bsc_gsmnet, bsc_gsmnet->mgw.conf); + if (!mgcp_client_single) { + LOGP(DNM, LOGL_ERROR, "MGW (single) client initalization failed\n"); + return -EINVAL; + } + if (mgcp_client_connect(mgcp_client_single)) { + LOGP(DNM, LOGL_ERROR, "MGW (single) connect failed at (%s:%u)\n", + bsc_gsmnet->mgw.conf->remote_addr, + bsc_gsmnet->mgw.conf->remote_port); + return -EINVAL; + } + mgcp_client_pool_register_single(bsc_gsmnet->mgw.mgw_pool, mgcp_client_single); + + return 0; +} int main(int argc, char **argv) { @@ -840,13 +880,13 @@ int main(int argc, char **argv) tall_paging_ctx = talloc_named_const(tall_bsc_ctx, 0, "paging_request"); tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0, "bs11_file_list_entry"); tall_tqe_ctx = talloc_named_const(tall_bsc_ctx, 0, "subch_txq_entry"); - tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter"); osmo_init_logging2(tall_bsc_ctx, &log_info); osmo_stats_init(tall_bsc_ctx); rate_ctr_init(tall_bsc_ctx); osmo_fsm_set_dealloc_ctx(OTC_SELECT); + osmo_fsm_log_timeouts(true); /* Allocate global gsm_network struct */ rc = bsc_network_alloc(); @@ -856,6 +896,7 @@ int main(int argc, char **argv) } bsc_gsmnet->mgw.conf = talloc_zero(bsc_gsmnet, struct mgcp_client_conf); + bsc_gsmnet->mgw.mgw_pool = mgcp_client_pool_alloc(bsc_gsmnet); mgcp_client_conf_init(bsc_gsmnet->mgw.conf); bts_init(); @@ -883,12 +924,14 @@ int main(int argc, char **argv) /* seed the PRNG */ srand(time(NULL)); - ts_fsm_init(); lchan_fsm_init(); bsc_subscr_conn_fsm_init(); assignment_fsm_init(); handover_fsm_init(); lb_init(); + acc_ramp_global_init(); + paging_global_init(); + smscb_global_init(); /* Read the config */ rc = bsc_network_configure(config_file); @@ -897,11 +940,14 @@ int main(int argc, char **argv) exit(1); } + if (neighbors_check_cfg()) { + fprintf(stderr, "Errors in neighbor configuration, check the DHO log. exiting.\n"); + exit(1); + } + /* start control interface after reading config for * ctrl_vty_get_bind_addr() */ - bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, - ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_NITB_BSC); + bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, OSMO_CTRL_PORT_NITB_BSC); if (!bsc_gsmnet->ctrl) { fprintf(stderr, "Failed to init the control interface. Exiting.\n"); exit(1); @@ -913,6 +959,19 @@ int main(int argc, char **argv) exit(1); } + if (bsc_gsmnet->neigh_ctrl.addr) { + bsc_gsmnet->neigh_ctrl.handle = neighbor_controlif_setup(bsc_gsmnet); + if (!bsc_gsmnet->neigh_ctrl.handle) { + fprintf(stderr, "Failed to bind Neighbor Resolution Service. Exiting.\n"); + exit(1); + } + rc = neighbor_ctrl_cmds_install(bsc_gsmnet); + if (rc < 0) { + fprintf(stderr, "Failed to install Neighbor Resolution Service commands. Exiting.\n"); + exit(1); + } + } + if (rf_ctrl) osmo_talloc_replace_string(bsc_gsmnet, &bsc_gsmnet->rf_ctrl_name, rf_ctrl); @@ -934,6 +993,9 @@ int main(int argc, char **argv) } } + if (bsc_mgw_setup() != 0) + exit(1); + llist_for_each_entry(msc, &bsc_gsmnet->mscs, entry) { if (osmo_bsc_msc_init(msc) != 0) { LOGP(DMSC, LOGL_ERROR, "Failed to start up. Exiting.\n"); @@ -941,15 +1003,6 @@ int main(int argc, char **argv) } } - bsc_gsmnet->mgw.client = mgcp_client_init(bsc_gsmnet, bsc_gsmnet->mgw.conf); - - if (mgcp_client_connect(bsc_gsmnet->mgw.client)) { - LOGP(DNM, LOGL_ERROR, "MGW connect failed at (%s:%u)\n", - bsc_gsmnet->mgw.conf->remote_addr, - bsc_gsmnet->mgw.conf->remote_port); - exit(1); - } - if (osmo_bsc_sigtran_init(&bsc_gsmnet->mscs) != 0) { LOGP(DNM, LOGL_ERROR, "Failed to initialize sigtran backhaul.\n"); exit(1); @@ -967,6 +1020,9 @@ int main(int argc, char **argv) signal(SIGUSR2, &signal_handler); osmo_init_ignore_signals(); + update_connection_stats_cb(NULL); + chan_counts_sig_init(); + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { @@ -975,7 +1031,7 @@ int main(int argc, char **argv) } } - while (1) { + while (!osmo_select_shutdown_done()) { osmo_select_main_ctx(0); } |