aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/handover_logic.c
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2019-07-13 01:12:53 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2019-08-13 23:47:23 +0200
commit91a202d4885d1e3aff6cb090ec688d695c2cd26b (patch)
treed3a0ebfff0c2acdce868a4756cd3231e41563443 /src/osmo-bsc/handover_logic.c
parent12224e7ca7201b78cdf78b055065f07d223a060d (diff)
neighbor config: allow re-using ARFCN+BSIC pairs
Fix neighbor config to match OsmoBSC manual: implement the plan for neighbor configuration that was so far only described in the manual without actually being in operation. This first allows re-using ARFCN+BSIC pairs in and across BSS. So far the handover_start() code always looked for handover target cells across *all* local cells, even if they were not listed as neighbors to a source cell. Imply all cells as neighbors only as long as there are no explicit neighbors configured. As soon as the first 'neighbor' line appears in a 'bts' config, only the listed neighbors are regarded as handover target cells. (The 'neighbor-list' commands are not related to this, only the relatively new 'neighbor (bts|lac|cgi|...)' commands affect actual handover procedures.) TTCN3 tests TC_ho_neighbor_config_1 thru _7 play through the various aspects of neighbor configuration: both the legacy implicit all-cells-are-neighbors as well as allowing only explicit neighbors by config. Related: OS#4056 Related: osmo-ttcn3-hacks Ia4ba0e75abd3d45a3422b2525e5f938cdc5a04cc Change-Id: I29bca59ab232eddc74e0d4698efb9c9992443983
Diffstat (limited to 'src/osmo-bsc/handover_logic.c')
-rw-r--r--src/osmo-bsc/handover_logic.c211
1 files changed, 187 insertions, 24 deletions
diff --git a/src/osmo-bsc/handover_logic.c b/src/osmo-bsc/handover_logic.c
index 5725213ef..5be838340 100644
--- a/src/osmo-bsc/handover_logic.c
+++ b/src/osmo-bsc/handover_logic.c
@@ -125,42 +125,205 @@ int bts_handover_count(struct gsm_bts *bts, int ho_scopes)
return count;
}
-struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,
- const struct neighbor_ident_key *search_for)
+/* Find out a handover target cell for the given neighbor_ident_key,
+ * and make sure there are no ambiguous matches.
+ * Given a source BTS and a target ARFCN+BSIC, find which cell is the right handover target.
+ * ARFCN+BSIC may be re-used within and/or across BSS, so make sure that only those cells that are explicitly
+ * listed as neighbor of the source cell are viable handover targets.
+ * The (legacy) default configuration is that, when no explicit neighbors are listed, that all local cells are
+ * neighbors, in which case each ARFCN+BSIC must exist at most once.
+ * If there is more than one viable handover target cell found for the given ARFCN+BSIC, that constitutes a
+ * configuration error and should not result in handover, so that the system's misconfiguration is more likely
+ * to be found.
+ */
+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,
+ bool log_errors)
{
- struct gsm_bts *found = NULL;
- struct gsm_bts *bts;
- struct gsm_bts *wildcard_match = NULL;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- struct neighbor_ident_key entry = {
- .from_bts = NEIGHBOR_IDENT_KEY_ANY_BTS,
- .arfcn = bts->c0->arfcn,
- .bsic = bts->bsic,
- };
- if (neighbor_ident_key_match(&entry, search_for, true)) {
- if (found) {
- LOGP(DHO, LOGL_ERROR, "CONFIG ERROR: Multiple BTS match %s: %d and %d\n",
- neighbor_ident_key_name(search_for),
- found->nr, bts->nr);
- return found;
+ struct gsm_network *net = conn->network;
+ struct gsm_bts *from_bts;
+ struct gsm_bts *local_target_cell = NULL;
+ const struct gsm0808_cell_id_list2 *remote_target_cell = NULL;
+ struct gsm_bts_ref *neigh;
+ bool ho_active;
+ bool as_active;
+
+ if (local_target_cell_p)
+ *local_target_cell_p = NULL;
+ if (remote_target_cell_p)
+ *remote_target_cell_p = NULL;
+
+ if (!search_for) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR, "Handover without target cell\n");
+ return -EINVAL;
+ }
+
+ from_bts = gsm_bts_num(net, search_for->from_bts);
+ if (!from_bts) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR, "Handover without source cell\n");
+ return -EINVAL;
+ }
+
+ ho_active = ho_get_ho_active(from_bts->ho);
+ as_active = (ho_get_algorithm(from_bts->ho) == 2)
+ && ho_get_hodec2_as_active(from_bts->ho);
+ if (!ho_active && !as_active) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR, "Cannot start Handover: Handover and Assignment disabled for this source cell (%s)\n",
+ neighbor_ident_key_name(search_for));
+ return -EINVAL;
+ }
+
+ if (llist_empty(&from_bts->local_neighbors)
+ && !neighbor_ident_bts_entry_exists(from_bts->nr)) {
+ /* No explicit neighbor entries exist for this BTS. Hence apply the legacy default behavior that all
+ * local cells are neighbors. */
+ struct gsm_bts *bts;
+ struct gsm_bts *wildcard_match = NULL;
+
+ LOG_HO(conn, LOGL_DEBUG, "No explicit neighbors, regarding all local cells as neighbors\n");
+
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ struct neighbor_ident_key bts_key = *bts_ident_key(bts);
+ if (neighbor_ident_key_match(&bts_key, search_for, true)) {
+ if (local_target_cell) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR,
+ "NEIGHBOR CONFIGURATION ERROR: Multiple local cells match %s"
+ " (BTS %d and BTS %d)."
+ " Aborting Handover because of ambiguous network topology.\n",
+ neighbor_ident_key_name(search_for),
+ local_target_cell->nr, bts->nr);
+ return -EINVAL;
+ }
+ local_target_cell = bts;
}
- found = bts;
+ if (neighbor_ident_key_match(&bts_key, search_for, false))
+ wildcard_match = bts;
+ }
+
+ if (!local_target_cell)
+ local_target_cell = wildcard_match;
+
+ if (!local_target_cell) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR, "Cannot Handover, no cell matches %s\n",
+ neighbor_ident_key_name(search_for));
+ return -EINVAL;
+ }
+
+ if (local_target_cell == from_bts && !as_active) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR,
+ "Cannot start re-assignment, Assignment disabled for this cell (%s)\n",
+ neighbor_ident_key_name(search_for));
+ return -EINVAL;
+ }
+ if (local_target_cell != from_bts && !ho_active) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR,
+ "Cannot start Handover, Handover disabled for this cell (%s)\n",
+ neighbor_ident_key_name(search_for));
+ return -EINVAL;
+ }
+
+ if (local_target_cell_p)
+ *local_target_cell_p = local_target_cell;
+ return 0;
+ }
+
+ /* One or more local- or remote-BSS cell neighbors are configured. Find a match among those, but also detect
+ * ambiguous matches (if multiple cells match, it is a configuration error). */
+
+ LOG_HO(conn, LOGL_DEBUG, "There are explicit neighbors configured for this cell\n");
+
+ /* Iterate explicit local neighbor cells */
+ llist_for_each_entry(neigh, &from_bts->local_neighbors, entry) {
+ struct gsm_bts *neigh_bts = neigh->bts;
+ struct neighbor_ident_key neigh_bts_key = *bts_ident_key(neigh_bts);
+ neigh_bts_key.from_bts = from_bts->nr;
+
+ LOG_HO(conn, LOGL_DEBUG, "Local neighbor %s\n", neighbor_ident_key_name(&neigh_bts_key));
+
+ if (!neighbor_ident_key_match(&neigh_bts_key, search_for, true)) {
+ LOG_HO(conn, LOGL_DEBUG, "Doesn't match %s\n", neighbor_ident_key_name(search_for));
+ continue;
}
- if (neighbor_ident_key_match(&entry, search_for, false))
- wildcard_match = bts;
+
+ if (local_target_cell) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR,
+ "NEIGHBOR CONFIGURATION ERROR: Multiple BTS match %s (BTS %d and BTS %d)."
+ " Aborting Handover because of ambiguous network topology.\n",
+ neighbor_ident_key_name(search_for), local_target_cell->nr, neigh_bts->nr);
+ return -EINVAL;
+ }
+
+ local_target_cell = neigh_bts;
+ }
+
+ /* Any matching remote-BSS neighbor cell? */
+ remote_target_cell = neighbor_ident_get(net->neighbor_bss_cells, search_for);
+
+ if (remote_target_cell)
+ LOG_HO(conn, LOGL_DEBUG, "Found remote target cell %s\n",
+ gsm0808_cell_id_list_name(remote_target_cell));
+
+ if (local_target_cell && remote_target_cell) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR, "NEIGHBOR CONFIGURATION ERROR: Both a local and a remote-BSS cell match %s"
+ " (BTS %d and remote %s)."
+ " Aborting Handover because of ambiguous network topology.\n",
+ neighbor_ident_key_name(search_for), local_target_cell->nr,
+ gsm0808_cell_id_list_name(remote_target_cell));
+ return -EINVAL;
+ }
+
+ if (local_target_cell == from_bts && !as_active) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR,
+ "Cannot start re-assignment, Assignment disabled for this cell (%s)\n",
+ neighbor_ident_key_name(search_for));
+ return -EINVAL;
+ }
+
+ if (((local_target_cell && local_target_cell != from_bts)
+ || remote_target_cell)
+ && !ho_active) {
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR,
+ "Cannot start Handover, Handover disabled for this cell (%s)\n",
+ neighbor_ident_key_name(search_for));
+ return -EINVAL;
+ }
+
+ if (local_target_cell) {
+ if (local_target_cell_p)
+ *local_target_cell_p = local_target_cell;
+ return 0;
+ }
+
+ if (remote_target_cell) {
+ if (remote_target_cell_p)
+ *remote_target_cell_p = remote_target_cell;
+ return 0;
}
- if (found)
- return found;
+ if (log_errors)
+ LOG_HO(conn, LOGL_ERROR, "Cannot handover %s: neighbor unknown\n",
+ neighbor_ident_key_name(search_for));
- return wildcard_match;
+ return -ENODEV;
}
struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts)
{
static struct neighbor_ident_key key;
key = (struct neighbor_ident_key){
+ .from_bts = NEIGHBOR_IDENT_KEY_ANY_BTS,
.arfcn = bts->c0->arfcn,
.bsic = bts->bsic,
};