Stefan Sperling has uploaded this change for review. ( https://gerrit.osmocom.org/12446
Change subject: add BSC/MSC neighbor VTY commands for inter-MSC HO ...................................................................... add BSC/MSC neighbor VTY commands for inter-MSC HO Allow configuration of neighbor BSC/MSC via osmo-msc.cfg and the VTY. Each neighbor is mapped to the list of identifiers of cells which are reachable via that neighbor. A new neighbor_ident API manages the neighbor list and supports mapping neighboring BSCs/MSCs to cells, and vice versa. Neighbours are managed with the following new VTY commands: [no] neighbor lac <0-65535> bsc-pc POINT_CODE [no] neighbor lac <0-65535> msc-ip-name IPA_NAME [no] neighbor lac <0-65535> ci <0-999>bsc-pc POINT_CODE [no] neighbor lac <0-65535> ci <0-999> msc-ip-name IPA_NAME [no] neighbor cgi <0-999> <0-999> <0-65535> <0-65535> bsc-pc POINT_CODE [no] neighbor cgi <0-999> <0-999> <0-65535> <0-65535> msc-ipa-name IPA_NAME show neighbor all show neighbor bsc-pc POINT_CODE show neighbor msc-ipa-name IPA_NAME Change-Id: Ia0dd08b087bfd4aa22e234917669d003150a4cd4 Depends: I5535f0d149c2173294538df75764dd181b023312 --- M include/osmocom/msc/Makefile.am M include/osmocom/msc/gsm_data.h A include/osmocom/msc/neighbor_ident.h M src/libmsc/Makefile.am M src/libmsc/msc_vty.c A src/libmsc/neighbor_ident.c A src/libmsc/neighbor_ident_vty.c 7 files changed, 700 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/46/12446/1 diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am index d98bc9c..e821993 100644 --- a/include/osmocom/msc/Makefile.am +++ b/include/osmocom/msc/Makefile.am @@ -19,6 +19,7 @@ msc_common.h \ msc_ifaces.h \ msc_mgcp.h \ + neighbor_ident.h \ a_reset.h \ ran_conn.h \ rrlp.h \ diff --git a/include/osmocom/msc/gsm_data.h b/include/osmocom/msc/gsm_data.h index d2511cb..8930380 100644 --- a/include/osmocom/msc/gsm_data.h +++ b/include/osmocom/msc/gsm_data.h @@ -16,6 +16,7 @@ #include <osmocom/mgcp_client/mgcp_client.h> #include <osmocom/msc/msc_common.h> +#include <osmocom/msc/neighbor_ident.h> #include "gsm_data_shared.h" @@ -208,6 +209,10 @@ struct osmo_sccp_instance *sccp; } a; + /* A list of neighbor BSCs. This list is defined statically via VTY and does not + * necessarily correspond to BSCs attached to the A interface at a given moment. */ + struct neighbor_ident_list *neighbor_list; + struct { /* MSISDN to which to route MO emergency calls */ char *route_to_msisdn; diff --git a/include/osmocom/msc/neighbor_ident.h b/include/osmocom/msc/neighbor_ident.h new file mode 100644 index 0000000..d79d262 --- /dev/null +++ b/include/osmocom/msc/neighbor_ident.h @@ -0,0 +1,71 @@ +/* Manage identity of neighboring BSS cells for inter-BSC handover */ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/gsm/gsm0808.h> + +struct vty; +struct gsm_network; + +enum msc_neighbor_type { + /* Neighboring BSC reachable via SCCP. */ + MSC_NEIGHBOR_TYPE_BSC, + + /* Neighboring MSC reachable via GSUP. */ + MSC_NEIGHBOR_TYPE_MSC +}; + +struct neighbor_ident_addr { + enum msc_neighbor_type type; + union { + int point_code; /* BSC */ + const char *ipa_name; /* MSC */ + } a; +}; + +struct neighbor_ident_list { + struct llist_head list; +}; + +struct neighbor_ident { + struct llist_head entry; + + /* Address of a neighboring BSC or MSC. */ + struct neighbor_ident_addr addr; + + /* IDs of cells in this neighbor's domain. */ + struct gsm0808_cell_id_list2 cell_ids; +}; + +struct gsm0808_cell_id; +struct gsm0808_cell_id_list2; + +const char *neighbor_ident_addr_name(struct gsm_network *net, const struct neighbor_ident_addr *ni_addr); + +struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx); +void neighbor_ident_free(struct neighbor_ident_list *nil); + +bool neighbor_ident_addr_match(const struct neighbor_ident_addr *entry, + const struct neighbor_ident_addr *search_for, + bool exact_match); + +int neighbor_ident_add(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr, + const struct gsm0808_cell_id_list2 *cell_ids); +const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct neighbor_ident_list *nil, + const struct neighbor_ident_addr *addr); +const struct neighbor_ident_addr *neighbor_ident_lookup_cell(const struct neighbor_ident_list *nil, + struct gsm0808_cell_id *cell_id); +bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr); +void neighbor_ident_clear(struct neighbor_ident_list *nil); + +void neighbor_ident_iter(const struct neighbor_ident_list *nil, + bool (* iter_cb )(const struct neighbor_ident_addr *addr, + const struct gsm0808_cell_id_list2 *cell_ids, + void *cb_data), + void *cb_data); + +void neighbor_ident_vty_init(struct gsm_network *net); +void neighbor_ident_vty_write(struct vty *vty); diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am index 9183ff9..f498001 100644 --- a/src/libmsc/Makefile.am +++ b/src/libmsc/Makefile.am @@ -44,6 +44,8 @@ mncc_sock.c \ msc_ifaces.c \ msc_mgcp.c \ + neighbor_ident.c \ + neighbor_ident_vty.c \ ran_conn.c \ rrlp.c \ silent_call.c \ diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index 7745e5d..1af42e4 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -1538,6 +1538,8 @@ #ifdef BUILD_IU ranap_iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc); #endif + neighbor_ident_vty_init(msc_network); + osmo_fsm_vty_add_cmds(); osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL); diff --git a/src/libmsc/neighbor_ident.c b/src/libmsc/neighbor_ident.c new file mode 100644 index 0000000..f7187a9 --- /dev/null +++ b/src/libmsc/neighbor_ident.c @@ -0,0 +1,206 @@ +/* Manage identity of neighboring BSS cells for inter-MSC handover. */ +/* (C) 2018 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de> + * + * All Rights Reserved + * + * Author: Neels Hofmeyr <nhofm...@sysmocom.de> + * Author: Stefan Sperling <ssperl...@sysmocom.de> + * + * 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 <errno.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/utils.h> +#include <osmocom/gsm/gsm0808.h> +#include <osmocom/sigtran/osmo_ss7.h> + +#include <osmocom/msc/neighbor_ident.h> +#include <osmocom/msc/gsm_data.h> + +/* XXX greater than or equal to IPA_STIRNG_MAX (libosmocore) and MAX_PC_STR_LEN (libosmo-sccp). */ +#define NEIGHBOR_IDENT_ADDR_STRING_MAX 64 + +const char *neighbor_ident_addr_name(struct gsm_network *net, const struct neighbor_ident_addr *na) +{ + static char buf[NEIGHBOR_IDENT_ADDR_STRING_MAX + 4]; + struct osmo_ss7_instance *ss7; + + switch (na->type) { + case MSC_NEIGHBOR_TYPE_BSC: + ss7 = osmo_ss7_instance_find(net->a.cs7_instance); + OSMO_ASSERT(ss7); + snprintf(buf, sizeof(buf), "BSC %s", osmo_ss7_pointcode_print(ss7, na->a.point_code)); + break; + case MSC_NEIGHBOR_TYPE_MSC: + snprintf(buf, sizeof(buf), "MSC %s", na->a.ipa_name); + break; + default: + return NULL; + } + + return buf; +} + +struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx) +{ + struct neighbor_ident_list *nil = talloc_zero(talloc_ctx, struct neighbor_ident_list); + OSMO_ASSERT(nil); + INIT_LLIST_HEAD(&nil->list); + return nil; +} + +void neighbor_ident_free(struct neighbor_ident_list *nil) +{ + if (!nil) + return; + talloc_free(nil); +} + +static struct neighbor_ident *_neighbor_ident_get(const struct neighbor_ident_list *nil, + const struct neighbor_ident_addr *na) +{ + struct neighbor_ident *ni; + + llist_for_each_entry(ni, &nil->list, entry) { + if (na->type != ni->addr.type) + continue; + + switch (na->type) { + case MSC_NEIGHBOR_TYPE_BSC: + if (ni->addr.a.point_code == na->a.point_code) + return ni; + break; + case MSC_NEIGHBOR_TYPE_MSC: + if (strcmp(ni->addr.a.ipa_name, na->a.ipa_name) == 0) + return ni; + break; + } + } + + return NULL; +} + +static void _neighbor_ident_free(struct neighbor_ident *ni) +{ + llist_del(&ni->entry); + talloc_free(ni); +} + +/*! Add Cell Identifiers to a neighbor BSC/MSC entry. + * Exactly one kind of identifier is allowed per entry, and any number of entries of that kind + * may be added up to the capacity of gsm0808_cell_id_list2, by one or more calls to this function. To + * replace an existing entry, first call neighbor_ident_del(nil, cell_id). + * \returns number of entries in the resulting identifier list, or negative on error: + * see gsm0808_cell_id_list_add() for the meaning of returned error codes; + * return -ENOMEM when the list is not initialized, -ERANGE when the BSIC value is too large. */ +int neighbor_ident_add(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr, + const struct gsm0808_cell_id_list2 *cell_id) +{ + struct neighbor_ident *ni; + int rc; + + if (!nil) + return -ENOMEM; + + ni = _neighbor_ident_get(nil, addr); + if (!ni) { + ni = talloc_zero(nil, struct neighbor_ident); + OSMO_ASSERT(ni); + ni->addr.type = addr->type; + switch (ni->addr.type) { + case MSC_NEIGHBOR_TYPE_MSC: + ni->addr.a.ipa_name = talloc_strdup(ni, addr->a.ipa_name); + break; + case MSC_NEIGHBOR_TYPE_BSC: + ni->addr.a.point_code = addr->a.point_code; + break; + } + llist_add_tail(&ni->entry, &nil->list); + } + + rc = gsm0808_cell_id_list_add(&ni->cell_ids, cell_id); + if (rc < 0) + return rc; + + return ni->cell_ids.id_list_len; +} + +/*! Find cell identity for given BSC or MSC, as previously added by neighbor_ident_add(). + */ +const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct neighbor_ident_list *nil, + const struct neighbor_ident_addr *addr) +{ + struct neighbor_ident *ni; + if (!nil) + return NULL; + ni = _neighbor_ident_get(nil, addr); + if (!ni) + return NULL; + return &ni->cell_ids; +} + +/*! Find a BSC or MSC, as previously added by neighbor_ident_add(), for a given cell identity. + */ +const struct neighbor_ident_addr *neighbor_ident_lookup_cell(const struct neighbor_ident_list *nil, + struct gsm0808_cell_id *cell_id) +{ + struct neighbor_ident *ni; + if (!nil) + return NULL; + llist_for_each_entry(ni, &nil->list, entry) { + if (gsm0808_cell_id_matches_list(cell_id, &ni->cell_ids, 0)) + return &ni->addr; + } + + return NULL; +} + +bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr) +{ + struct neighbor_ident *ni; + if (!nil) + return false; + ni = _neighbor_ident_get(nil, addr); + if (!ni) + return false; + _neighbor_ident_free(ni); + return true; +} + +void neighbor_ident_clear(struct neighbor_ident_list *nil) +{ + struct neighbor_ident *ni; + while ((ni = llist_first_entry_or_null(&nil->list, struct neighbor_ident, entry))) + _neighbor_ident_free(ni); +} + +/*! Iterate all neighbor_ident_list entries and call iter_cb for each. + * If iter_cb returns false, the iteration is stopped. */ +void neighbor_ident_iter(const struct neighbor_ident_list *nil, + bool (* iter_cb )(const struct neighbor_ident_addr *addr, + const struct gsm0808_cell_id_list2 *cell_ids, + void *cb_data), + void *cb_data) +{ + struct neighbor_ident *ni, *ni_next; + if (!nil) + return; + llist_for_each_entry_safe(ni, ni_next, &nil->list, entry) { + if (!iter_cb(&ni->addr, &ni->cell_ids, cb_data)) + return; + } +} diff --git a/src/libmsc/neighbor_ident_vty.c b/src/libmsc/neighbor_ident_vty.c new file mode 100644 index 0000000..a44a284 --- /dev/null +++ b/src/libmsc/neighbor_ident_vty.c @@ -0,0 +1,413 @@ +/* Quagga VTY implementation to manage identity of neighboring BSS cells for inter-BSC handover. */ +/* (C) 2018 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de> + * + * All Rights Reserved + * + * Author: Neels Hofmeyr <nhofm...@sysmocom.de> + * Author: Stefan Sperling <ssperl...@sysmocom.de> + * + * 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 <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <osmocom/vty/command.h> +#include <osmocom/gsm/gsm0808.h> +#include <osmocom/sigtran/osmo_ss7.h> + +#include <osmocom/msc/vty.h> +#include <osmocom/msc/neighbor_ident.h> +#include <osmocom/msc/gsm_data.h> + +#define NEIGHBOR_ADD_CMD "neighbor " +#define NEIGHBOR_DEL_CMD "no neighbor " +#define NEIGHBOR_SHOW_CMD "show neighbor " +#define NEIGHBOR_DOC "Manage neighbor BSS cells\n" +#define NEIGHBOR_ADD_DOC NEIGHBOR_DOC "Add " +#define NEIGHBOR_DEL_DOC NO_STR "Remove neighbor BSS cell\n" + +#define LAC_PARAMS "lac <0-65535>" +#define LAC_DOC "Neighbor cell by LAC\n" "LAC\n" + +#define LAC_CI_PARAMS "lac-ci <0-65535> <0-65535>" +#define LAC_CI_DOC "Neighbor cell by LAC and CI\n" "LAC\n" "CI\n" + +#define CGI_PARAMS "cgi <0-999> <0-999> <0-65535> <0-65535>" +#define CGI_DOC "Neighbor cell by cgi\n" "MCC\n" "MNC\n" "LAC\n" "CI\n" + +#define NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS "bsc-pc POINT_CODE" +#define NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC "Point code of neighbor BSC\n" "Point code value\n" +#define NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS "msc-ipa-name IPA_NAME" +#define NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC "IPA name of neighbor MSC\n" "IPA name value\n" + +static struct gsm_network *g_net = NULL; + +static struct gsm0808_cell_id *neighbor_ident_vty_parse_lac(struct vty *vty, const char **argv) +{ + static struct gsm0808_cell_id cell_id; + cell_id = (struct gsm0808_cell_id){ + .id_discr = CELL_IDENT_LAC, + .id.lac = atoi(argv[0]), + }; + return &cell_id; +} + +static struct gsm0808_cell_id *neighbor_ident_vty_parse_lac_ci(struct vty *vty, const char **argv) +{ + static struct gsm0808_cell_id cell_id; + cell_id = (struct gsm0808_cell_id){ + .id_discr = CELL_IDENT_LAC_AND_CI, + .id.lac_and_ci = { + .lac = atoi(argv[0]), + .ci = atoi(argv[1]), + }, + }; + return &cell_id; +} + +static struct gsm0808_cell_id *neighbor_ident_vty_parse_cgi(struct vty *vty, const char **argv) +{ + static struct gsm0808_cell_id cell_id; + cell_id = (struct gsm0808_cell_id){ + .id_discr = CELL_IDENT_WHOLE_GLOBAL, + }; + struct osmo_cell_global_id *cgi = &cell_id.id.global; + const char *mcc = argv[0]; + const char *mnc = argv[1]; + const char *lac = argv[2]; + const char *ci = argv[3]; + + if (osmo_mcc_from_str(mcc, &cgi->lai.plmn.mcc)) { + vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE); + return NULL; + } + + if (osmo_mnc_from_str(mnc, &cgi->lai.plmn.mnc, &cgi->lai.plmn.mnc_3_digits)) { + vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE); + return NULL; + } + + cgi->lai.lac = atoi(lac); + cgi->cell_identity = atoi(ci); + return &cell_id; +} + +static int add_neighbor(struct vty *vty, struct neighbor_ident_addr *addr, const struct gsm0808_cell_id *cell_id) +{ + struct gsm0808_cell_id_list2 cell_ids; + int rc; + + gsm0808_cell_id_to_list(&cell_ids, cell_id); + rc = neighbor_ident_add(g_net->neighbor_list, addr, &cell_ids); + if (rc < 0) { + vty_out(vty, "%% Error: cannot add cell %s to neighbor %s: %s%s", + gsm0808_cell_id_name(cell_id), neighbor_ident_addr_name(g_net, addr), + strerror(-rc), VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +static int parse_point_code(const char *point_code_str) +{ + struct osmo_ss7_instance *ss7 = osmo_ss7_instance_find(g_net->a.cs7_instance); + OSMO_ASSERT(ss7); + return osmo_ss7_pointcode_parse(ss7, point_code_str); +} + +DEFUN(cfg_neighbor_add_lac_bsc, cfg_neighbor_add_lac_bsc_cmd, + NEIGHBOR_ADD_CMD LAC_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS, + NEIGHBOR_ADD_DOC LAC_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + int point_code = parse_point_code(argv[1]); + + if (point_code < 0) { + vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + addr.type = MSC_NEIGHBOR_TYPE_BSC; + addr.a.point_code = point_code; + return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac(vty, argv + 1)); +} + +DEFUN(cfg_neighbor_add_lac_msc, cfg_neighbor_add_lac_msc_cmd, + NEIGHBOR_ADD_CMD LAC_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS, + NEIGHBOR_ADD_DOC LAC_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + + addr.type = MSC_NEIGHBOR_TYPE_MSC; + addr.a.ipa_name = argv[1]; + return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac(vty, argv + 1)); +} + +DEFUN(cfg_neighbor_add_lac_ci_bsc, cfg_neighbor_add_lac_ci_bsc_cmd, + NEIGHBOR_ADD_CMD LAC_CI_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS, + NEIGHBOR_ADD_DOC LAC_CI_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + int point_code = parse_point_code(argv[2]); + + if (point_code < 0) { + vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + addr.type = MSC_NEIGHBOR_TYPE_BSC; + addr.a.point_code = point_code; + return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac_ci(vty, argv + 1)); +} + +DEFUN(cfg_neighbor_add_lac_ci_msc, cfg_neighbor_add_lac_ci_msc_cmd, + NEIGHBOR_ADD_CMD LAC_CI_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS, + NEIGHBOR_ADD_DOC LAC_CI_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + + addr.type = MSC_NEIGHBOR_TYPE_MSC; + addr.a.ipa_name = argv[2]; + return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac_ci(vty, argv + 1)); +} + +DEFUN(cfg_neighbor_add_cgi_bsc, cfg_neighbor_add_cgi_bsc_cmd, + NEIGHBOR_ADD_CMD CGI_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS, + NEIGHBOR_ADD_DOC CGI_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + int point_code = parse_point_code(argv[4]); + + if (point_code < 0) { + vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + addr.type = MSC_NEIGHBOR_TYPE_BSC; + addr.a.point_code = point_code; + return add_neighbor(vty, &addr, neighbor_ident_vty_parse_cgi(vty, argv + 1)); +} + +DEFUN(cfg_neighbor_add_cgi_msc, cfg_neighbor_add_cgi_msc_cmd, + NEIGHBOR_ADD_CMD CGI_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS, + NEIGHBOR_ADD_DOC CGI_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + + addr.type = MSC_NEIGHBOR_TYPE_MSC; + addr.a.ipa_name = argv[4]; + return add_neighbor(vty, &addr, neighbor_ident_vty_parse_cgi(vty, argv + 1)); +} + +static int del_by_addr(struct vty *vty, const struct neighbor_ident_addr *addr) +{ + int removed = 0; + + if (vty->node != MSC_NODE) { + vty_out(vty, "%% Error: cannot remove neighbor, not on MSC node%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (neighbor_ident_del(g_net->neighbor_list, addr)) { + vty_out(vty, "%% Removed neighbor %s%s", + neighbor_ident_addr_name(g_net, addr), VTY_NEWLINE); + removed = 1; + } + + if (!removed) { + vty_out(vty, "%% Cannot remove, no such neighbor: %s%s", + neighbor_ident_addr_name(g_net, addr), VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_del_neighbor_bsc, cfg_del_neighbor_bsc_cmd, + NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS, + SHOW_STR "Delete a neighbor BSC\n" "BSC point code\n" + "Delete a specified neighbor BSC\n" + NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + int point_code = parse_point_code(argv[0]); + + if (point_code < 0) { + vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + addr.type = MSC_NEIGHBOR_TYPE_BSC; + addr.a.point_code = point_code; + return del_by_addr(vty, &addr); +} + +DEFUN(cfg_del_neighbor_msc, cfg_del_neighbor_msc_cmd, + NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS, + SHOW_STR "Delete a neighbor MSC\n" "MSC ipa-nam\n" + "Delete a specified neighbor MSC\n" + NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC) +{ + struct neighbor_ident_addr addr; + + addr.type = MSC_NEIGHBOR_TYPE_MSC; + addr.a.ipa_name = argv[0]; + return del_by_addr(vty, &addr); +} + +static void write_neighbor_ident(struct vty *vty, const struct neighbor_ident *ni) +{ + const struct neighbor_ident_addr *addr = &ni->addr; + const struct gsm0808_cell_id_list2 *cell_ids = &ni->cell_ids; + struct osmo_ss7_instance *ss7; + int i; + + switch (cell_ids->id_discr) { + case CELL_IDENT_LAC: + for (i = 0; i < cell_ids->id_list_len; i++) { + vty_out(vty, " neighbor lac %u", cell_ids->id_list[i].lac); + } + break; + case CELL_IDENT_LAC_AND_CI: + for (i = 0; i < cell_ids->id_list_len; i++) { + vty_out(vty, " neighbor lac-ci %u %u", cell_ids->id_list[i].lac_and_ci.lac, + cell_ids->id_list[i].lac_and_ci.ci); + } + break; + case CELL_IDENT_WHOLE_GLOBAL: + for (i = 0; i < cell_ids->id_list_len; i++) { + const struct osmo_cell_global_id *cgi = &cell_ids->id_list[i].global; + vty_out(vty, " neighbor cgi %s %s %u %u", osmo_mcc_name(cgi->lai.plmn.mcc), + osmo_mnc_name(cgi->lai.plmn.mnc, cgi->lai.plmn.mnc_3_digits), + cgi->lai.lac, cgi->cell_identity); + } + break; + default: + vty_out(vty, "%% Unsupported Cell Identity%s", VTY_NEWLINE); + return; + } + + switch (ni->addr.type) { + case MSC_NEIGHBOR_TYPE_BSC: + ss7 = osmo_ss7_instance_find(g_net->a.cs7_instance); + OSMO_ASSERT(ss7); + vty_out(vty, "bsc-pc %s%s", osmo_ss7_pointcode_print(ss7, addr->a.point_code), VTY_NEWLINE); + break; + case MSC_NEIGHBOR_TYPE_MSC: + vty_out(vty, "msc-ipa-name %s%s", addr->a.ipa_name, VTY_NEWLINE); + break; + } +} + +void neighbor_ident_vty_write(struct vty *vty) +{ + const struct neighbor_ident *ni; + + llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) + write_neighbor_ident(vty, ni); +} + +DEFUN(show_neighbor_all, show_neighbor_all_cmd, + NEIGHBOR_SHOW_CMD "all", + SHOW_STR "Display information about neighbor BSCs and MSCs\n" + "Show which cells are reachable via the neighbor BSCs and MSCs\n") +{ + struct neighbor_ident *ni; + + llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) { + vty_out(vty, "%s: %s%s", neighbor_ident_addr_name(g_net, &ni->addr), + gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(show_neighbor_bsc, show_neighbor_bsc_cmd, + NEIGHBOR_SHOW_CMD NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS, + SHOW_STR "Display information about a neighbor BSC\n" "BSC point code\n" + "Show which cells are reachable via the specified neighbor BSC\n" + NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC) +{ + int point_code; + struct neighbor_ident *ni; + int found = 0; + + point_code = parse_point_code(argv[0]); + if (point_code < 0) { + vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) { + if (ni->addr.type != MSC_NEIGHBOR_TYPE_BSC) + continue; + if (ni->addr.a.point_code == point_code) { + vty_out(vty, "%s%s", gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE); + found = 1; + break; + } + } + + if (!found) + vty_out(vty, "%% No entry for %s%s", argv[0], VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_neighbor_msc, show_neighbor_msc_cmd, + NEIGHBOR_SHOW_CMD NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS, + SHOW_STR "Display information about a neighbor MSC\n" "MSC ipa-name\n" + "Show which cells are reachable via the specified neighbor MSC\n" + NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC) +{ + const char *ipa_name = argv[0]; + struct neighbor_ident *ni; + int found = 0; + + llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) { + if (ni->addr.type != MSC_NEIGHBOR_TYPE_MSC) + continue; + if (strcmp(ni->addr.a.ipa_name, ipa_name) == 0) { + vty_out(vty, "%s%s", gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE); + found = 1; + break; + } + } + + if (!found) + vty_out(vty, "%% No entry for %s%s", ipa_name, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +void neighbor_ident_vty_init(struct gsm_network *net) +{ + g_net = net; + g_net->neighbor_list = neighbor_ident_init(net); + + install_element(MSC_NODE, &cfg_neighbor_add_lac_bsc_cmd); + install_element(MSC_NODE, &cfg_neighbor_add_lac_msc_cmd); + install_element(MSC_NODE, &cfg_neighbor_add_lac_ci_bsc_cmd); + install_element(MSC_NODE, &cfg_neighbor_add_lac_ci_msc_cmd); + install_element(MSC_NODE, &cfg_neighbor_add_cgi_bsc_cmd); + install_element(MSC_NODE, &cfg_neighbor_add_cgi_msc_cmd); + install_element(MSC_NODE, &cfg_del_neighbor_bsc_cmd); + install_element(MSC_NODE, &cfg_del_neighbor_msc_cmd); + install_element_ve(&show_neighbor_all_cmd); + install_element_ve(&show_neighbor_bsc_cmd); + install_element_ve(&show_neighbor_msc_cmd); +} -- To view, visit https://gerrit.osmocom.org/12446 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-msc Gerrit-Branch: master Gerrit-MessageType: newchange Gerrit-Change-Id: Ia0dd08b087bfd4aa22e234917669d003150a4cd4 Gerrit-Change-Number: 12446 Gerrit-PatchSet: 1 Gerrit-Owner: Stefan Sperling <s...@stsp.name>