osmo-bsc/src/osmo-bsc/handover_decision.c

344 lines
9.1 KiB
C
Raw Normal View History

/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This
* only implements the handover algorithm/decision, but not execution
* of it */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* 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 <errno.h>
#include <osmocom/core/msgb.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/meas_rep.h>
#include <osmocom/bsc/signal.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/gsm_utils.h>
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
#include <osmocom/bsc/handover.h>
#include <osmocom/bsc/handover_cfg.h>
/* Find BTS by ARFCN and BSIC */
struct gsm_bts *bts_by_arfcn_bsic(const struct gsm_network *net,
uint16_t arfcn, uint8_t bsic)
mscsplit: various preparations to separate MSC from BSC Disable large parts of the code that depend on BSC presence. The code sections disabled by #if BEFORE_MSCSPLIT shall be modified or dropped in the course of adding the A-interface. Don't set msg->lchan nor msg->dst. Don't use lchan in libmsc. Decouple lac from bts. Prepare entry/exit point for MSC -> BSC and MSC -> RNC communication: Add msc_ifaces.[hc], a_iface.c, with a general msc_tx_dtap() to redirect to different interfaces depending on the actual subscriber connection. While iu_tx() is going to be functional fairly soon, the a_tx() is going to be just a dummy for some time (see comment). Add Iu specific fields in gsm_subscriber_connection: the UE connection pointer and an indicator for the Integrity Protection status on Iu (to be fully implemented in later commits). Add lac member to gsm_subscriber_connection, to allow decoupling from bts->location_area_code. The conn->lac will actually be set in iu.c in an upcoming commit ("add iucs.[hc]"). move to libcommon-cs: gsm48_extract_mi(), gsm48_paging_extract_mi(). libmsc: duplicate gsm0808 / gsm48 functions (towards BSC). In osmo-nitb, libmsc would directly call the functions on the BSC level, not always via the bsc_api. When separating libmsc from libbsc, some functions are missing from the linkage. Hence duplicate these functions to libmsc, add an msc_ prefix for clarity, also add a _tx to gsm0808_cipher_mode(): * add msc_gsm0808_tx_cipher_mode() (dummy/stub) * add msc_gsm48_tx_mm_serv_ack() * add msc_gsm48_tx_mm_serv_rej() Call these from libmsc instead of * gsm0808_cipher_mode() * gsm48_tx_mm_serv_ack() * gsm48_tx_mm_serv_rej() Also add a comment related to msc_gsm0808_tx_cipher_mode() in two places. Remove internal RTP streaming code; OsmoNITB supported that, but for OsmoMSC, this will be done with an external MGCP gateway. Remove LCHAN_MODIFY from internal MNCC state machine. Temporarily disable all paging to be able to link libmsc without libbsc. Skip the paging part of channel_test because the paging is now disabled. Employ fake paging shims in order for msc_vlr_tests to still work. msc_compl_l3(): publish in .h, tweak return value. Use new libmsc enum values for return val, to avoid dependency on libbsc headers. Make callable from other scopes: publish in osmo_msc.h and remove 'static' in osmo_msc.c add gsm_encr to subscr_conn move subscr_request to gsm_subscriber.h subscr_request_channel() -> subscr_request_conn() move to libmsc: osmo_stats_vty_add_cmds() gsm_04_08: remove apply_codec_restrictions() gsm0408_test: use NULL for root ctx move to libbsc: gsm_bts_neighbor() move to libbsc: lchan_next_meas_rep() move vty config for t3212 to network level (periodic lu) remove unneccessary linking from some tests remove handle_abisip_signal() abis_rsl.c: don't use libvlr from libbsc gsm_subscriber_connection: put the LAC here, so that it is available without accessing conn->bts. In bsc_api.c, place this lac in conn for the sake of transition: Iu and A will use this new field to pass the LAC around, but in a completely separate OsmoBSC this is not actually needed. It can be removed again from osmo-bsc.git when the time has come. Siemens MRPCI: completely drop sending the MRPCI messages for now, they shall be added in osmo-bsc once the A-Interface code has settled. See OS#2389. Related: OS#1845 OS#2257 OS#2389 Change-Id: Id3705236350d5f69e447046b0a764bbabc3d493c
2017-05-08 13:12:20 +00:00
{
struct gsm_bts *bts;
mscsplit: various preparations to separate MSC from BSC Disable large parts of the code that depend on BSC presence. The code sections disabled by #if BEFORE_MSCSPLIT shall be modified or dropped in the course of adding the A-interface. Don't set msg->lchan nor msg->dst. Don't use lchan in libmsc. Decouple lac from bts. Prepare entry/exit point for MSC -> BSC and MSC -> RNC communication: Add msc_ifaces.[hc], a_iface.c, with a general msc_tx_dtap() to redirect to different interfaces depending on the actual subscriber connection. While iu_tx() is going to be functional fairly soon, the a_tx() is going to be just a dummy for some time (see comment). Add Iu specific fields in gsm_subscriber_connection: the UE connection pointer and an indicator for the Integrity Protection status on Iu (to be fully implemented in later commits). Add lac member to gsm_subscriber_connection, to allow decoupling from bts->location_area_code. The conn->lac will actually be set in iu.c in an upcoming commit ("add iucs.[hc]"). move to libcommon-cs: gsm48_extract_mi(), gsm48_paging_extract_mi(). libmsc: duplicate gsm0808 / gsm48 functions (towards BSC). In osmo-nitb, libmsc would directly call the functions on the BSC level, not always via the bsc_api. When separating libmsc from libbsc, some functions are missing from the linkage. Hence duplicate these functions to libmsc, add an msc_ prefix for clarity, also add a _tx to gsm0808_cipher_mode(): * add msc_gsm0808_tx_cipher_mode() (dummy/stub) * add msc_gsm48_tx_mm_serv_ack() * add msc_gsm48_tx_mm_serv_rej() Call these from libmsc instead of * gsm0808_cipher_mode() * gsm48_tx_mm_serv_ack() * gsm48_tx_mm_serv_rej() Also add a comment related to msc_gsm0808_tx_cipher_mode() in two places. Remove internal RTP streaming code; OsmoNITB supported that, but for OsmoMSC, this will be done with an external MGCP gateway. Remove LCHAN_MODIFY from internal MNCC state machine. Temporarily disable all paging to be able to link libmsc without libbsc. Skip the paging part of channel_test because the paging is now disabled. Employ fake paging shims in order for msc_vlr_tests to still work. msc_compl_l3(): publish in .h, tweak return value. Use new libmsc enum values for return val, to avoid dependency on libbsc headers. Make callable from other scopes: publish in osmo_msc.h and remove 'static' in osmo_msc.c add gsm_encr to subscr_conn move subscr_request to gsm_subscriber.h subscr_request_channel() -> subscr_request_conn() move to libmsc: osmo_stats_vty_add_cmds() gsm_04_08: remove apply_codec_restrictions() gsm0408_test: use NULL for root ctx move to libbsc: gsm_bts_neighbor() move to libbsc: lchan_next_meas_rep() move vty config for t3212 to network level (periodic lu) remove unneccessary linking from some tests remove handle_abisip_signal() abis_rsl.c: don't use libvlr from libbsc gsm_subscriber_connection: put the LAC here, so that it is available without accessing conn->bts. In bsc_api.c, place this lac in conn for the sake of transition: Iu and A will use this new field to pass the LAC around, but in a completely separate OsmoBSC this is not actually needed. It can be removed again from osmo-bsc.git when the time has come. Siemens MRPCI: completely drop sending the MRPCI messages for now, they shall be added in osmo-bsc once the A-Interface code has settled. See OS#2389. Related: OS#1845 OS#2257 OS#2389 Change-Id: Id3705236350d5f69e447046b0a764bbabc3d493c
2017-05-08 13:12:20 +00:00
llist_for_each_entry(bts, &net->bts_list, list) {
if (bts->c0->arfcn == arfcn &&
bts->bsic == bsic)
return bts;
mscsplit: various preparations to separate MSC from BSC Disable large parts of the code that depend on BSC presence. The code sections disabled by #if BEFORE_MSCSPLIT shall be modified or dropped in the course of adding the A-interface. Don't set msg->lchan nor msg->dst. Don't use lchan in libmsc. Decouple lac from bts. Prepare entry/exit point for MSC -> BSC and MSC -> RNC communication: Add msc_ifaces.[hc], a_iface.c, with a general msc_tx_dtap() to redirect to different interfaces depending on the actual subscriber connection. While iu_tx() is going to be functional fairly soon, the a_tx() is going to be just a dummy for some time (see comment). Add Iu specific fields in gsm_subscriber_connection: the UE connection pointer and an indicator for the Integrity Protection status on Iu (to be fully implemented in later commits). Add lac member to gsm_subscriber_connection, to allow decoupling from bts->location_area_code. The conn->lac will actually be set in iu.c in an upcoming commit ("add iucs.[hc]"). move to libcommon-cs: gsm48_extract_mi(), gsm48_paging_extract_mi(). libmsc: duplicate gsm0808 / gsm48 functions (towards BSC). In osmo-nitb, libmsc would directly call the functions on the BSC level, not always via the bsc_api. When separating libmsc from libbsc, some functions are missing from the linkage. Hence duplicate these functions to libmsc, add an msc_ prefix for clarity, also add a _tx to gsm0808_cipher_mode(): * add msc_gsm0808_tx_cipher_mode() (dummy/stub) * add msc_gsm48_tx_mm_serv_ack() * add msc_gsm48_tx_mm_serv_rej() Call these from libmsc instead of * gsm0808_cipher_mode() * gsm48_tx_mm_serv_ack() * gsm48_tx_mm_serv_rej() Also add a comment related to msc_gsm0808_tx_cipher_mode() in two places. Remove internal RTP streaming code; OsmoNITB supported that, but for OsmoMSC, this will be done with an external MGCP gateway. Remove LCHAN_MODIFY from internal MNCC state machine. Temporarily disable all paging to be able to link libmsc without libbsc. Skip the paging part of channel_test because the paging is now disabled. Employ fake paging shims in order for msc_vlr_tests to still work. msc_compl_l3(): publish in .h, tweak return value. Use new libmsc enum values for return val, to avoid dependency on libbsc headers. Make callable from other scopes: publish in osmo_msc.h and remove 'static' in osmo_msc.c add gsm_encr to subscr_conn move subscr_request to gsm_subscriber.h subscr_request_channel() -> subscr_request_conn() move to libmsc: osmo_stats_vty_add_cmds() gsm_04_08: remove apply_codec_restrictions() gsm0408_test: use NULL for root ctx move to libbsc: gsm_bts_neighbor() move to libbsc: lchan_next_meas_rep() move vty config for t3212 to network level (periodic lu) remove unneccessary linking from some tests remove handle_abisip_signal() abis_rsl.c: don't use libvlr from libbsc gsm_subscriber_connection: put the LAC here, so that it is available without accessing conn->bts. In bsc_api.c, place this lac in conn for the sake of transition: Iu and A will use this new field to pass the LAC around, but in a completely separate OsmoBSC this is not actually needed. It can be removed again from osmo-bsc.git when the time has come. Siemens MRPCI: completely drop sending the MRPCI messages for now, they shall be added in osmo-bsc once the A-Interface code has settled. See OS#2389. Related: OS#1845 OS#2257 OS#2389 Change-Id: Id3705236350d5f69e447046b0a764bbabc3d493c
2017-05-08 13:12:20 +00:00
}
return NULL;
}
/* issue handover to a cell identified by ARFCN and BSIC */
static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
uint16_t arfcn, uint8_t bsic)
{
struct gsm_bts *new_bts;
/* resolve the gsm_bts structure for the best neighbor */
/* FIXME: use some better heuristics here to determine which cell
* using this ARFCN really is closest to the target cell. For
* now we simply assume that each ARFCN will only be used by one
* cell */
new_bts = bts_by_arfcn_bsic(lchan->ts->trx->bts->network, arfcn, bsic);
if (!new_bts) {
LOGP(DHODEC, LOGL_NOTICE, "unable to determine neighbor BTS "
"for ARFCN %u BSIC %u ?!?\n", arfcn, bsic);
return -EINVAL;
}
/* and actually try to handover to that cell */
HO: introduce ho decision callbacks Instead of reacting on S_LCHAN* signals in the handover decision code, introduce callbacks for the handover decision to be invoked by handover_logic.c at the appropriate time. The rationale is explained in a comment to struct handover_decision_callbacks, quoting: " All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals, so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up handover operation state upon receiving some of these signals. To allow a handover decision algorithm to take advantage of e.g. the struct bsc_handover before it is discarded, the handover decision event handler needs to be invoked before handover_logic.c discards the state. For example, if the handover decision wants to place a penalty timer upon a handover failure, it still needs to know which target cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it needs to clean up the lchan's handover state. The most explicit and safest way to ensure the correct order of event handling is to invoke the handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct provides the callback functions for this purpose. For consistency, also handle signals in this way that aren't actually in danger of interference from handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover decision algorithms should not register any signal handler at all. " Also: - Publish struct bsc_handover to use it as argument to above callbacks. - Add enum hodec_id to struct bsc_handover, to be able to signal the appropriate hodec algorithm per event. - Add hodec_id argument to bsc_handover_start*() to be placed in the bsc_handover struct. - Publish the LOGPHO logging macros in handover.h along with struct bsc_handover, convenient for logging in callback implementations. Replace handover_decision.c's signal handler with a registered handover_decision_callbacks instance. (Upcoming handover_decision_2 will use all of the callbacks introduced here.) Change-Id: Id5b64504007fe03e0406a4b395cd0359232b77d2
2018-02-15 13:10:12 +00:00
return bsc_handover_start(HODEC1, lchan, new_bts, lchan->type);
}
/* did we get a RXLEV for a given cell in the given report? */
static int rxlev_for_cell_in_rep(struct gsm_meas_rep *mr,
uint16_t arfcn, uint8_t bsic)
{
int i;
for (i = 0; i < mr->num_cell; i++) {
struct gsm_meas_rep_cell *mrc = &mr->cell[i];
/* search for matching report */
if (!(mrc->arfcn == arfcn && mrc->bsic == bsic))
continue;
mrc->flags |= MRC_F_PROCESSED;
return mrc->rxlev;
}
return -ENODEV;
}
/* obtain averaged rxlev for given neighbor */
static int neigh_meas_avg(struct neigh_meas_proc *nmp, int window)
{
unsigned int i, idx;
int avg = 0;
/* reduce window to the actual number of existing measurements */
if (window > nmp->rxlev_cnt)
window = nmp->rxlev_cnt;
/* this should never happen */
if (window <= 0) {
LOGP(DHODEC, LOGL_ERROR, "Requested Neighbor RxLev for invalid window size of %d\n", window);
return 0;
}
idx = calc_initial_idx(ARRAY_SIZE(nmp->rxlev),
nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev),
window);
for (i = 0; i < window; i++) {
int j = (idx+i) % ARRAY_SIZE(nmp->rxlev);
avg += nmp->rxlev[j];
}
return avg / window;
}
/* find empty or evict bad neighbor */
static struct neigh_meas_proc *find_evict_neigh(struct gsm_lchan *lchan)
{
int j, worst = 999999;
struct neigh_meas_proc *nmp_worst = NULL;
/* first try to find an empty/unused slot */
for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) {
struct neigh_meas_proc *nmp = &lchan->neigh_meas[j];
if (!nmp->arfcn)
return nmp;
}
/* no empty slot found. evict worst neighbor from list */
for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) {
struct neigh_meas_proc *nmp = &lchan->neigh_meas[j];
int avg = neigh_meas_avg(nmp, MAX_WIN_NEIGH_AVG);
if (!nmp_worst || avg < worst) {
worst = avg;
nmp_worst = nmp;
}
}
return nmp_worst;
}
/* process neighbor cell measurement reports */
static void process_meas_neigh(struct gsm_meas_rep *mr)
{
int i, j, idx;
/* for each reported cell, try to update global state */
for (j = 0; j < ARRAY_SIZE(mr->lchan->neigh_meas); j++) {
struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[j];
unsigned int idx;
int rxlev;
/* skip unused entries */
if (!nmp->arfcn)
continue;
rxlev = rxlev_for_cell_in_rep(mr, nmp->arfcn, nmp->bsic);
idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev);
if (rxlev >= 0) {
nmp->rxlev[idx] = rxlev;
nmp->last_seen_nr = mr->nr;
} else
nmp->rxlev[idx] = 0;
nmp->rxlev_cnt++;
}
/* iterate over list of reported cells, check if we did not
* process all of them */
for (i = 0; i < mr->num_cell; i++) {
struct gsm_meas_rep_cell *mrc = &mr->cell[i];
struct neigh_meas_proc *nmp;
if (mrc->flags & MRC_F_PROCESSED)
continue;
nmp = find_evict_neigh(mr->lchan);
nmp->arfcn = mrc->arfcn;
nmp->bsic = mrc->bsic;
nmp->rxlev_cnt = 0;
idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev);
nmp->rxlev[idx] = mrc->rxlev;
nmp->rxlev_cnt++;
nmp->last_seen_nr = mr->nr;
mrc->flags |= MRC_F_PROCESSED;
}
}
/* attempt to do a handover */
static int attempt_handover(struct gsm_meas_rep *mr)
{
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
struct gsm_bts *bts = mr->lchan->ts->trx->bts;
struct neigh_meas_proc *best_cell = NULL;
unsigned int best_better_db = 0;
int i, rc;
/* find the best cell in this report that is at least RXLEV_HYST
* better than the current serving cell */
for (i = 0; i < ARRAY_SIZE(mr->lchan->neigh_meas); i++) {
struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[i];
int avg, better;
/* skip empty slots */
if (nmp->arfcn == 0)
continue;
/* caculate average rxlev for this cell over the window */
HO: cfg: separate hodec1 from hodec2 parameters Do not share config items between the current handover decision and the upcoming handover_decision_2. Rename current handover config items to hodec2_* and duplicate the ones relevant to handover decision algorithm 1 with name prefix of hodec1_*. I considered moving hodec2 parameters to an entirely separate .c file and struct, but that causes considerable code bloat. Rather use the nice handover_cfg net/bts level mechanism as-is, and simply prefix the names. In the VTY, the hodec1 parameters are configurable by 'handover foo 23' commands, while the hodec2 parameters are by 'handover2 foo 23'. The generic VTY commands to enable/disable handover and to choose the algorithm are still 'handover (0|1)' and 'handover algorithm (1|2)'. (Note, a subsequent commit will rename the 'handover foo' for hodec1 to 'handover1 foo' and add backwards-compat aliases.) For example, the 'window rxlev averaging 5' command now exists both for handover decision 1 and handover decision 2, and its values are independent. This is valid config: network # set up handover decision algorithm 1 # (pending rename of these items to 'handover1 ...') handover window rxlev averaging 5 handover window rxlev neighbor averaging 5 # set up handover decision algorithm 2 handover2 window rxlev averaging 7 handover2 window rxlev neighbor averaging 7 handover2 penalty-time max-distance 10 # enable handover handover 1 bts 0 handover algorithm 1 bts 1 handover algorithm 2 In this example, bts 0 uses algo 1 with rxlev averaging of 5, while bts 1 uses algorithm 2 where rxlev averaging of 7 is in effect. Change-Id: I6475b2543b18d21710a6d774b214cb484f36ec8e
2018-02-14 18:56:23 +00:00
avg = neigh_meas_avg(nmp, ho_get_hodec1_rxlev_neigh_avg_win(bts->ho));
/* check if hysteresis is fulfilled */
HO: cfg: separate hodec1 from hodec2 parameters Do not share config items between the current handover decision and the upcoming handover_decision_2. Rename current handover config items to hodec2_* and duplicate the ones relevant to handover decision algorithm 1 with name prefix of hodec1_*. I considered moving hodec2 parameters to an entirely separate .c file and struct, but that causes considerable code bloat. Rather use the nice handover_cfg net/bts level mechanism as-is, and simply prefix the names. In the VTY, the hodec1 parameters are configurable by 'handover foo 23' commands, while the hodec2 parameters are by 'handover2 foo 23'. The generic VTY commands to enable/disable handover and to choose the algorithm are still 'handover (0|1)' and 'handover algorithm (1|2)'. (Note, a subsequent commit will rename the 'handover foo' for hodec1 to 'handover1 foo' and add backwards-compat aliases.) For example, the 'window rxlev averaging 5' command now exists both for handover decision 1 and handover decision 2, and its values are independent. This is valid config: network # set up handover decision algorithm 1 # (pending rename of these items to 'handover1 ...') handover window rxlev averaging 5 handover window rxlev neighbor averaging 5 # set up handover decision algorithm 2 handover2 window rxlev averaging 7 handover2 window rxlev neighbor averaging 7 handover2 penalty-time max-distance 10 # enable handover handover 1 bts 0 handover algorithm 1 bts 1 handover algorithm 2 In this example, bts 0 uses algo 1 with rxlev averaging of 5, while bts 1 uses algorithm 2 where rxlev averaging of 7 is in effect. Change-Id: I6475b2543b18d21710a6d774b214cb484f36ec8e
2018-02-14 18:56:23 +00:00
if (avg < mr->dl.full.rx_lev + ho_get_hodec1_pwr_hysteresis(bts->ho))
continue;
better = avg - mr->dl.full.rx_lev;
if (better > best_better_db) {
best_cell = nmp;
best_better_db = better;
}
}
if (!best_cell)
return 0;
LOGP(DHODEC, LOGL_INFO, "%s: Cell on ARFCN %u is better: ",
gsm_ts_name(mr->lchan->ts), best_cell->arfcn);
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
if (!ho_get_ho_active(bts->ho)) {
LOGPC(DHODEC, LOGL_INFO, "Skipping, Handover disabled\n");
return 0;
}
rc = handover_to_arfcn_bsic(mr->lchan, best_cell->arfcn, best_cell->bsic);
switch (rc) {
case 0:
LOGPC(DHODEC, LOGL_INFO, "Starting handover: meas report number %d \n", mr->nr);
break;
case -ENOSPC:
LOGPC(DHODEC, LOGL_INFO, "No channel available\n");
break;
case -EBUSY:
LOGPC(DHODEC, LOGL_INFO, "Handover already active\n");
break;
default:
LOGPC(DHODEC, LOGL_ERROR, "Unknown error\n");
}
return rc;
}
/* process an already parsed measurement report and decide if we want to
* attempt a handover */
HO: introduce ho decision callbacks Instead of reacting on S_LCHAN* signals in the handover decision code, introduce callbacks for the handover decision to be invoked by handover_logic.c at the appropriate time. The rationale is explained in a comment to struct handover_decision_callbacks, quoting: " All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals, so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up handover operation state upon receiving some of these signals. To allow a handover decision algorithm to take advantage of e.g. the struct bsc_handover before it is discarded, the handover decision event handler needs to be invoked before handover_logic.c discards the state. For example, if the handover decision wants to place a penalty timer upon a handover failure, it still needs to know which target cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it needs to clean up the lchan's handover state. The most explicit and safest way to ensure the correct order of event handling is to invoke the handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct provides the callback functions for this purpose. For consistency, also handle signals in this way that aren't actually in danger of interference from handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover decision algorithms should not register any signal handler at all. " Also: - Publish struct bsc_handover to use it as argument to above callbacks. - Add enum hodec_id to struct bsc_handover, to be able to signal the appropriate hodec algorithm per event. - Add hodec_id argument to bsc_handover_start*() to be placed in the bsc_handover struct. - Publish the LOGPHO logging macros in handover.h along with struct bsc_handover, convenient for logging in callback implementations. Replace handover_decision.c's signal handler with a registered handover_decision_callbacks instance. (Upcoming handover_decision_2 will use all of the callbacks introduced here.) Change-Id: Id5b64504007fe03e0406a4b395cd0359232b77d2
2018-02-15 13:10:12 +00:00
static void on_measurement_report(struct gsm_meas_rep *mr)
{
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
struct gsm_bts *bts = mr->lchan->ts->trx->bts;
enum meas_rep_field dlev, dqual;
int av_rxlev;
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
unsigned int pwr_interval;
/* If this cell does not use handover algorithm 1, then we're not responsible. */
if (ho_get_algorithm(bts->ho) != 1)
return;
/* we currently only do handover for TCH channels */
switch (mr->lchan->type) {
case GSM_LCHAN_TCH_F:
case GSM_LCHAN_TCH_H:
break;
default:
return;
}
if (mr->flags & MEAS_REP_F_DL_DTX) {
dlev = MEAS_REP_DL_RXLEV_SUB;
dqual = MEAS_REP_DL_RXQUAL_SUB;
} else {
dlev = MEAS_REP_DL_RXLEV_FULL;
dqual = MEAS_REP_DL_RXQUAL_FULL;
}
/* parse actual neighbor cell info */
if (mr->num_cell > 0 && mr->num_cell < 7)
process_meas_neigh(mr);
av_rxlev = get_meas_rep_avg(mr->lchan, dlev,
HO: cfg: separate hodec1 from hodec2 parameters Do not share config items between the current handover decision and the upcoming handover_decision_2. Rename current handover config items to hodec2_* and duplicate the ones relevant to handover decision algorithm 1 with name prefix of hodec1_*. I considered moving hodec2 parameters to an entirely separate .c file and struct, but that causes considerable code bloat. Rather use the nice handover_cfg net/bts level mechanism as-is, and simply prefix the names. In the VTY, the hodec1 parameters are configurable by 'handover foo 23' commands, while the hodec2 parameters are by 'handover2 foo 23'. The generic VTY commands to enable/disable handover and to choose the algorithm are still 'handover (0|1)' and 'handover algorithm (1|2)'. (Note, a subsequent commit will rename the 'handover foo' for hodec1 to 'handover1 foo' and add backwards-compat aliases.) For example, the 'window rxlev averaging 5' command now exists both for handover decision 1 and handover decision 2, and its values are independent. This is valid config: network # set up handover decision algorithm 1 # (pending rename of these items to 'handover1 ...') handover window rxlev averaging 5 handover window rxlev neighbor averaging 5 # set up handover decision algorithm 2 handover2 window rxlev averaging 7 handover2 window rxlev neighbor averaging 7 handover2 penalty-time max-distance 10 # enable handover handover 1 bts 0 handover algorithm 1 bts 1 handover algorithm 2 In this example, bts 0 uses algo 1 with rxlev averaging of 5, while bts 1 uses algorithm 2 where rxlev averaging of 7 is in effect. Change-Id: I6475b2543b18d21710a6d774b214cb484f36ec8e
2018-02-14 18:56:23 +00:00
ho_get_hodec1_rxlev_avg_win(bts->ho));
/* Interference HO */
if (rxlev2dbm(av_rxlev) > -85 &&
meas_rep_n_out_of_m_be(mr->lchan, dqual, 3, 4, 5)) {
LOGPC(DHO, LOGL_INFO, "HO cause: Interference HO av_rxlev=%d dBm\n",
rxlev2dbm(av_rxlev));
attempt_handover(mr);
return;
}
/* Bad Quality */
if (meas_rep_n_out_of_m_be(mr->lchan, dqual, 3, 4, 5)) {
LOGPC(DHO, LOGL_INFO, "HO cause: Bad Quality av_rxlev=%d dBm\n", rxlev2dbm(av_rxlev));
attempt_handover(mr);
return;
}
/* Low Level */
if (rxlev2dbm(av_rxlev) <= -110) {
LOGPC(DHO, LOGL_INFO, "HO cause: Low Level av_rxlev=%d dBm\n", rxlev2dbm(av_rxlev));
attempt_handover(mr);
return;
}
/* Distance */
HO: cfg: separate hodec1 from hodec2 parameters Do not share config items between the current handover decision and the upcoming handover_decision_2. Rename current handover config items to hodec2_* and duplicate the ones relevant to handover decision algorithm 1 with name prefix of hodec1_*. I considered moving hodec2 parameters to an entirely separate .c file and struct, but that causes considerable code bloat. Rather use the nice handover_cfg net/bts level mechanism as-is, and simply prefix the names. In the VTY, the hodec1 parameters are configurable by 'handover foo 23' commands, while the hodec2 parameters are by 'handover2 foo 23'. The generic VTY commands to enable/disable handover and to choose the algorithm are still 'handover (0|1)' and 'handover algorithm (1|2)'. (Note, a subsequent commit will rename the 'handover foo' for hodec1 to 'handover1 foo' and add backwards-compat aliases.) For example, the 'window rxlev averaging 5' command now exists both for handover decision 1 and handover decision 2, and its values are independent. This is valid config: network # set up handover decision algorithm 1 # (pending rename of these items to 'handover1 ...') handover window rxlev averaging 5 handover window rxlev neighbor averaging 5 # set up handover decision algorithm 2 handover2 window rxlev averaging 7 handover2 window rxlev neighbor averaging 7 handover2 penalty-time max-distance 10 # enable handover handover 1 bts 0 handover algorithm 1 bts 1 handover algorithm 2 In this example, bts 0 uses algo 1 with rxlev averaging of 5, while bts 1 uses algorithm 2 where rxlev averaging of 7 is in effect. Change-Id: I6475b2543b18d21710a6d774b214cb484f36ec8e
2018-02-14 18:56:23 +00:00
if (mr->ms_l1.ta > ho_get_hodec1_max_distance(bts->ho)) {
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
LOGPC(DHO, LOGL_INFO, "HO cause: Distance av_rxlev=%d dBm ta=%d \n",
rxlev2dbm(av_rxlev), mr->ms_l1.ta);
attempt_handover(mr);
return;
}
/* Power Budget AKA Better Cell */
HO: cfg: separate hodec1 from hodec2 parameters Do not share config items between the current handover decision and the upcoming handover_decision_2. Rename current handover config items to hodec2_* and duplicate the ones relevant to handover decision algorithm 1 with name prefix of hodec1_*. I considered moving hodec2 parameters to an entirely separate .c file and struct, but that causes considerable code bloat. Rather use the nice handover_cfg net/bts level mechanism as-is, and simply prefix the names. In the VTY, the hodec1 parameters are configurable by 'handover foo 23' commands, while the hodec2 parameters are by 'handover2 foo 23'. The generic VTY commands to enable/disable handover and to choose the algorithm are still 'handover (0|1)' and 'handover algorithm (1|2)'. (Note, a subsequent commit will rename the 'handover foo' for hodec1 to 'handover1 foo' and add backwards-compat aliases.) For example, the 'window rxlev averaging 5' command now exists both for handover decision 1 and handover decision 2, and its values are independent. This is valid config: network # set up handover decision algorithm 1 # (pending rename of these items to 'handover1 ...') handover window rxlev averaging 5 handover window rxlev neighbor averaging 5 # set up handover decision algorithm 2 handover2 window rxlev averaging 7 handover2 window rxlev neighbor averaging 7 handover2 penalty-time max-distance 10 # enable handover handover 1 bts 0 handover algorithm 1 bts 1 handover algorithm 2 In this example, bts 0 uses algo 1 with rxlev averaging of 5, while bts 1 uses algorithm 2 where rxlev averaging of 7 is in effect. Change-Id: I6475b2543b18d21710a6d774b214cb484f36ec8e
2018-02-14 18:56:23 +00:00
pwr_interval = ho_get_hodec1_pwr_interval(bts->ho);
/* handover_cfg.h defines pwr_interval as [1..99], but since we're using it in a modulo below,
* assert non-zero to clarify. */
OSMO_ASSERT(pwr_interval);
HO prep: introduce per-BTS handover config, with defaults on net node It is desirable to allow configuring handover for each individual network cell. At the same time, it is desirable to set global defaults. Treat the 'network' node handover parameters as global defaults, add another set of parameters for each individual BTS. This raises questions on how the 'network' node should affect the individual BTS. The simplistic solution would have been: on creating a BTS in the config, just copy the current defaults; with serious drawbacks: - tweaking any parameter in the telnet VTY on network node will never affect any running BTS. - network node defaults *must* be issued before the bts sections in the config file. - when writing a config back to file, we would copy all net node defaults to each BTS node, making the network node configs pointless. Instead, add a handover_cfg API that tracks whether a given node has a value set or not. A bts node ho_cfg gets a pointer to the network node config and returns those values if locally unset. If no value is set on any node, use the "factory" defaults, which are hardcoded in the API. Only write back exactly those config items that were actually issued in a config file / on the telnet VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if we so desire in the future.) Implement ho parameters as an opaque config struct with getters and setters to ensure the tracking is always heeded. Opaqueness dictates allocating instead of direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts. This is 100% backwards compatible to old configs. - No VTY command syntax changes (only the online help). - If a 'bts' sets nothing, it will use the 'network' defaults. - The 'show network' output only changes in presence of individual BTS configs. On 'show network', say "Handover: On|Off" as before, iff all BTS reflect identical behavior. Otherwise, output BTS counts of handover being enabled or not. Use the same set of VTY commands (same VTY cmd syntax as before) on network and BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure out which ho_cfg to modify. For linking, add handover_cfg.c (the value API) in libcommon, while the handover_vty.c is in libbsc. This is mainly because some utility programs use gsm_network and hence suck in the ho stuff, but don't need the VTY commands. Review the VTY online help strings. Add VTY transcript test for handover options, testing config propagation from network to bts nodes, 'show network' output and VTY online help strings. (Needs recent addition of '... !' wildcard to osmo_interact_common.py.) I considered leaving parts of this more readable, but in the end decided for heavy use of macros to define and declare the API, because more values will be added in upcoming patches and I want to prevent myself from messing them up. Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests) Change-Id: I79d35f6d3c0fbee67904378ad7f216df34fde79a
2017-11-27 20:29:33 +00:00
if ((mr->nr % pwr_interval) == pwr_interval - 1)
attempt_handover(mr);
}
HO: introduce ho decision callbacks Instead of reacting on S_LCHAN* signals in the handover decision code, introduce callbacks for the handover decision to be invoked by handover_logic.c at the appropriate time. The rationale is explained in a comment to struct handover_decision_callbacks, quoting: " All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals, so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up handover operation state upon receiving some of these signals. To allow a handover decision algorithm to take advantage of e.g. the struct bsc_handover before it is discarded, the handover decision event handler needs to be invoked before handover_logic.c discards the state. For example, if the handover decision wants to place a penalty timer upon a handover failure, it still needs to know which target cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it needs to clean up the lchan's handover state. The most explicit and safest way to ensure the correct order of event handling is to invoke the handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct provides the callback functions for this purpose. For consistency, also handle signals in this way that aren't actually in danger of interference from handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover decision algorithms should not register any signal handler at all. " Also: - Publish struct bsc_handover to use it as argument to above callbacks. - Add enum hodec_id to struct bsc_handover, to be able to signal the appropriate hodec algorithm per event. - Add hodec_id argument to bsc_handover_start*() to be placed in the bsc_handover struct. - Publish the LOGPHO logging macros in handover.h along with struct bsc_handover, convenient for logging in callback implementations. Replace handover_decision.c's signal handler with a registered handover_decision_callbacks instance. (Upcoming handover_decision_2 will use all of the callbacks introduced here.) Change-Id: Id5b64504007fe03e0406a4b395cd0359232b77d2
2018-02-15 13:10:12 +00:00
struct handover_decision_callbacks hodec1_callbacks = {
.hodec_id = HODEC1,
.on_measurement_report = on_measurement_report,
};
void handover_decision_1_init(void)
{
HO: introduce ho decision callbacks Instead of reacting on S_LCHAN* signals in the handover decision code, introduce callbacks for the handover decision to be invoked by handover_logic.c at the appropriate time. The rationale is explained in a comment to struct handover_decision_callbacks, quoting: " All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals, so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up handover operation state upon receiving some of these signals. To allow a handover decision algorithm to take advantage of e.g. the struct bsc_handover before it is discarded, the handover decision event handler needs to be invoked before handover_logic.c discards the state. For example, if the handover decision wants to place a penalty timer upon a handover failure, it still needs to know which target cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it needs to clean up the lchan's handover state. The most explicit and safest way to ensure the correct order of event handling is to invoke the handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct provides the callback functions for this purpose. For consistency, also handle signals in this way that aren't actually in danger of interference from handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover decision algorithms should not register any signal handler at all. " Also: - Publish struct bsc_handover to use it as argument to above callbacks. - Add enum hodec_id to struct bsc_handover, to be able to signal the appropriate hodec algorithm per event. - Add hodec_id argument to bsc_handover_start*() to be placed in the bsc_handover struct. - Publish the LOGPHO logging macros in handover.h along with struct bsc_handover, convenient for logging in callback implementations. Replace handover_decision.c's signal handler with a registered handover_decision_callbacks instance. (Upcoming handover_decision_2 will use all of the callbacks introduced here.) Change-Id: Id5b64504007fe03e0406a4b395cd0359232b77d2
2018-02-15 13:10:12 +00:00
handover_decision_callbacks_register(&hodec1_callbacks);
}