Change in osmo-msc[master]: add BSC/MSC neighbor VTY commands for inter-MSC HO

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Stefan Sperling gerrit-no-reply at lists.osmocom.org
Sat Dec 29 12:27:00 UTC 2018


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 <info at sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr at sysmocom.de>
+ * Author: Stefan Sperling <ssperling at 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 <info at sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr at sysmocom.de>
+ * Author: Stefan Sperling <ssperling at 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 <stsp at stsp.name>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20181229/272cf1c7/attachment.htm>


More information about the gerrit-log mailing list