diff --git a/doc/examples/osmo-gbproxy/osmo-gbproxy-pool.cfg b/doc/examples/osmo-gbproxy/osmo-gbproxy-pool.cfg new file mode 100644 index 00000000..df765c0d --- /dev/null +++ b/doc/examples/osmo-gbproxy/osmo-gbproxy-pool.cfg @@ -0,0 +1,38 @@ +! +! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty +!! +! +line vty + no login +! +gbproxy + nri bitlen 4 + nri null add 0 4 +sgsn nsei 101 + nri add 1 + nri add 11 +sgsn nsei 102 + nri add 2 + nri add 12 +ns + nse 101 nsvci 101 + nse 101 remote-role sgsn + nse 101 encapsulation udp + nse 101 remote-ip 192.168.100.239 + nse 101 remote-port 7777 + nse 102 nsvci 102 + nse 102 remote-role sgsn + nse 102 encapsulation udp + nse 102 remote-ip 192.168.100.239 + nse 102 remote-port 7778 + timer tns-block 3 + timer tns-block-retries 3 + timer tns-reset 3 + timer tns-reset-retries 3 + timer tns-test 30 + timer tns-alive 3 + timer tns-alive-retries 10 + encapsulation framerelay-gre enabled 0 + encapsulation framerelay-gre local-ip 0.0.0.0 + encapsulation udp local-ip 127.0.0.100 + encapsulation udp local-port 23000 diff --git a/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg b/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg index 29f698f3..5cabc6d6 100644 --- a/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg +++ b/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg @@ -6,7 +6,7 @@ line vty no login ! gbproxy - sgsn nsei 101 +sgsn nsei 101 ns nse 101 nsvci 101 nse 101 remote-role sgsn diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h index 200a539e..46decc0e 100644 --- a/include/osmocom/sgsn/gb_proxy.h +++ b/include/osmocom/sgsn/gb_proxy.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include #define GBPROXY_INIT_VU_GEN_TX 256 +#define GBPROXY_MAX_NR_SGSN 16 /* BVCI uses 16 bits */ #define BVC_LOG_CTX_FLAG (1<<17) @@ -55,9 +57,12 @@ struct gbproxy_config { struct { /* percentage of BVC flow control advertised to each SGSN in the pool */ uint8_t bvc_fc_ratio; + /* NRI bitlen and usable NULL-NRI ranges */ + uint8_t nri_bitlen; + struct osmo_nri_ranges *null_nri_ranges; } pool; - /* Linked list of all BSS side Gb peers */ + /* hash table of all BSS side Gb peers */ DECLARE_HASHTABLE(bss_nses, 8); /* hash table of all SGSN-side Gb peers */ @@ -66,6 +71,9 @@ struct gbproxy_config { /* hash table of all gbproxy_cell */ DECLARE_HASHTABLE(cells, 8); + /* List of all SGSNs */ + struct llist_head sgsns; + /* Counter */ struct rate_ctr_group *ctrg; }; @@ -88,7 +96,7 @@ struct gbproxy_cell { struct gbproxy_bvc *bss_bvc; /* pointers to SGSN-side BVC (one for each pool member) */ - struct gbproxy_bvc *sgsn_bvc[16]; + struct gbproxy_bvc *sgsn_bvc[GBPROXY_MAX_NR_SGSN]; }; /* One BVC inside an NSE */ @@ -133,6 +141,21 @@ struct gbproxy_nse { DECLARE_HASHTABLE(bvcs, 10); }; +/* SGSN configuration such as pool options (only for NSE where sgsn_facing == true) */ +struct gbproxy_sgsn { + /* linked to gbproxy_config.sgsns */ + struct llist_head list; + + /* The NSE belonging to this SGSN */ + struct gbproxy_nse *nse; + + /* Pool configuration for the sgsn (only valid if sgsn_facing == true) */ + struct { + bool allow_attach; + struct osmo_nri_ranges *nri_ranges; + } pool; +}; + /* Convenience logging macros for NSE/BVC */ #define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \ LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \ @@ -152,6 +175,11 @@ struct gbproxy_nse { #define LOGPCELL(CELL, LEVEL, FMT, ARGS...) \ LOGPCELL_CAT(CELL, DGPRS, LEVEL, FMT, ## ARGS) +#define LOGPSGSN_CAT(SGSN, SUBSYS, LEVEL, FMT, ARGS...) \ + LOGP(SUBSYS, LEVEL, "NSE(%05u)-SGSN " FMT, (SGSN)->nse->nsei, ## ARGS) +#define LOGPSGSN(SGSN, LEVEL, FMT, ARGS...) \ + LOGPSGSN_CAT(SGSN, DGPRS, LEVEL, FMT, ## ARGS) + /* gb_proxy_vty .c */ int gbproxy_vty_init(void); @@ -195,4 +223,11 @@ void gbproxy_nse_free(struct gbproxy_nse *nse); struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags); struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing); +/* SGSN handling */ +struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei); +void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn); +struct gbproxy_sgsn *gbproxy_sgsn_by_nsei(struct gbproxy_config *cfg, uint16_t nsei); +struct gbproxy_sgsn *gbproxy_sgsn_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei); +struct gbproxy_sgsn *gbproxy_sgsn_by_nri(struct gbproxy_config *cfg, uint16_t nri, bool *null_nri); + #endif diff --git a/src/gb_proxy.c b/src/gb_proxy.c index ca1c07c8..4b6dc091 100644 --- a/src/gb_proxy.c +++ b/src/gb_proxy.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -1286,9 +1287,13 @@ int gbproxy_init_config(struct gbproxy_config *cfg) /* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */ cfg->pool.bvc_fc_ratio = 100; + cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg); + hash_init(cfg->bss_nses); hash_init(cfg->sgsn_nses); hash_init(cfg->cells); + INIT_LLIST_HEAD(&cfg->sgsns); + cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0); if (!cfg->ctrg) { LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n"); diff --git a/src/gb_proxy_peer.c b/src/gb_proxy_peer.c index c38b2f75..863ec501 100644 --- a/src/gb_proxy_peer.c +++ b/src/gb_proxy_peer.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -273,7 +274,7 @@ struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei, return nse; } -void gbproxy_nse_free(struct gbproxy_nse *nse) +static void _nse_free(struct gbproxy_nse *nse) { struct gbproxy_bvc *bvc; struct hlist_node *tmp; @@ -291,6 +292,22 @@ void gbproxy_nse_free(struct gbproxy_nse *nse) talloc_free(nse); } +static void _sgsn_free(struct gbproxy_sgsn *sgsn); + +void gbproxy_nse_free(struct gbproxy_nse *nse) +{ + if (!nse) + return; + OSMO_ASSERT(nse->cfg); + + if (nse->sgsn_facing) { + struct gbproxy_sgsn *sgsn = gbproxy_sgsn_by_nsei(nse->cfg, nse->nsei); + OSMO_ASSERT(sgsn); + _sgsn_free(sgsn); + } + + _nse_free(nse); +} struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags) { @@ -325,3 +342,104 @@ struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint1 return nse; } + +/* SGSN */ +struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei) +{ + struct gbproxy_sgsn *sgsn; + OSMO_ASSERT(cfg); + + sgsn = talloc_zero(tall_sgsn_ctx, struct gbproxy_sgsn); + if (!sgsn) + return NULL; + + sgsn->nse = gbproxy_nse_alloc(cfg, nsei, true); + if (!sgsn->nse) { + LOGPSGSN_CAT(sgsn, DOBJ, LOGL_INFO, "Could not allocate NSE(%05u) for SGSN\n", nsei); + talloc_free(sgsn); + return NULL; + } + + sgsn->pool.allow_attach = true; + sgsn->pool.nri_ranges = osmo_nri_ranges_alloc(sgsn); + + llist_add_tail(&sgsn->list, &cfg->sgsns); + LOGPSGSN_CAT(sgsn, DOBJ, LOGL_INFO, "SGSN Created\n"); + return sgsn; +} + +/* Only free gbproxy_sgsn, sgsn can't be NULL */ +static void _sgsn_free(struct gbproxy_sgsn *sgsn) { + struct gbproxy_config *cfg; + + OSMO_ASSERT(sgsn->nse); + cfg = sgsn->nse->cfg; + OSMO_ASSERT(cfg); + + LOGPSGSN_CAT(sgsn, DOBJ, LOGL_INFO, "SGSN Destroying\n"); + llist_del(&sgsn->list); + talloc_free(sgsn); +} + +void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn) +{ + if (!sgsn) + return; + + OSMO_ASSERT(sgsn->nse) + + _nse_free(sgsn->nse); + _sgsn_free(sgsn); +} + +struct gbproxy_sgsn *gbproxy_sgsn_by_nsei(struct gbproxy_config *cfg, uint16_t nsei) +{ + struct gbproxy_sgsn *sgsn; + OSMO_ASSERT(cfg); + + llist_for_each_entry(sgsn, &cfg->sgsns, list) { + if (sgsn->nse->nsei == nsei) + return sgsn; + } + + return NULL; +} + +struct gbproxy_sgsn *gbproxy_sgsn_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei) +{ + struct gbproxy_sgsn *sgsn; + OSMO_ASSERT(cfg); + + sgsn = gbproxy_sgsn_by_nsei(cfg, nsei); + if (!sgsn) + sgsn = gbproxy_sgsn_alloc(cfg, nsei); + + return sgsn; +} + +/*! Return the gbproxy_sgsn matching that NRI + * \param[in] cfg proxy in which we operate + * \param[in] nri NRI to look for + * \param[out] null_nri If not NULL this indicates whether the NRI is a null NRI + * \return The SGSN this NRI has been added to, NULL if no matching SGSN could be found + */ +struct gbproxy_sgsn *gbproxy_sgsn_by_nri(struct gbproxy_config *cfg, uint16_t nri, bool *null_nri) +{ + struct gbproxy_sgsn *sgsn; + OSMO_ASSERT(cfg); + + llist_for_each_entry(sgsn, &cfg->sgsns, list) { + if (osmo_nri_v_matches_ranges(nri, sgsn->pool.nri_ranges)) { + /* Also check if the NRI we're looking for is a NULL NRI */ + if (sgsn && null_nri) { + if (osmo_nri_v_matches_ranges(nri, cfg->pool.null_nri_ranges)) + *null_nri = true; + else + *null_nri = false; + } + return sgsn; + } + } + + return NULL; +} diff --git a/src/gb_proxy_vty.c b/src/gb_proxy_vty.c index 595ac024..92915fea 100644 --- a/src/gb_proxy_vty.c +++ b/src/gb_proxy_vty.c @@ -25,14 +25,17 @@ #include #include +#include #include #include #include -#include #include #include + #include +#include +#include #include #include @@ -44,6 +47,17 @@ #include #include +#define NRI_STR "Mapping of Network Resource Indicators to this SGSN, for SGSN pooling\n" +#define NULL_NRI_STR "Define NULL-NRI values that cause re-assignment of an MS to a different SGSN, for SGSN 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] : "" +#define NRI_WARN(SGSN, FORMAT, args...) do { \ + vty_out(vty, "%% Warning: NSE(%05d/SGSN): " FORMAT "%s", (SGSN)->nse->nsei, ##args, VTY_NEWLINE); \ + LOGP(DLBSSGP, LOGL_ERROR, "NSE(%05d/SGSN): " FORMAT "\n", (SGSN)->nse->nsei, ##args); \ + } while (0) static struct gbproxy_config *g_cfg = NULL; @@ -111,18 +125,22 @@ static void gbproxy_vty_print_cell(struct vty *vty, struct gbproxy_cell *cell, b static int config_write_gbproxy(struct vty *vty) { - struct gbproxy_nse *nse; - int i; + struct osmo_nri_range *r; vty_out(vty, "gbproxy%s", VTY_NEWLINE); if (g_cfg->pool.bvc_fc_ratio != 100) vty_out(vty, " pool bvc-flow-control-ratio %u%s", g_cfg->pool.bvc_fc_ratio, VTY_NEWLINE); - hash_for_each(g_cfg->sgsn_nses, i, nse, list) { - vty_out(vty, " sgsn nsei %u%s", nse->nsei, VTY_NEWLINE); - } + if (g_cfg->pool.nri_bitlen != OSMO_NRI_BITLEN_DEFAULT) + vty_out(vty, " nri bitlen %u%s", g_cfg->pool.nri_bitlen, VTY_NEWLINE); + llist_for_each_entry(r, &g_cfg->pool.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; } @@ -135,30 +153,89 @@ DEFUN(cfg_gbproxy, return CMD_SUCCESS; } +/* VTY code for SGSN (pool) configuration */ extern const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops; #include -DEFUN(cfg_nsip_sgsn_nsei, - cfg_nsip_sgsn_nsei_cmd, +static struct cmd_node sgsn_node = { + SGSN_NODE, + "%s(config-sgsn)# ", + 1, +}; + +static void sgsn_write_nri(struct vty *vty, struct gbproxy_sgsn *sgsn, bool verbose) +{ + struct osmo_nri_range *r; + + if (verbose) { + vty_out(vty, "sgsn nsei %d%s", sgsn->nse->nsei, VTY_NEWLINE); + if (llist_empty(&sgsn->pool.nri_ranges->entries)) { + vty_out(vty, " %% no NRI mappings%s", VTY_NEWLINE); + return; + } + } + + llist_for_each_entry(r, &sgsn->pool.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); + } +} + +static void write_sgsn(struct vty *vty, struct gbproxy_sgsn *sgsn) +{ + vty_out(vty, "sgsn nsei %u%s", sgsn->nse->nsei, VTY_NEWLINE); + vty_out(vty, " %sallow-attach%s", sgsn->pool.allow_attach ? "" : "no ", VTY_NEWLINE); + sgsn_write_nri(vty, sgsn, false); +} + +static int config_write_sgsn(struct vty *vty) +{ + struct gbproxy_sgsn *sgsn; + + llist_for_each_entry(sgsn, &g_cfg->sgsns, list) + write_sgsn(vty, sgsn); + + return CMD_SUCCESS; +} + +DEFUN(cfg_sgsn_nsei, + cfg_sgsn_nsei_cmd, "sgsn nsei <0-65534>", - "SGSN information\n" + "Configure the SGSN\n" "NSEI to be used in the connection with the SGSN\n" "The NSEI\n") { uint32_t features = 0; // FIXME: make configurable unsigned int nsei = atoi(argv[0]); + unsigned int num_sgsn = llist_count(&g_cfg->sgsns); + struct gbproxy_sgsn *sgsn; struct gbproxy_nse *nse; struct gbproxy_bvc *bvc; - nse = gbproxy_nse_by_nsei_or_new(g_cfg, nsei, true); - if (!nse) + if (num_sgsn >= GBPROXY_MAX_NR_SGSN) { + vty_out(vty, "%% Too many SGSN NSE defined (%d), increase GBPROXY_MAX_NR_SGSN%s", + num_sgsn, VTY_NEWLINE); + return CMD_WARNING; + } + + /* This will have created the gbproxy_nse as well */ + sgsn = gbproxy_sgsn_by_nsei_or_new(g_cfg, nsei); + if (!sgsn) goto free_nothing; + nse = sgsn->nse; + if (num_sgsn > 1 && g_cfg->pool.nri_bitlen == 0) + vty_out(vty, "%% Multiple SGSNs defined, but no pooling enabled%s", VTY_NEWLINE); + if (!gbproxy_bvc_by_bvci(nse, 0)) { uint8_t cause = BSSGP_CAUSE_OML_INTERV; bvc = gbproxy_bvc_alloc(nse, 0); if (!bvc) - goto free_nse; + goto free_sgsn; bvc->fi = bssgp_bvc_fsm_alloc_sig_bss(bvc, nse->cfg->nsi, nsei, features); if (!bvc->fi) goto free_bvc; @@ -166,17 +243,134 @@ DEFUN(cfg_nsip_sgsn_nsei, osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause); } + vty->node = SGSN_NODE; + vty->index = sgsn; return CMD_SUCCESS; free_bvc: gbproxy_bvc_free(bvc); -free_nse: - gbproxy_nse_free(nse); +free_sgsn: + gbproxy_sgsn_free(sgsn); free_nothing: vty_out(vty, "%% Unable to create NSE for NSEI=%05u%s", nsei, VTY_NEWLINE); return CMD_WARNING; } +DEFUN_ATTR(cfg_sgsn_nri_add, cfg_sgsn_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, + CMD_ATTR_IMMEDIATE) +{ + struct gbproxy_sgsn *sgsn = vty->index; + struct gbproxy_sgsn *other_sgsn; + bool before; + int rc; + const char *message; + struct osmo_nri_range add_range; + + rc = osmo_nri_ranges_vty_add(&message, &add_range, sgsn->pool.nri_ranges, argc, argv, g_cfg->pool.nri_bitlen); + if (message) { + NRI_WARN(sgsn, "%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 SGSN comes fist in the gbproxy_config->sgsns llist, + * which should be the first one defined in the config */ + before = true; + + llist_for_each_entry(other_sgsn, &g_cfg->sgsns, list) { + if (other_sgsn == sgsn) { + before = false; + continue; + } + if (osmo_nri_range_overlaps_ranges(&add_range, other_sgsn->pool.nri_ranges)) { + uint16_t nsei = sgsn->nse->nsei; + uint16_t other_nsei = other_sgsn->nse->nsei; + NRI_WARN(sgsn, "NRI range [%d..%d] overlaps between NSE %05d and NSE %05d." + " For overlaps, NSE %05d has higher priority than NSE %05d", + add_range.first, add_range.last, nsei, other_nsei, + before ? other_nsei : nsei, before ? nsei : other_nsei); + } + } + return CMD_SUCCESS; +} + +DEFUN_ATTR(cfg_sgsn_nri_del, cfg_sgsn_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, + CMD_ATTR_IMMEDIATE) +{ + struct gbproxy_sgsn *sgsn = vty->index; + int rc; + const char *message; + + rc = osmo_nri_ranges_vty_del(&message, NULL, sgsn->pool.nri_ranges, argc, argv); + if (message) { + NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv)); + } + if (rc < 0) + return CMD_WARNING; + return CMD_SUCCESS; +} + +DEFUN_ATTR(cfg_sgsn_allow_attach, cfg_sgsn_allow_attach_cmd, + "allow-attach", + "Allow this SGSN to attach new subscribers (default).\n", + CMD_ATTR_IMMEDIATE) +{ + struct gbproxy_sgsn *sgsn = vty->index; + sgsn->pool.allow_attach = true; + return CMD_SUCCESS; +} + +DEFUN_ATTR(cfg_sgsn_no_allow_attach, cfg_sgsn_no_allow_attach_cmd, + "no allow-attach", + NO_STR + "Do not assign new subscribers to this MSC." + " Useful if an MSC in an MSC pool is configured to off-load subscribers." + " The MSC will still be operational for already IMSI-Attached subscribers," + " but the NAS node selection function will skip this MSC for new subscribers\n", + CMD_ATTR_IMMEDIATE) +{ + struct gbproxy_sgsn *sgsn = vty->index; + sgsn->pool.allow_attach = false; + return CMD_SUCCESS; +} + +DEFUN(cfg_sgsn_show_nri_all, show_nri_all_cmd, + "show nri all", + SHOW_STR NRI_STR "Show all SGSNs\n") +{ + struct gbproxy_sgsn *sgsn; + + llist_for_each_entry(sgsn, &g_cfg->sgsns, list) + sgsn_write_nri(vty, sgsn, true); + + return CMD_SUCCESS; +} + +DEFUN(show_nri, show_nri_nsei_cmd, + "show nri nsei <0-65535>", + SHOW_STR NRI_STR "Identify SGSN by NSEI\n" + "NSEI of the SGSN\n") +{ + struct gbproxy_sgsn *sgsn; + int nsei = atoi(argv[0]); + + sgsn = gbproxy_sgsn_by_nsei(g_cfg, nsei); + if (!sgsn) { + vty_out(vty, "%% No SGSN with found for NSEI %05d%s", nsei, VTY_NEWLINE); + return CMD_SUCCESS; + } + sgsn_write_nri(vty, sgsn, true); + + return CMD_SUCCESS; +} + DEFUN(cfg_pool_bvc_fc_ratio, cfg_pool_bvc_fc_ratio_cmd, "pool bvc-flow-control-ratio <1-100>", @@ -187,6 +381,64 @@ DEFUN(cfg_pool_bvc_fc_ratio, g_cfg->pool.bvc_fc_ratio = atoi(argv[0]); return CMD_SUCCESS; } +DEFUN_ATTR(cfg_gbproxy_nri_bitlen, + cfg_gbproxy_nri_bitlen_cmd, + "nri bitlen <0-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 (0 disables) pooling)\n", + CMD_ATTR_IMMEDIATE) +{ + g_cfg->pool.nri_bitlen = atoi(argv[0]); + + if (llist_count(&g_cfg->sgsns) > 1 && g_cfg->pool.nri_bitlen == 0) + vty_out(vty, "%% Pooling disabled, but multiple SGSNs defined%s", VTY_NEWLINE); + + /* TODO: Verify all nri ranges and warn on mismatch */ + + return CMD_SUCCESS; +} + +DEFUN_ATTR(cfg_gbproxy_nri_null_add, + cfg_gbproxy_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, + CMD_ATTR_IMMEDIATE) +{ + int rc; + const char *message; + + rc = osmo_nri_ranges_vty_add(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv, + g_cfg->pool.nri_bitlen); + if (message) { + vty_out(vty, "%% nri null add: %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv), + VTY_NEWLINE); + vty_out(vty, "%s: \n" NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv)); + } + if (rc < 0) + return CMD_WARNING; + return CMD_SUCCESS; +} + +DEFUN_ATTR(cfg_gbproxy_nri_null_del, + cfg_gbproxy_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, + CMD_ATTR_IMMEDIATE) +{ + int rc; + const char *message; + rc = osmo_nri_ranges_vty_del(&message, NULL, g_cfg->pool.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; +} static void log_set_bvc_filter(struct log_target *target, const uint16_t *bvci) @@ -379,6 +631,8 @@ int gbproxy_vty_init(void) install_element_ve(&show_gbproxy_bvc_cmd); install_element_ve(&show_gbproxy_cell_cmd); install_element_ve(&show_gbproxy_links_cmd); + install_element_ve(&show_nri_all_cmd); + install_element_ve(&show_nri_nsei_cmd); install_element_ve(&logging_fltr_bvc_cmd); install_element(ENABLE_NODE, &delete_gb_bvci_cmd); @@ -386,8 +640,18 @@ int gbproxy_vty_init(void) install_element(CONFIG_NODE, &cfg_gbproxy_cmd); install_node(&gbproxy_node, config_write_gbproxy); - install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd); install_element(GBPROXY_NODE, &cfg_pool_bvc_fc_ratio_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_nri_bitlen_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_add_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_del_cmd); + + install_element(CONFIG_NODE, &cfg_sgsn_nsei_cmd); + install_node(&sgsn_node, config_write_sgsn); + install_element(SGSN_NODE, &cfg_sgsn_allow_attach_cmd); + install_element(SGSN_NODE, &cfg_sgsn_no_allow_attach_cmd); + install_element(SGSN_NODE, &cfg_sgsn_nri_add_cmd); + install_element(SGSN_NODE, &cfg_sgsn_nri_del_cmd); + return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 4a9449a3..32ed4725 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -32,7 +32,9 @@ EXTRA_DIST = \ $(TESTSUITE) \ vty_test_runner.py \ ctrl_test_runner.py \ - test_nodes.vty \ + osmo-sgsn_test-nodes.vty \ + osmo-gbproxy_test-nodes.vty \ + osmo-gbproxy-pool_test-nodes.vty \ $(NULL) TESTSUITE = $(srcdir)/testsuite @@ -60,10 +62,18 @@ vty-python-test: $(BUILT_SOURCES) # pass -u to vty_script_runner.py by doing: # make vty-transcript-test U=-u vty-transcript-test: + osmo_verify_transcript_vty.py -v \ + -n OsmoGbProxy -p 4246 \ + -r "$(top_builddir)/src/gbproxy/osmo-gbproxy -c $(top_srcdir)/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg" \ + $(U) $${T:-$(srcdir)/osmo-gbproxy_test-nodes.vty} + osmo_verify_transcript_vty.py -v \ + -n OsmoGbProxy -p 4246 \ + -r "$(top_builddir)/src/gbproxy/osmo-gbproxy -c $(top_srcdir)/doc/examples/osmo-gbproxy/osmo-gbproxy-pool.cfg" \ + $(U) $${T:-$(srcdir)/osmo-gbproxy-pool_test-nodes.vty} osmo_verify_transcript_vty.py -v \ -n OsmoSGSN -p 4245 \ -r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \ - $(U) $${T:-$(srcdir)/*.vty} + $(U) $${T:-$(srcdir)/osmo-sgsn*.vty} rm -f $(builddir)/sms.db $(builddir)/gsn_restart # don't run multiple tests concurrently so that the ports don't conflict diff --git a/tests/osmo-gbproxy-pool_test-nodes.vty b/tests/osmo-gbproxy-pool_test-nodes.vty new file mode 100644 index 00000000..a741e483 --- /dev/null +++ b/tests/osmo-gbproxy-pool_test-nodes.vty @@ -0,0 +1,35 @@ +OsmoGbProxy> enable +OsmoGbProxy# show nri all +sgsn nsei 101 + nri add 1 + nri add 11 +sgsn nsei 102 + nri add 2 + nri add 12 +OsmoGbProxy# configure terminal +OsmoGbProxy(config)# list +... + gbproxy + sgsn nsei <0-65534> + ns +... + +OsmoGbProxy(config)# sgsn nsei 101 +OsmoGbProxy(config-sgsn)# list +... + allow-attach + no allow-attach + nri add <0-32767> [<0-32767>] + nri del <0-32767> [<0-32767>] +... + +OsmoGbProxy(config-sgsn)# exit +OsmoGbProxy(config)# gbproxy + +OsmoGbProxy(config-gbproxy)# list +... + pool bvc-flow-control-ratio <1-100> + nri bitlen <0-15> + nri null add <0-32767> [<0-32767>] + nri null del <0-32767> [<0-32767>] +... diff --git a/tests/osmo-gbproxy_test-nodes.vty b/tests/osmo-gbproxy_test-nodes.vty new file mode 100644 index 00000000..8a47aa07 --- /dev/null +++ b/tests/osmo-gbproxy_test-nodes.vty @@ -0,0 +1,32 @@ +OsmoGbProxy> enable +OsmoGbProxy# show nri all +sgsn nsei 101 + % no NRI mappings +... +OsmoGbProxy# configure terminal +OsmoGbProxy(config)# list +... + gbproxy + sgsn nsei <0-65534> + ns +... + +OsmoGbProxy(config)# sgsn nsei 101 +OsmoGbProxy(config-sgsn)# list +... + allow-attach + no allow-attach + nri add <0-32767> [<0-32767>] + nri del <0-32767> [<0-32767>] +... + +OsmoGbProxy(config-sgsn)# exit +OsmoGbProxy(config)# gbproxy + +OsmoGbProxy(config-gbproxy)# list +... + pool bvc-flow-control-ratio <1-100> + nri bitlen <0-15> + nri null add <0-32767> [<0-32767>] + nri null del <0-32767> [<0-32767>] +... diff --git a/tests/test_nodes.vty b/tests/osmo-sgsn_test-nodes.vty similarity index 100% rename from tests/test_nodes.vty rename to tests/osmo-sgsn_test-nodes.vty