From 4099f1db504c401e3d7211d9761b034d62d15f7c Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Tue, 26 May 2020 03:58:14 +0200 Subject: [PATCH] MSC pooling: make NRI mappings VTY configurable Use the osmo_nri_ranges API to manage each MSC's NRI ranges by VTY configuration. Change-Id: I6c251f2744d7be26fc4ad74adefc96a6a3fe08b0 --- include/osmocom/bsc/bsc_msc_data.h | 2 + include/osmocom/bsc/gsm_data.h | 3 + src/osmo-bsc/bsc_vty.c | 69 +++++++++++++ src/osmo-bsc/net_init.c | 4 + src/osmo-bsc/osmo_bsc_msc.c | 3 + src/osmo-bsc/osmo_bsc_vty.c | 135 ++++++++++++++++++++++++- tests/nri_cfg.vty | 152 +++++++++++++++++++++++++++++ 7 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 tests/nri_cfg.vty diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h index 43adaec00..6e29bfe55 100644 --- a/include/osmocom/bsc/bsc_msc_data.h +++ b/include/osmocom/bsc/bsc_msc_data.h @@ -179,6 +179,8 @@ struct bsc_msc_data { /* UDP socket for proxying MGCP via SCCPlite/IPA */ struct osmo_fd ofd; } mgcp_ipa; + + struct osmo_nri_ranges *nri_ranges; }; int osmo_bsc_msc_init(struct bsc_msc_data *msc); diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index bc4c01771..38047d29d 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -1716,6 +1716,9 @@ struct gsm_network { /* Don't refuse to start with mutually exclusive codec settings */ bool allow_unusable_timeslots; + + uint8_t nri_bitlen; + struct osmo_nri_ranges *null_nri_ranges; }; struct gsm_audio_support { diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c index 80658ece8..916ab96bf 100644 --- a/src/osmo-bsc/bsc_vty.c +++ b/src/osmo-bsc/bsc_vty.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -1110,6 +1111,7 @@ static int config_write_net(struct vty *vty) { struct gsm_network *gsmnet = gsmnet_from_vty(vty); int i; + struct osmo_nri_range *r; vty_out(vty, "network%s", VTY_NEWLINE); vty_out(vty, " network country code %s%s", osmo_mcc_name(gsmnet->plmn.mcc), VTY_NEWLINE); @@ -1159,6 +1161,16 @@ static int config_write_net(struct vty *vty) if (gsmnet->allow_unusable_timeslots) vty_out(vty, " allow-unusable-timeslots%s", VTY_NEWLINE); + if (gsmnet->nri_bitlen != OSMO_NRI_BITLEN_DEFAULT) + vty_out(vty, " nri bitlen %u%s", gsmnet->nri_bitlen, VTY_NEWLINE); + + llist_for_each_entry(r, &gsmnet->null_nri_ranges->entries, entry) { + vty_out(vty, " nri null add %d", r->first); + if (r->first != r->last) + vty_out(vty, " %d", r->last); + vty_out(vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -2058,6 +2070,60 @@ DEFUN_DEPRECATED(cfg_net_dtx, return CMD_SUCCESS; } +#define NRI_STR "Mapping of Network Resource Indicators to this MSC, for MSC pooling\n" +#define NULL_NRI_STR "Define NULL-NRI values that cause re-assignment of an MS to a different MSC, for MSC pooling.\n" +#define NRI_FIRST_LAST_STR "First value of the NRI value range, should not surpass the configured 'nri bitlen'.\n" \ + "Last value of the NRI value range, should not surpass the configured 'nri bitlen' and be larger than the" \ + " first value; if omitted, apply only the first value.\n" +#define NRI_ARGS_TO_STR_FMT "%s%s%s" +#define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : "" + +DEFUN(cfg_net_nri_bitlen, + cfg_net_nri_bitlen_cmd, + "nri bitlen <1-15>", + NRI_STR + "Set number of bits that an NRI has, to extract from TMSI identities (always starting just after the TMSI's most significant octet).\n" + "bit count (default: " OSMO_STRINGIFY_VAL(NRI_BITLEN_DEFAULT) ")\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->nri_bitlen = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_nri_null_add, cfg_net_nri_null_add_cmd, + "nri null add <0-32767> [<0-32767>]", + NRI_STR NULL_NRI_STR "Add NULL-NRI value (or range)\n" + NRI_FIRST_LAST_STR) +{ + int rc; + const char *message; + rc = osmo_nri_ranges_vty_add(&message, NULL, bsc_gsmnet->null_nri_ranges, argc, argv, + bsc_gsmnet->nri_bitlen); + if (message) { + vty_out(vty, "%% %s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv)); + } + if (rc < 0) + return CMD_WARNING; + return CMD_SUCCESS; +} + +DEFUN(cfg_net_nri_null_del, cfg_net_nri_null_del_cmd, + "nri null del <0-32767> [<0-32767>]", + NRI_STR NULL_NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n" + NRI_FIRST_LAST_STR) +{ + int rc; + const char *message; + rc = osmo_nri_ranges_vty_del(&message, NULL, bsc_gsmnet->null_nri_ranges, argc, argv); + if (message) { + vty_out(vty, "%% %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv), + VTY_NEWLINE); + } + if (rc < 0) + return CMD_WARNING; + return CMD_SUCCESS; +} + /* per-BTS configuration */ DEFUN(cfg_bts, cfg_bts_cmd, @@ -5400,6 +5466,9 @@ int bsc_vty_init(struct gsm_network *network) install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_dtx_cmd); install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd); + install_element(GSMNET_NODE, &cfg_net_nri_bitlen_cmd); + install_element(GSMNET_NODE, &cfg_net_nri_null_add_cmd); + install_element(GSMNET_NODE, &cfg_net_nri_null_del_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); install_node(&bts_node, config_write_bts); diff --git a/src/osmo-bsc/net_init.c b/src/osmo-bsc/net_init.c index 34403fa1f..353099ddd 100644 --- a/src/osmo-bsc/net_init.c +++ b/src/osmo-bsc/net_init.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -90,5 +91,8 @@ struct gsm_network *gsm_network_init(void *ctx) net->mgw.tdefs = g_mgw_tdefs; osmo_tdefs_reset(net->mgw.tdefs); + net->null_nri_ranges = osmo_nri_ranges_alloc(net); + net->nri_bitlen = OSMO_NRI_BITLEN_DEFAULT; + return net; } diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c index 30b54f3d5..ce0751806 100644 --- a/src/osmo-bsc/osmo_bsc_msc.c +++ b/src/osmo-bsc/osmo_bsc_msc.c @@ -34,6 +34,7 @@ #include #include +#include #include @@ -228,6 +229,8 @@ struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr) msc_data->mgcp_ipa.local_addr = talloc_strdup(msc_data, "0.0.0.0"); msc_data->mgcp_ipa.local_port = 0; /* dynamic */ + msc_data->nri_ranges = osmo_nri_ranges_alloc(msc_data); + return msc_data; } diff --git a/src/osmo-bsc/osmo_bsc_vty.c b/src/osmo-bsc/osmo_bsc_vty.c index 34a56dedb..c860cfef8 100644 --- a/src/osmo-bsc/osmo_bsc_vty.c +++ b/src/osmo-bsc/osmo_bsc_vty.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -52,8 +53,10 @@ static struct cmd_node msc_node = { 1, }; +#define MSC_NR_RANGE "<0-1000>" + DEFUN(cfg_net_msc, cfg_net_msc_cmd, - "msc [<0-1000>]", "Configure MSC details\n" "MSC connection to configure\n") + "msc [" MSC_NR_RANGE "]", "Configure MSC details\n" "MSC connection to configure\n") { int index = argc == 1 ? atoi(argv[0]) : 0; struct bsc_msc_data *msc; @@ -99,6 +102,8 @@ static void write_msc_amr_options(struct vty *vty, struct bsc_msc_data *msc) vty_out(vty, " amr-payload bandwith-efficient%s", VTY_NEWLINE); } +static void msc_write_nri(struct vty *vty, struct bsc_msc_data *msc, bool verbose); + static void write_msc(struct vty *vty, struct bsc_msc_data *msc) { vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE); @@ -170,6 +175,8 @@ static void write_msc(struct vty *vty, struct bsc_msc_data *msc) vty_out(vty, " osmux %s%s", msc->use_osmux == OSMUX_USAGE_ON ? "on" : "only", VTY_NEWLINE); } + + msc_write_nri(vty, msc, false); } static int config_write_msc(struct vty *vty) @@ -784,6 +791,128 @@ DEFUN(cfg_net_msc_amr_octet_align, return CMD_SUCCESS; } +#define NRI_STR "Mapping of Network Resource Indicators to this MSC, for MSC pooling\n" +#define NRI_FIRST_LAST_STR "First value of the NRI value range, should not surpass the configured 'nri bitlen'.\n" \ + "Last value of the NRI value range, should not surpass the configured 'nri bitlen' and be larger than the" \ + " first value; if omitted, apply only the first value.\n" + +#define NRI_WARN(MSC, FORMAT, args...) do { \ + vty_out(vty, "%% Warning: msc %d: " FORMAT "%s", MSC->nr, ##args, VTY_NEWLINE); \ + LOGP(DMSC, LOGL_ERROR, "msc %d: " FORMAT "\n", MSC->nr, ##args); \ + } while (0) + +#define NRI_ARGS_TO_STR_FMT "%s%s%s" +#define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : "" + +DEFUN(cfg_msc_nri_add, cfg_msc_nri_add_cmd, + "nri add <0-32767> [<0-32767>]", + NRI_STR "Add NRI value or range to the NRI mapping for this MSC\n" + NRI_FIRST_LAST_STR) +{ + struct bsc_msc_data *msc = bsc_msc_data(vty); + struct bsc_msc_data *other_msc; + bool before; + int rc; + const char *message; + struct osmo_nri_range add_range; + + rc = osmo_nri_ranges_vty_add(&message, &add_range, msc->nri_ranges, argc, argv, bsc_gsmnet->nri_bitlen); + if (message) { + NRI_WARN(msc, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv)); + } + if (rc < 0) + return CMD_WARNING; + + /* Issue a warning about NRI range overlaps (but still allow them). + * Overlapping ranges will map to whichever MSC comes fist in the bsc_gsmnet->mscs llist, + * which is not necessarily in the order of increasing msc->nr. */ + before = true; + llist_for_each_entry(other_msc, &bsc_gsmnet->mscs, entry) { + if (other_msc == msc) { + before = false; + continue; + } + if (osmo_nri_range_overlaps_ranges(&add_range, other_msc->nri_ranges)) { + NRI_WARN(msc, "NRI range [%d..%d] overlaps between msc %d and msc %d." + " For overlaps, msc %d has higher priority than msc %d", + add_range.first, add_range.last, msc->nr, other_msc->nr, + before ? other_msc->nr : msc->nr, before ? msc->nr : other_msc->nr); + } + } + return CMD_SUCCESS; +} + +DEFUN(cfg_msc_nri_del, cfg_msc_nri_del_cmd, + "nri del <0-32767> [<0-32767>]", + NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n" + NRI_FIRST_LAST_STR) +{ + struct bsc_msc_data *msc = bsc_msc_data(vty); + int rc; + const char *message; + + rc = osmo_nri_ranges_vty_del(&message, NULL, msc->nri_ranges, argc, argv); + if (message) { + NRI_WARN(msc, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv)); + } + if (rc < 0) + return CMD_WARNING; + return CMD_SUCCESS; +} + +static void msc_write_nri(struct vty *vty, struct bsc_msc_data *msc, bool verbose) +{ + struct osmo_nri_range *r; + + if (verbose) { + vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE); + if (llist_empty(&msc->nri_ranges->entries)) { + vty_out(vty, " %% no NRI mappings%s", VTY_NEWLINE); + return; + } + } + + llist_for_each_entry(r, &msc->nri_ranges->entries, entry) { + if (osmo_nri_range_validate(r, 255)) + vty_out(vty, " %% INVALID RANGE:"); + vty_out(vty, " nri add %d", r->first); + if (r->first != r->last) + vty_out(vty, " %d", r->last); + vty_out(vty, "%s", VTY_NEWLINE); + } +} + +DEFUN(cfg_msc_show_nri, cfg_msc_show_nri_cmd, + "show nri", + SHOW_STR NRI_STR) +{ + struct bsc_msc_data *msc = bsc_msc_data(vty); + msc_write_nri(vty, msc, true); + return CMD_SUCCESS; +} + +DEFUN(show_nri, show_nri_cmd, + "show nri [" MSC_NR_RANGE "]", + SHOW_STR NRI_STR "Optional MSC number to limit to\n") +{ + struct bsc_msc_data *msc; + if (argc > 0) { + int msc_nr = atoi(argv[0]); + msc = osmo_msc_data_find(bsc_gsmnet, msc_nr); + if (!msc) { + vty_out(vty, "%% No such MSC%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + msc_write_nri(vty, msc, true); + return CMD_SUCCESS; + } + + llist_for_each_entry(msc, &bsc_gsmnet->mscs, entry) { + msc_write_nri(vty, msc, true); + } + return CMD_SUCCESS; +} + int bsc_vty_init_extra(void) { struct gsm_network *net = bsc_gsmnet; @@ -831,6 +960,9 @@ int bsc_vty_init_extra(void) install_element(MSC_NODE, &cfg_msc_cs7_bsc_addr_cmd); install_element(MSC_NODE, &cfg_msc_cs7_msc_addr_cmd); install_element(MSC_NODE, &cfg_msc_cs7_asp_proto_cmd); + install_element(MSC_NODE, &cfg_msc_nri_add_cmd); + install_element(MSC_NODE, &cfg_msc_nri_del_cmd); + install_element(MSC_NODE, &cfg_msc_show_nri_cmd); /* Deprecated: ping time config, kept to support legacy config files. */ install_element(MSC_NODE, &cfg_net_msc_no_ping_time_cmd); @@ -842,6 +974,7 @@ int bsc_vty_init_extra(void) install_element_ve(&show_pos_cmd); install_element_ve(&logging_fltr_imsi_cmd); install_element_ve(&show_subscr_all_cmd); + install_element_ve(&show_nri_cmd); install_element(ENABLE_NODE, &gen_position_trap_cmd); diff --git a/tests/nri_cfg.vty b/tests/nri_cfg.vty new file mode 100644 index 000000000..680b8efe8 --- /dev/null +++ b/tests/nri_cfg.vty @@ -0,0 +1,152 @@ +OsmoBSC> show nri +msc 0 + % no NRI mappings + +OsmoBSC> enable +OsmoBSC# configure terminal + +OsmoBSC(config)# msc 0 + +OsmoBSC(config-msc)# list +... + nri add <0-32767> [<0-32767>] + nri del <0-32767> [<0-32767>] + show nri +... +OsmoBSC(config-msc)# nri ? + add Add NRI value or range to the NRI mapping for this MSC + del Remove NRI value or range from the NRI mapping for this MSC +OsmoBSC(config-msc)# nri add ? + <0-32767> First value of the NRI value range, should not surpass the configured 'nri bitlen'. +OsmoBSC(config-msc)# nri add 23 ? + [<0-32767>] Last value of the NRI value range, should not surpass the configured 'nri bitlen' and be larger than the first value; if omitted, apply only the first value. + +OsmoBSC(config-msc)# nri add 23 +OsmoBSC(config-msc)# nri add 256 511 +OsmoBSC(config-msc)# nri add 100 200 +OsmoBSC(config-msc)# nri add 1024 1024 +% Warning: msc 0: Warning: NRI range surpasses current NRI bitlen: 1024..1024 +OsmoBSC(config-msc)# show nri +msc 0 + nri add 23 + nri add 100 200 + nri add 256 511 + nri add 1024 +OsmoBSC(config-msc)# exit + +OsmoBSC(config)# ### Do msc 2 first, to see that the order of mscs in the internal list is not determined by the msc->nr, +OsmoBSC(config)# ### and whichever was configured first gets higher priority for overlaps. + +OsmoBSC(config)# msc 2 +OsmoBSC(config-msc)# nri add 200 300 +% Warning: msc 2: NRI range [200..300] overlaps between msc 2 and msc 0. For overlaps, msc 0 has higher priority than msc 2 +OsmoBSC(config-msc)# nri add 1024 1025 +% Warning: msc 2: Warning: NRI range surpasses current NRI bitlen: 1024..1025 +% Warning: msc 2: NRI range [1024..1025] overlaps between msc 2 and msc 0. For overlaps, msc 0 has higher priority than msc 2 +OsmoBSC(config-msc)# exit + +OsmoBSC(config)# msc 1 +OsmoBSC(config-msc)# nri add 42 +OsmoBSC(config-msc)# nri add 512 767 +OsmoBSC(config-msc)# nri add 200 300 +% Warning: msc 1: NRI range [200..300] overlaps between msc 1 and msc 0. For overlaps, msc 0 has higher priority than msc 1 +% Warning: msc 1: NRI range [200..300] overlaps between msc 1 and msc 2. For overlaps, msc 2 has higher priority than msc 1 +OsmoBSC(config-msc)# nri add 1024 1025 +% Warning: msc 1: Warning: NRI range surpasses current NRI bitlen: 1024..1025 +% Warning: msc 1: NRI range [1024..1025] overlaps between msc 1 and msc 0. For overlaps, msc 0 has higher priority than msc 1 +% Warning: msc 1: NRI range [1024..1025] overlaps between msc 1 and msc 2. For overlaps, msc 2 has higher priority than msc 1 +OsmoBSC(config-msc)# show nri +msc 1 + nri add 42 + nri add 200 300 + nri add 512 767 + nri add 1024 1025 +OsmoBSC(config-msc)# exit + +OsmoBSC(config)# do show nri +msc 0 + nri add 23 + nri add 100 200 + nri add 256 511 + nri add 1024 +msc 2 + nri add 200 300 + nri add 1024 1025 +msc 1 + nri add 42 + nri add 200 300 + nri add 512 767 + nri add 1024 1025 + +OsmoBSC(config)# network +OsmoBSC(config-net)# nri bitlen 11 +OsmoBSC(config-net)# show running-config +... +network +... + nri bitlen 11 +... +msc 0 +... + nri add 23 + nri add 100 200 + nri add 256 511 + nri add 1024 +... +msc 2 +... + nri add 200 300 + nri add 1024 1025 +... +msc 1 +... + nri add 42 + nri add 200 300 + nri add 512 767 + nri add 1024 1025 +... +OsmoBSC(config-net)# exit + +OsmoBSC(config)# msc 0 +OsmoBSC(config-msc)# nri del 0 10000 +OsmoBSC(config-msc)# exit +OsmoBSC(config)# msc 1 +OsmoBSC(config-msc)# nri del 0 10000 +OsmoBSC(config-msc)# exit +OsmoBSC(config)# msc 2 +OsmoBSC(config-msc)# nri del 0 10000 +OsmoBSC(config-msc)# exit +OsmoBSC(config)# do show nri +msc 0 + % no NRI mappings +msc 2 + % no NRI mappings +msc 1 + % no NRI mappings + +OsmoBSC(config)# msc 0 +OsmoBSC(config-msc)# nri add 0 1000 +OsmoBSC(config-msc)# show nri +msc 0 + nri add 0 1000 +OsmoBSC(config-msc)# nri del 23 +OsmoBSC(config-msc)# nri del 200 300 +OsmoBSC(config-msc)# nri del 1000 2000 +OsmoBSC(config-msc)# show nri +msc 0 + nri add 0 22 + nri add 24 199 + nri add 301 999 +OsmoBSC(config-msc)# nri add 23 +OsmoBSC(config-msc)# show nri +msc 0 + nri add 0 199 + nri add 301 999 +OsmoBSC(config-msc)# nri add 200 300 +OsmoBSC(config-msc)# show nri +msc 0 + nri add 0 999 +OsmoBSC(config-msc)# nri add 1000 +OsmoBSC(config-msc)# show nri +msc 0 + nri add 0 1000