neighbor vty: identify neighbors by gsm0808 cell id
For deleting neighbor entries and for triggering manual handovers, it is useful to identify neighbors by the gsm0808_cell_id, instead of just by ARFCN+BSIC. This is not a hard requirement, since BTS+ARFCN+BSIC fully identifies a neighbor. But consider these contrived examples of the situation before this patch: # bts 0 # neighbor cgi 001 01 23 42 # no neighbor cgi 001 01 23 42 % No such command # no neighbor bts 5 (manually looked up that BTS 5 has above CGI) # neighbor lac 42 arfcn 23 bsic 5 # do handover any to lac 42 % No such command # do handover any to arfcn 23 bsic 5 (if multiple cells have the same ARFCN+BSIC, the identification is not unique) So this fills a gap, if only to help debugging / analyzing handover operations. Change-Id: I198fe7055d1e09b128693eb51276e3d8cde1c0ba
This commit is contained in:
parent
8d8d710a28
commit
d77bd741c1
|
@ -1152,6 +1152,21 @@ struct gsm_bts *gsm_bts_by_cell_id(const struct gsm_network *net,
|
|||
int gsm_bts_local_neighbor_add(struct gsm_bts *bts, struct gsm_bts *neighbor);
|
||||
int gsm_bts_local_neighbor_del(struct gsm_bts *bts, const struct gsm_bts *neighbor);
|
||||
|
||||
typedef bool (*neighbors_find_by_cell_id_cb_t)(struct gsm_bts *from_bts,
|
||||
struct gsm_bts *neighbor_bts,
|
||||
const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
int val_idx,
|
||||
void *cb_data);
|
||||
int neighbors_find_by_cell_id(struct gsm_network *net,
|
||||
struct gsm_bts *for_bts,
|
||||
struct neighbor_ident_list *neighbor_bss_cells,
|
||||
const struct gsm0808_cell_id *id,
|
||||
bool remote_neighbors_exact_match,
|
||||
bool remote_neighbors_all_matches,
|
||||
neighbors_find_by_cell_id_cb_t cb,
|
||||
void *cb_data);
|
||||
|
||||
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
|
||||
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ osmo_bsc_SOURCES = \
|
|||
mgw_endpoint_fsm.c \
|
||||
neighbor_ident.c \
|
||||
neighbor_ident_vty.c \
|
||||
neighbor_iter.c \
|
||||
net_init.c \
|
||||
gsm_08_08.c \
|
||||
osmo_bsc_bssap.c \
|
||||
|
|
|
@ -86,6 +86,13 @@ bool neighbor_ident_bts_parse_key_params(struct vty *vty, struct gsm_bts *bts, c
|
|||
#define LOCAL_BTS_PARAMS "bts <0-255>"
|
||||
#define LOCAL_BTS_DOC "Neighbor cell by local BTS number\n" "BTS number\n"
|
||||
|
||||
#define SHOW_BTS_PARAMS "show " LOCAL_BTS_PARAMS
|
||||
#define SHOW_BTS_DOC SHOW_STR "Display information about a BTS\n" "BTS number\n"
|
||||
|
||||
#define SHOW_BTS_NEIGHBOR_PARAMS SHOW_BTS_PARAMS " neighbor"
|
||||
#define SHOW_BTS_NEIGHBOR_DOC SHOW_BTS_DOC \
|
||||
"List this cell's neighbors matching the given criteria\n"
|
||||
|
||||
static struct gsm_bts *neighbor_ident_vty_parse_bts_nr(struct vty *vty, const char **argv)
|
||||
{
|
||||
const char *bts_nr_str = argv[0];
|
||||
|
@ -186,7 +193,7 @@ static int add_local_bts(struct vty *vty, struct gsm_bts *neigh)
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int del_local_bts(struct vty *vty, struct gsm_bts *neigh)
|
||||
static int del_local_bts_neighbor(struct vty *vty, struct gsm_bts *neigh)
|
||||
{
|
||||
int rc;
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
@ -211,12 +218,123 @@ static int del_local_bts(struct vty *vty, struct gsm_bts *neigh)
|
|||
neigh->nr, bts->nr, strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
vty_out(vty, "%% BTS %u is no neighbor of BTS %u%s",
|
||||
neigh->nr, bts->nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
vty_out(vty, "%% Removed from BTS %u local neighbor BTS %u%s", bts->nr, neigh->nr, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int del_remote_neighbor(struct vty *vty, const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val)
|
||||
{
|
||||
vty_out(vty, "%% Removing remote neighbor: %s %s%s",
|
||||
neighbor_ident_key_name(key),
|
||||
gsm0808_cell_id_list_name(val),
|
||||
VTY_NEWLINE);
|
||||
if (!neighbor_ident_del(g_neighbor_cells, key)) {
|
||||
vty_out(vty, "%% Error: removing neighbor failed%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct del_local_or_remote_neighbor_iter_data {
|
||||
struct vty *vty;
|
||||
struct gsm_bts *bts;
|
||||
const struct gsm0808_cell_id *id;
|
||||
int count_local;
|
||||
int count_remote;
|
||||
};
|
||||
|
||||
static bool del_local_or_remote_neighbor_iter_cb_count(struct gsm_bts *from_bts,
|
||||
struct gsm_bts *neighbor_bts,
|
||||
const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
int val_idx,
|
||||
void *cb_data)
|
||||
{
|
||||
struct del_local_or_remote_neighbor_iter_data *d = cb_data;
|
||||
if (neighbor_bts)
|
||||
d->count_local++;
|
||||
else
|
||||
d->count_remote++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool del_local_or_remote_neighbor_iter_cb_list(struct gsm_bts *from_bts,
|
||||
struct gsm_bts *neighbor_bts,
|
||||
const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
int val_idx,
|
||||
void *cb_data)
|
||||
{
|
||||
struct del_local_or_remote_neighbor_iter_data *d = cb_data;
|
||||
struct vty *vty = d->vty;
|
||||
if (neighbor_bts)
|
||||
vty_out(vty, "%% BTS %u has local neighbor BTS %u%s",
|
||||
d->bts->nr, neighbor_bts->nr, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, "%% Remote neighbor %s %s%s",
|
||||
neighbor_ident_key_name(key),
|
||||
gsm0808_cell_id_list_name(val), VTY_NEWLINE);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool del_local_or_remote_neighbor_iter_cb_del(struct gsm_bts *from_bts,
|
||||
struct gsm_bts *neighbor_bts,
|
||||
const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
int val_idx,
|
||||
void *cb_data)
|
||||
{
|
||||
struct del_local_or_remote_neighbor_iter_data *d = cb_data;
|
||||
|
||||
if (neighbor_bts)
|
||||
del_local_bts_neighbor(d->vty, neighbor_bts);
|
||||
else
|
||||
del_remote_neighbor(d->vty, key, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int del_local_or_remote_neighbor(struct vty *vty, const struct gsm0808_cell_id *id,
|
||||
bool allow_multiple_matches)
|
||||
{
|
||||
struct del_local_or_remote_neighbor_iter_data d = {
|
||||
.vty = vty,
|
||||
.bts = vty->index,
|
||||
.id = id,
|
||||
};
|
||||
int total;
|
||||
|
||||
if (vty->node != BTS_NODE)
|
||||
d.bts = NULL;
|
||||
|
||||
neighbors_find_by_cell_id(g_net, d.bts, g_neighbor_cells, id, true, true,
|
||||
del_local_or_remote_neighbor_iter_cb_count, &d);
|
||||
|
||||
total = d.count_local + d.count_remote;
|
||||
if (!total) {
|
||||
vty_out(vty, "%% No matching neighbor%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (total > 1 && !allow_multiple_matches) {
|
||||
vty_out(vty, "%% More than one match found:%s", VTY_NEWLINE);
|
||||
neighbors_find_by_cell_id(g_net, d.bts, g_neighbor_cells, id, true, true,
|
||||
del_local_or_remote_neighbor_iter_cb_list,
|
||||
&d);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
total = neighbors_find_by_cell_id(g_net, d.bts, g_neighbor_cells, id, true, true,
|
||||
del_local_or_remote_neighbor_iter_cb_del, &d);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN(cfg_neighbor_add_bts_nr, cfg_neighbor_add_bts_nr_cmd,
|
||||
NEIGHBOR_ADD_CMD LOCAL_BTS_PARAMS,
|
||||
NEIGHBOR_ADD_DOC LOCAL_BTS_DOC)
|
||||
|
@ -352,7 +470,7 @@ static int del_by_key(struct vty *vty, const struct neighbor_ident_key *key)
|
|||
continue;
|
||||
rc = gsm_bts_local_neighbor_del(bts, neigh->bts);
|
||||
if (rc > 0) {
|
||||
vty_out(vty, "%% Removed local neighbor bts %u to bts %u%s",
|
||||
vty_out(vty, "%% Removed from BTS %u local neighbor BTS %u%s",
|
||||
bts->nr, neigh_bts->nr, VTY_NEWLINE);
|
||||
removed += rc;
|
||||
}
|
||||
|
@ -415,7 +533,7 @@ DEFUN(cfg_neighbor_del_bts_nr, cfg_neighbor_del_bts_nr_cmd,
|
|||
NEIGHBOR_DEL_CMD LOCAL_BTS_PARAMS,
|
||||
NEIGHBOR_DEL_DOC LOCAL_BTS_DOC)
|
||||
{
|
||||
return del_local_bts(vty, neighbor_ident_vty_parse_bts_nr(vty, argv));
|
||||
return del_local_bts_neighbor(vty, neighbor_ident_vty_parse_bts_nr(vty, argv));
|
||||
}
|
||||
|
||||
DEFUN(cfg_neighbor_del_arfcn_bsic, cfg_neighbor_del_arfcn_bsic_cmd,
|
||||
|
@ -430,12 +548,76 @@ DEFUN(cfg_neighbor_del_arfcn_bsic, cfg_neighbor_del_arfcn_bsic_cmd,
|
|||
return del_by_key(vty, &key);
|
||||
}
|
||||
|
||||
DEFUN(cfg_neighbor_del_lac, cfg_neighbor_del_lac_cmd,
|
||||
NEIGHBOR_DEL_CMD LAC_PARAMS,
|
||||
NEIGHBOR_DEL_DOC LAC_DOC)
|
||||
{
|
||||
return del_local_or_remote_neighbor(vty, neighbor_ident_vty_parse_lac(vty, argv), false);
|
||||
}
|
||||
|
||||
DEFUN(cfg_neighbor_del_lac_ci, cfg_neighbor_del_lac_ci_cmd,
|
||||
NEIGHBOR_DEL_CMD LAC_CI_PARAMS,
|
||||
NEIGHBOR_DEL_DOC LAC_CI_DOC)
|
||||
{
|
||||
return del_local_or_remote_neighbor(vty, neighbor_ident_vty_parse_lac(vty, argv), false);
|
||||
}
|
||||
|
||||
DEFUN(cfg_neighbor_del_cgi, cfg_neighbor_del_cgi_cmd,
|
||||
NEIGHBOR_DEL_CMD CGI_PARAMS,
|
||||
NEIGHBOR_DEL_DOC CGI_DOC)
|
||||
{
|
||||
return del_local_or_remote_neighbor(vty, neighbor_ident_vty_parse_lac(vty, argv), false);
|
||||
}
|
||||
|
||||
|
||||
struct write_neighbor_ident_entry_data {
|
||||
struct vty *vty;
|
||||
const char *indent;
|
||||
struct gsm_bts *bts;
|
||||
};
|
||||
|
||||
static void write_neighbor_ident_list_entry(struct vty *vty,
|
||||
const char *indent,
|
||||
const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
int idx)
|
||||
{
|
||||
if (idx >= val->id_list_len)
|
||||
return;
|
||||
|
||||
#define NEIGH_BSS_WRITE(fmt, args...) do { \
|
||||
vty_out(vty, "%sneighbor " fmt " arfcn %u ", indent, ## args, key->arfcn); \
|
||||
if (key->bsic == BSIC_ANY) \
|
||||
vty_out(vty, "bsic any"); \
|
||||
else \
|
||||
vty_out(vty, "bsic %u", key->bsic & 0x3f); \
|
||||
vty_out(vty, "%s", VTY_NEWLINE); \
|
||||
} while(0)
|
||||
|
||||
switch (val->id_discr) {
|
||||
case CELL_IDENT_LAC:
|
||||
NEIGH_BSS_WRITE("lac %u", val->id_list[idx].lac);
|
||||
break;
|
||||
case CELL_IDENT_LAC_AND_CI:
|
||||
NEIGH_BSS_WRITE("lac-ci %u %u",
|
||||
val->id_list[idx].lac_and_ci.lac,
|
||||
val->id_list[idx].lac_and_ci.ci);
|
||||
break;
|
||||
case CELL_IDENT_WHOLE_GLOBAL:
|
||||
{
|
||||
const struct osmo_cell_global_id *cgi = &val->id_list[idx].global;
|
||||
NEIGH_BSS_WRITE("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 type: %d%s", val->id_discr, VTY_NEWLINE);
|
||||
}
|
||||
#undef NEIGH_BSS_WRITE
|
||||
}
|
||||
|
||||
static bool write_neighbor_ident_list(const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
void *cb_data)
|
||||
|
@ -450,42 +632,9 @@ static bool write_neighbor_ident_list(const struct neighbor_ident_key *key,
|
|||
} else if (key->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS)
|
||||
return true;
|
||||
|
||||
#define NEIGH_BSS_WRITE(fmt, args...) do { \
|
||||
vty_out(vty, "%sneighbor " fmt " arfcn %u ", d->indent, ## args, key->arfcn); \
|
||||
if (key->bsic == BSIC_ANY) \
|
||||
vty_out(vty, "bsic any"); \
|
||||
else \
|
||||
vty_out(vty, "bsic %u", key->bsic & 0x3f); \
|
||||
vty_out(vty, "%s", VTY_NEWLINE); \
|
||||
} while(0)
|
||||
|
||||
switch (val->id_discr) {
|
||||
case CELL_IDENT_LAC:
|
||||
for (i = 0; i < val->id_list_len; i++) {
|
||||
NEIGH_BSS_WRITE("lac %u", val->id_list[i].lac);
|
||||
}
|
||||
break;
|
||||
case CELL_IDENT_LAC_AND_CI:
|
||||
for (i = 0; i < val->id_list_len; i++) {
|
||||
NEIGH_BSS_WRITE("lac-ci %u %u",
|
||||
val->id_list[i].lac_and_ci.lac,
|
||||
val->id_list[i].lac_and_ci.ci);
|
||||
}
|
||||
break;
|
||||
case CELL_IDENT_WHOLE_GLOBAL:
|
||||
for (i = 0; i < val->id_list_len; i++) {
|
||||
const struct osmo_cell_global_id *cgi = &val->id_list[i].global;
|
||||
NEIGH_BSS_WRITE("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);
|
||||
for (i = 0; i < val->id_list_len; i++) {
|
||||
write_neighbor_ident_list_entry(vty, d->indent, key, val, i);
|
||||
}
|
||||
#undef NEIGH_BSS_WRITE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -500,12 +649,17 @@ void neighbor_ident_vty_write_remote_bss(struct vty *vty, const char *indent, st
|
|||
neighbor_ident_iter(g_neighbor_cells, write_neighbor_ident_list, &d);
|
||||
}
|
||||
|
||||
void neighbor_ident_vty_write_local_neighbor(struct vty *vty, const char *indent, struct gsm_bts *neighbor_bts)
|
||||
{
|
||||
vty_out(vty, "%sneighbor bts %u%s", indent, neighbor_bts->nr, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
void neighbor_ident_vty_write_local_neighbors(struct vty *vty, const char *indent, struct gsm_bts *bts)
|
||||
{
|
||||
struct gsm_bts_ref *neigh;
|
||||
|
||||
llist_for_each_entry(neigh, &bts->local_neighbors, entry) {
|
||||
vty_out(vty, "%sneighbor bts %u%s", indent, neigh->bts->nr, VTY_NEWLINE);
|
||||
neighbor_ident_vty_write_local_neighbor(vty, indent, neigh->bts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,11 +669,25 @@ void neighbor_ident_vty_write(struct vty *vty, const char *indent, struct gsm_bt
|
|||
neighbor_ident_vty_write_remote_bss(vty, indent, bts);
|
||||
}
|
||||
|
||||
DEFUN(show_bts_neighbor, show_bts_neighbor_cmd,
|
||||
"show bts <0-255> neighbor " NEIGHBOR_IDENT_VTY_KEY_PARAMS,
|
||||
SHOW_STR "Display information about a BTS\n" "BTS number\n"
|
||||
"Query which cell would be the target for this neighbor ARFCN+BSIC\n"
|
||||
NEIGHBOR_IDENT_VTY_KEY_DOC)
|
||||
DEFUN(show_bts_neighbor_all, show_bts_neighbor_all_cmd,
|
||||
SHOW_BTS_NEIGHBOR_PARAMS " all",
|
||||
SHOW_BTS_NEIGHBOR_DOC "List all neighbors\n")
|
||||
{
|
||||
struct gsm_bts *bts = gsm_bts_num(g_net, atoi(argv[0]));
|
||||
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% Error: cannot find BTS '%s'%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
neighbor_ident_vty_write(vty, "% ", bts);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_bts_neighbor_arfcn, show_bts_neighbor_arfcn_cmd,
|
||||
SHOW_BTS_NEIGHBOR_PARAMS " " NEIGHBOR_IDENT_VTY_KEY_PARAMS,
|
||||
SHOW_BTS_NEIGHBOR_DOC NEIGHBOR_IDENT_VTY_KEY_DOC)
|
||||
{
|
||||
int found = 0;
|
||||
struct neighbor_ident_key key;
|
||||
|
@ -563,6 +731,57 @@ DEFUN(show_bts_neighbor, show_bts_neighbor_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static bool show_neighbor_by_cell_id_cb(struct gsm_bts *from_bts,
|
||||
struct gsm_bts *neighbor_bts,
|
||||
const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
int val_idx,
|
||||
void *cb_data)
|
||||
{
|
||||
struct vty *vty = cb_data;
|
||||
if (neighbor_bts)
|
||||
neighbor_ident_vty_write_local_neighbor(vty, "% ", neighbor_bts);
|
||||
else
|
||||
write_neighbor_ident_list_entry(vty, "% ", key, val, val_idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int show_neighbor_by_cell_id(struct vty *vty, const char **argv, const struct gsm0808_cell_id *id)
|
||||
{
|
||||
struct gsm_bts *bts = gsm_bts_num(g_net, atoi(argv[0]));
|
||||
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% Error: cannot find BTS '%s'%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
neighbors_find_by_cell_id(g_net, bts, g_neighbor_cells, id, false, true,
|
||||
show_neighbor_by_cell_id_cb, vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_bts_neighbor_lac, show_bts_neighbor_lac_cmd,
|
||||
SHOW_BTS_NEIGHBOR_PARAMS " " LAC_PARAMS,
|
||||
SHOW_BTS_NEIGHBOR_DOC LAC_DOC)
|
||||
{
|
||||
return show_neighbor_by_cell_id(vty, argv, neighbor_ident_vty_parse_lac(vty, &argv[1]));
|
||||
}
|
||||
|
||||
DEFUN(show_bts_neighbor_lac_ci, show_bts_neighbor_lac_ci_cmd,
|
||||
SHOW_BTS_NEIGHBOR_PARAMS " " LAC_CI_PARAMS,
|
||||
SHOW_BTS_NEIGHBOR_DOC LAC_CI_DOC)
|
||||
{
|
||||
return show_neighbor_by_cell_id(vty, argv, neighbor_ident_vty_parse_lac_ci(vty, &argv[1]));
|
||||
}
|
||||
|
||||
DEFUN(show_bts_neighbor_cgi, show_bts_neighbor_cgi_cmd,
|
||||
SHOW_BTS_NEIGHBOR_PARAMS " " CGI_PARAMS,
|
||||
SHOW_BTS_NEIGHBOR_DOC CGI_DOC)
|
||||
{
|
||||
return show_neighbor_by_cell_id(vty, argv, neighbor_ident_vty_parse_cgi(vty, &argv[1]));
|
||||
}
|
||||
|
||||
void neighbor_ident_vty_init(struct gsm_network *net, struct neighbor_ident_list *nil)
|
||||
{
|
||||
g_net = net;
|
||||
|
@ -576,5 +795,12 @@ void neighbor_ident_vty_init(struct gsm_network *net, struct neighbor_ident_list
|
|||
install_element(BTS_NODE, &cfg_neighbor_add_cgi_arfcn_bsic_cmd);
|
||||
install_element(BTS_NODE, &cfg_neighbor_del_bts_nr_cmd);
|
||||
install_element(BTS_NODE, &cfg_neighbor_del_arfcn_bsic_cmd);
|
||||
install_element_ve(&show_bts_neighbor_cmd);
|
||||
install_element(BTS_NODE, &cfg_neighbor_del_lac_cmd);
|
||||
install_element(BTS_NODE, &cfg_neighbor_del_lac_ci_cmd);
|
||||
install_element(BTS_NODE, &cfg_neighbor_del_cgi_cmd);
|
||||
install_element_ve(&show_bts_neighbor_all_cmd);
|
||||
install_element_ve(&show_bts_neighbor_arfcn_cmd);
|
||||
install_element_ve(&show_bts_neighbor_lac_cmd);
|
||||
install_element_ve(&show_bts_neighbor_lac_ci_cmd);
|
||||
install_element_ve(&show_bts_neighbor_cgi_cmd);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/* Copyright (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Neels Hofmeyr <neels@hofmeyr.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This file implements iteration of both local and remote neighbors, which has dependencies to both
|
||||
* gsm_data.c as well as neighbor_ident.c. Placing this in gsm_data.c would require various tools to
|
||||
* include the neighbor_ident.c implementations. In turn, neighbor_ident.c is gsm_data.c agnostic. */
|
||||
|
||||
#include <osmocom/bsc/gsm_data.h>
|
||||
#include <osmocom/bsc/neighbor_ident.h>
|
||||
|
||||
static int bts_local_neighbors_find_by_cell_id(struct gsm_bts *for_bts,
|
||||
const struct gsm0808_cell_id *id,
|
||||
neighbors_find_by_cell_id_cb_t cb,
|
||||
void *cb_data)
|
||||
{
|
||||
int count = 0;
|
||||
struct gsm_bts_ref *ref, *ref_next;
|
||||
llist_for_each_entry_safe(ref, ref_next, &for_bts->local_neighbors, entry) {
|
||||
if (!id || gsm_bts_matches_cell_id(ref->bts, id)) {
|
||||
if (cb)
|
||||
cb(for_bts, ref->bts, NULL, NULL, -1, cb_data);
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int all_local_neighbors_find_by_cell_id(struct gsm_network *net,
|
||||
const struct gsm0808_cell_id *id,
|
||||
neighbors_find_by_cell_id_cb_t cb,
|
||||
void *cb_data)
|
||||
{
|
||||
struct gsm_bts *bts, *bts_next;
|
||||
int count = 0;
|
||||
llist_for_each_entry_safe(bts, bts_next, &net->bts_list, list) {
|
||||
count += bts_local_neighbors_find_by_cell_id(bts, id, cb, cb_data);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
struct neighbors_find_by_cell_id_iter_cb_data {
|
||||
struct gsm_network *net;
|
||||
const struct gsm0808_cell_id *id;
|
||||
bool all_matches;
|
||||
neighbors_find_by_cell_id_cb_t cb;
|
||||
void *cb_data;
|
||||
int count;
|
||||
};
|
||||
|
||||
static bool neighbors_find_by_cell_id_iter_cb(const struct neighbor_ident_key *key,
|
||||
const struct gsm0808_cell_id_list2 *val,
|
||||
void *cb_data)
|
||||
{
|
||||
struct neighbors_find_by_cell_id_iter_cb_data *d = cb_data;
|
||||
unsigned int match_nr;
|
||||
int match_idx;
|
||||
|
||||
for (match_nr = 0; ; match_nr ++) {
|
||||
/* On mismatch, just continue iterating. */
|
||||
match_idx = gsm0808_cell_id_matches_list(d->id, val, match_nr);
|
||||
if (match_idx < 0)
|
||||
return true;
|
||||
|
||||
/* Match! */
|
||||
if (d->cb)
|
||||
d->cb(d->net ? gsm_bts_num(d->net, key->from_bts) : NULL,
|
||||
NULL,
|
||||
key, val,
|
||||
match_idx,
|
||||
d->cb_data);
|
||||
d->count ++;
|
||||
|
||||
/* If neighbors_find_by_cell_id() was invoked with remote_neighbors_all_matches == false,
|
||||
* stop looking after the first match in this list. */
|
||||
if (!d->all_matches)
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Find all neighbors that match a given Cell Identifier.
|
||||
* If 'for_bts' is given, only neighbors for that cell are returned; NULL matches all cells' neighbors.
|
||||
* If 'neighbor_bss_cells' is NULL, no remote neighbors are returned.
|
||||
* If 'id' is NULL, all neighbors are returned. The id restricts the matches, where a CGI type is most
|
||||
* restrictive, and a LAC type might still match a neighbor with LAC+CI or a neighbor with full CGI that
|
||||
* contains this LAC.
|
||||
* Results are returned by calling the cb(). If cb() returns false, further iteration is stopped.
|
||||
* It is safe to remove any neighbor entries, except the neighbor entry *following* the one passed to
|
||||
* cb(), i.e. you may remove the neighbor passed to cb(), but not the adjacent following llist entry.
|
||||
*
|
||||
* With remote_neighbors_exact_match == true, ignore remote-BSS neighbors with a cell id list that have a
|
||||
* CELL_IDENT that differs from the id->id_discr. With false, any matching cell id item counts, e.g. a
|
||||
* LAC of 23 matches a CGI that contains a LAC = 23.
|
||||
*
|
||||
* With remote_neighbors_all_matches == false, return only the first match in each cell id list of a
|
||||
* remote neighbor. With true, cb() will be invoked for each matching val_idx in the given cell id list.
|
||||
*/
|
||||
int neighbors_find_by_cell_id(struct gsm_network *net,
|
||||
struct gsm_bts *for_bts,
|
||||
struct neighbor_ident_list *neighbor_bss_cells,
|
||||
const struct gsm0808_cell_id *id,
|
||||
bool remote_neighbors_exact_match,
|
||||
bool remote_neighbors_all_matches,
|
||||
neighbors_find_by_cell_id_cb_t cb,
|
||||
void *cb_data)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
/* Local neighbors */
|
||||
if (for_bts) {
|
||||
count += bts_local_neighbors_find_by_cell_id(for_bts, id, cb, cb_data);
|
||||
if (!net)
|
||||
net = for_bts->network;
|
||||
} else if (net)
|
||||
count += all_local_neighbors_find_by_cell_id(net, id, cb, cb_data);
|
||||
|
||||
/* Remote neighbors */
|
||||
if (neighbor_bss_cells) {
|
||||
struct neighbors_find_by_cell_id_iter_cb_data d = {
|
||||
.net = net,
|
||||
.id = id,
|
||||
.all_matches = remote_neighbors_all_matches,
|
||||
.cb = cb,
|
||||
.cb_data = cb_data,
|
||||
};
|
||||
|
||||
neighbor_ident_iter(neighbor_bss_cells,
|
||||
neighbors_find_by_cell_id_iter_cb,
|
||||
&d);
|
||||
count += d.count;
|
||||
}
|
||||
return count;
|
||||
}
|
|
@ -162,8 +162,11 @@ OsmoBSC(config-net-bts)# no neighbor?
|
|||
neighbor Remove local or remote-BSS neighbor cell
|
||||
|
||||
OsmoBSC(config-net-bts)# no neighbor ?
|
||||
bts Neighbor cell by local BTS number
|
||||
arfcn ARFCN of neighbor cell
|
||||
bts Neighbor cell by local BTS number
|
||||
arfcn ARFCN of neighbor cell
|
||||
lac Neighbor cell by LAC
|
||||
lac-ci Neighbor cell by LAC and CI
|
||||
cgi Neighbor cell by cgi
|
||||
|
||||
OsmoBSC(config-net-bts)# no neighbor bts ?
|
||||
<0-255> BTS number
|
||||
|
@ -195,10 +198,31 @@ OsmoBSC(config-net-bts)# show running-config
|
|||
|
||||
OsmoBSC(config-net-bts)# neighbor bts 1
|
||||
% BTS 0 now has local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11
|
||||
OsmoBSC(config-net-bts)# no neighbor bts 1
|
||||
% Removed from BTS 0 local neighbor BTS 1
|
||||
|
||||
OsmoBSC(config-net-bts)# neighbor lac 21
|
||||
% BTS 0 now has local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11
|
||||
OsmoBSC(config-net-bts)# no neighbor lac 21
|
||||
% Removed from BTS 0 local neighbor BTS 1
|
||||
|
||||
OsmoBSC(config-net-bts)# neighbor lac-ci 21 31
|
||||
% BTS 0 now has local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11
|
||||
OsmoBSC(config-net-bts)# no neighbor lac-ci 21 31
|
||||
% Removed from BTS 0 local neighbor BTS 1
|
||||
|
||||
OsmoBSC(config-net-bts)# neighbor cgi 901 70 21 31
|
||||
% BTS 0 now has local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11
|
||||
OsmoBSC(config-net-bts)# no neighbor cgi 901 70 21 31
|
||||
% No matching neighbor
|
||||
|
||||
OsmoBSC(config-net-bts)# neighbor bts 1
|
||||
% BTS 0 already had local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11
|
||||
|
||||
OsmoBSC(config-net-bts)# neighbor lac 22
|
||||
% BTS 0 now has local neighbor BTS 2 with LAC 22 CI 65535 and ARFCN 42 BSIC 12
|
||||
OsmoBSC(config-net-bts)# no neighbor bts 2
|
||||
% Removed from BTS 0 local neighbor BTS 2
|
||||
OsmoBSC(config-net-bts)# neighbor cgi 901 70 22 65535
|
||||
% BTS 0 now has local neighbor BTS 2 with LAC 22 CI 65535 and ARFCN 42 BSIC 12
|
||||
|
||||
|
@ -260,6 +284,40 @@ OsmoBSC(config-net-bts)# do show bts 0 neighbor arfcn 423 bsic 1
|
|||
OsmoBSC(config-net-bts)# do show bts 0 neighbor arfcn 423 bsic 23
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 23
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor all
|
||||
% neighbor bts 1
|
||||
% neighbor bts 2
|
||||
% neighbor cgi 023 42 423 5 arfcn 23 bsic 42
|
||||
% neighbor cgi 023 042 423 6 arfcn 23 bsic 42
|
||||
% neighbor cgi 023 042 234 56 arfcn 23 bsic 42
|
||||
% neighbor lac 456 arfcn 123 bsic 45
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic any
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 63
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 1
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor cgi 23 42 423 5
|
||||
% neighbor cgi 023 42 423 5 arfcn 23 bsic 42
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor lac 456
|
||||
% neighbor lac 456 arfcn 123 bsic 45
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor lac-ci 789 10
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic any
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 63
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 1
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor lac 789
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic any
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 63
|
||||
% neighbor lac-ci 789 10 arfcn 423 bsic 1
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor lac 423
|
||||
% neighbor cgi 023 42 423 5 arfcn 23 bsic 42
|
||||
% neighbor cgi 023 042 423 6 arfcn 23 bsic 42
|
||||
|
||||
OsmoBSC(config-net-bts)# do show bts 0 neighbor lac-ci 423 6
|
||||
% neighbor cgi 023 042 423 6 arfcn 23 bsic 42
|
||||
|
||||
OsmoBSC(config-net-bts)# no neighbor arfcn 99 bsic 7
|
||||
% Cannot remove, no such neighbor: BTS 0 to ARFCN 99 BSIC 7
|
||||
|
||||
|
@ -312,7 +370,7 @@ OsmoBSC(config-net-bts)# show running-config
|
|||
... !neighbor
|
||||
|
||||
OsmoBSC(config-net-bts)# no neighbor arfcn 41 bsic any
|
||||
% Removed local neighbor bts 0 to bts 1
|
||||
% Removed from BTS 0 local neighbor BTS 1
|
||||
|
||||
OsmoBSC(config-net-bts)# show running-config
|
||||
... !neighbor
|
||||
|
@ -328,7 +386,7 @@ OsmoBSC(config-net-bts)# show running-config
|
|||
... !neighbor
|
||||
|
||||
OsmoBSC(config-net-bts)# no neighbor arfcn 42 bsic 12
|
||||
% Removed local neighbor bts 0 to bts 2
|
||||
% Removed from BTS 0 local neighbor BTS 2
|
||||
|
||||
OsmoBSC(config-net-bts)# show running-config
|
||||
... !neighbor
|
||||
|
|
Loading…
Reference in New Issue