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
This commit is contained in:
Neels Hofmeyr 2020-05-26 03:58:14 +02:00
parent daf5d8b6c7
commit 4099f1db50
7 changed files with 367 additions and 1 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -35,6 +35,7 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm23236.h>
#include <arpa/inet.h>
@ -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);

View File

@ -18,6 +18,7 @@
*/
#include <osmocom/core/tdef.h>
#include <osmocom/gsm/gsm23236.h>
#include <osmocom/bsc/osmo_bsc.h>
#include <osmocom/bsc/gsm_04_08_rr.h>
@ -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;
}

View File

@ -34,6 +34,7 @@
#include <osmocom/core/socket.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm23236.h>
#include <osmocom/abis/ipa.h>
@ -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;
}

View File

@ -29,6 +29,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm23236.h>
#include <osmocom/vty/logging.h>
#include <osmocom/mgcp_client/mgcp_client.h>
@ -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);

152
tests/nri_cfg.vty Normal file
View File

@ -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