path: root/include
diff options
authorNeels Hofmeyr <neels@hofmeyr.de>2021-03-09 17:11:45 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2021-03-24 21:22:21 +0100
commit764449ec2ea6d6b45239278eae90613df8c93f59 (patch)
treef25eeef115083e20eaa7c4713b18d1889e7b865e /include
parentdc60505bc585b1d5f61aa7190b3a2f14fecacaa1 (diff)
fix/refactor neighbor config
The neighbor configuration storage is fundamentally broken: it requires all local cells to be configured before being able to list them as neighbors of each other. Upon config write-back, the neighbor config however is placed back inline with the other config, and hence a written-out neighbor config no longer works on program restart. The cause of this problem is that the config is stored as explicit pointers between local cells (struct gsm_bts), which of course requires the pointer to exist before being able to reference it. Instead, store the actual configuration that the user entered as-is, without pointers or references to objects that need to be ready. Resolve the neighbors every time a neighbor is needed. Hence the user may enter any config at any place in the config file, even non-working config (like a BTS number that doesn't exist), and the relation to actual local or remote neighbor cells is made at runtime. Abort program startup if the initial neighbor configuration contains errors. Related: OS#5018 Change-Id: I9ed992f8bfff888b3933733c0576f92d50f2625b
Diffstat (limited to 'include')
4 files changed, 72 insertions, 49 deletions
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index efa413411..f40aa3ec2 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -496,10 +496,13 @@ struct gsm_bts {
struct handover_cfg *ho;
- /* A list of struct gsm_bts_ref, indicating neighbors of this BTS.
- * When the si_common neigh_list is in automatic mode, it is populated from this list as well as
- * gsm_network->neighbor_bss_cells. */
- struct llist_head local_neighbors;
+ /* Local and remote neighbor configuration: a list of neighbors as written in the VTY config, not resolved to
+ * actual cells. Entries may point at non-existing BTS numbers, or yet unconfigured ARFCN+BSIC. The point of
+ * this list is to keep the config as the user entered it: a) to write it back exactly as entered, and b) to
+ * allow adding neighbor cells that will only be configured further down in the config file.
+ * An actual neighbor cell object (local or remote-BSS) is resolved "at runtime" whenever a neighbor is being
+ * looked up. */
+ struct llist_head neighbors;
/* BTS-specific overrides for timer values from struct gsm_network. */
uint8_t T3122; /* ASSIGNMENT REJECT wait indication */
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 1bf21aef1..2a9da26bc 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -31,7 +31,6 @@
#include <osmocom/abis/e1_input.h>
#include <osmocom/bsc/meas_rep.h>
#include <osmocom/bsc/acc.h>
-#include <osmocom/bsc/neighbor_ident.h>
#include <osmocom/bsc/osmux.h>
#define GSM_T3122_DEFAULT 10
@@ -174,10 +173,16 @@ extern const struct value_string handover_scope_names[];
inline static const char *handover_scope_name(enum handover_scope val)
{ return get_value_string(handover_scope_names, val); }
+/* Cell ARFCN + BSIC. */
+struct cell_ab {
+ uint16_t arfcn;
+ uint8_t bsic;
struct handover_out_req {
enum hodec_id from_hodec_id;
struct gsm_lchan *old_lchan;
- struct neighbor_ident_key target_nik;
+ struct cell_ab target_cell_ab;
enum gsm_chan_t new_lchan_type; /*< leave GSM_LCHAN_NONE to use same as old_lchan */
@@ -205,7 +210,7 @@ struct handover {
enum hodec_id from_hodec_id;
enum handover_scope scope;
enum gsm_chan_t new_lchan_type;
- struct neighbor_ident_key target_cell;
+ struct cell_ab target_cell_ab;
/* For inter-BSC handover, this may reflect more than one Cell ID. Must also be set for intra-BSC handover,
* because it is used as key for penalty timers (e.g. in handover decision 2). */
@@ -850,12 +855,6 @@ struct load_counter {
unsigned int used;
-/* Useful to track N-N relations between BTS, for example neighbors. */
-struct gsm_bts_ref {
- struct llist_head entry;
- struct gsm_bts *bts;
/* A single Page of a SMSCB message */
struct bts_smscb_page {
/* SMSCB message we're part of */
@@ -1219,8 +1218,6 @@ struct gsm_network {
struct osmo_tdef *tdefs;
} mgw;
- /* Remote BSS Cell Identifier Lists */
- struct neighbor_ident_list *neighbor_bss_cells;
/* Remote BSS resolution sevice (CTRL iface) */
struct {
char *addr;
diff --git a/include/osmocom/bsc/handover.h b/include/osmocom/bsc/handover.h
index a71bb98f0..f67149142 100644
--- a/include/osmocom/bsc/handover.h
+++ b/include/osmocom/bsc/handover.h
@@ -82,8 +82,9 @@ enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection
void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn);
int find_handover_target_cell(struct gsm_bts **local_target_cell_p,
- const struct gsm0808_cell_id_list2 **remote_target_cell_p,
- struct gsm_subscriber_connection *conn, const struct neighbor_ident_key *search_for,
+ struct gsm0808_cell_id_list2 *remote_target_cells,
+ struct gsm_subscriber_connection *conn,
+ const struct cell_ab *search_for,
bool log_errors);
void handover_parse_inter_bsc_mt(struct gsm_subscriber_connection *conn,
diff --git a/include/osmocom/bsc/neighbor_ident.h b/include/osmocom/bsc/neighbor_ident.h
index cab7f9e29..0565d528c 100644
--- a/include/osmocom/bsc/neighbor_ident.h
+++ b/include/osmocom/bsc/neighbor_ident.h
@@ -7,62 +7,84 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/bsc/gsm_data.h>
struct vty;
struct gsm_network;
struct gsm_bts;
-struct neighbor_ident_list;
struct gsm0808_cell_id_list2;
#define BSIC_ANY 0xff
-struct neighbor_ident_key {
- int from_bts; /*< BTS nr 0..255 or NEIGHBOR_IDENT_KEY_ANY_BTS */
- uint16_t arfcn;
- uint8_t bsic;
+enum neighbor_type {
+/* One line of VTY neighbor configuration as entered by the user.
+ * One of three variants:
+ *
+ * - just the local-BSS neighbor BTS nr:
+ * neighbor bts 123
+ *
+ * - a neighbor cell identifier *without* ARFCN+BSIC:
+ * neighbor (lac|lac-ci|cgi|cgi-ps) 1 2 3...
+ * This is an elaborate / BTS-nr-agnostic way of indicating a local-BSS neighbor cell.
+ *
+ * - a neighbor cell identifier *with* ARFCN+BSIC:
+ * neighbor (lac|lac-ci|cgi|cgi-ps) 1 2 3... arfcn 456 bsic (23|any)
+ * This can either be
+ * - a remote-BSS neighbor cell, or
+ * - a super elaborate way of indicating a local-BSS neighbor, if this cell id exists in the local BSS.
+ */
+struct neighbor {
+ struct llist_head entry;
+ enum neighbor_type type;
+ union {
+ uint8_t bts_nr;
+ struct {
+ struct gsm0808_cell_id id;
+ bool ab_present;
+ struct cell_ab ab;
+ } cell_id;
+ };
-const char *neighbor_ident_key_name(const struct neighbor_ident_key *ni_key);
+int resolve_local_neighbor(struct gsm_bts **local_neighbor_p, const struct gsm_bts *from_bts,
+ const struct neighbor *neighbor);
+int resolve_remote_neighbors(struct gsm_bts *from_bts, const struct cell_ab *target_ab);
-struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx);
-void neighbor_ident_free(struct neighbor_ident_list *nil);
+int cell_ab_to_str_buf(char *buf, size_t buflen, const struct cell_ab *cell);
+char *cell_ab_to_str_c(void *ctx, const struct cell_ab *cell);
-bool neighbor_ident_key_match(const struct neighbor_ident_key *entry,
- const struct neighbor_ident_key *search_for,
- bool exact_match);
+bool cell_ab_match(const struct cell_ab *entry, const struct cell_ab *search_for, bool exact_match);
+bool cell_ab_valid(const struct cell_ab *cell);
-int neighbor_ident_add(struct neighbor_ident_list *nil, const struct neighbor_ident_key *key,
- const struct gsm0808_cell_id_list2 *val);
-const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct neighbor_ident_list *nil,
- const struct neighbor_ident_key *key);
-bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_key *key);
-void neighbor_ident_clear(struct neighbor_ident_list *nil);
+int neighbor_to_str_buf(char *buf, size_t buflen, const struct neighbor *n);
+char *neighbor_to_str_c(void *ctx, const struct neighbor *n);
+bool neighbor_same(const struct neighbor *a, const struct neighbor *b, bool check_cell_ab);
-void neighbor_ident_iter(const struct neighbor_ident_list *nil,
- bool (* iter_cb )(const struct neighbor_ident_key *key,
- const struct gsm0808_cell_id_list2 *val,
- void *cb_data),
- void *cb_data);
+void bts_cell_ab(struct cell_ab *arfcn_bsic, const struct gsm_bts *bts);
-struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts);
+int resolve_neighbors(struct gsm_bts **local_neighbor_p, struct gsm0808_cell_id_list2 *remote_neighbors,
+ struct gsm_bts *from_bts, const struct cell_ab *target_ab, bool log_errors);
-void neighbor_ident_vty_init(struct gsm_network *net, struct neighbor_ident_list *nil);
+void neighbor_ident_vty_init();
void neighbor_ident_vty_write_bts(struct vty *vty, const char *indent, struct gsm_bts *bts);
void neighbor_ident_vty_write_network(struct vty *vty, const char *indent);
-bool neighbor_ident_bts_entry_exists(uint8_t from_bts);
+int neighbors_check_cfg();
-#define NEIGHBOR_IDENT_VTY_KEY_PARAMS "arfcn <0-1023> bsic (<0-63>|any)"
+#define CELL_AB_VTY_PARAMS "arfcn <0-1023> bsic (<0-63>|any)"
+#define CELL_AB_VTY_DOC \
"ARFCN of neighbor cell\n" "ARFCN value\n" \
"BSIC of neighbor cell\n" "BSIC value\n" \
"for all BSICs / use any BSIC in this ARFCN\n"
-bool neighbor_ident_vty_parse_key_params(struct vty *vty, const char **argv,
- struct neighbor_ident_key *key);
-bool neighbor_ident_bts_parse_key_params(struct vty *vty, struct gsm_bts *bts, const char **argv,
- struct neighbor_ident_key *key);
+void neighbor_ident_vty_parse_arfcn_bsic(struct cell_ab *ab, const char **argv);
struct ctrl_handle *neighbor_controlif_setup(struct gsm_network *net);
int neighbor_ctrl_cmds_install(struct gsm_network *net);