2009-12-16 23:31:10 +00:00
|
|
|
/* 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
|
2011-01-01 14:25:50 +00:00
|
|
|
* 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
|
2009-12-16 23:31:10 +00:00
|
|
|
* (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
|
2011-01-01 14:25:50 +00:00
|
|
|
* GNU Affero General Public License for more details.
|
2009-12-16 23:31:10 +00:00
|
|
|
*
|
2011-01-01 14:25:50 +00:00
|
|
|
* 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/>.
|
2009-12-16 23:31:10 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2011-03-22 15:47:59 +00:00
|
|
|
#include <osmocom/core/msgb.h>
|
2017-09-04 13:15:32 +00:00
|
|
|
#include <osmocom/bsc/debug.h>
|
|
|
|
#include <osmocom/bsc/gsm_data.h>
|
|
|
|
#include <osmocom/bsc/meas_rep.h>
|
|
|
|
#include <osmocom/bsc/signal.h>
|
2011-03-22 15:47:59 +00:00
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/gsm/gsm_utils.h>
|
2009-12-16 23:31:10 +00:00
|
|
|
|
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>
|
|
|
|
|
2018-01-08 14:44:56 +00:00
|
|
|
/* Find BTS by ARFCN and BSIC */
|
2018-01-08 15:52:37 +00:00
|
|
|
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
|
|
|
{
|
2018-01-08 14:44:56 +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
|
|
|
|
2018-01-08 14:44:56 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
/* issue handover to a cell identified by ARFCN and BSIC */
|
2009-12-16 23:31:10 +00:00
|
|
|
static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
|
2011-04-18 15:04:00 +00:00
|
|
|
uint16_t arfcn, uint8_t bsic)
|
2009-12-16 23:31:10 +00:00
|
|
|
{
|
|
|
|
struct gsm_bts *new_bts;
|
|
|
|
|
|
|
|
/* resolve the gsm_bts structure for the best neighbor */
|
2018-01-08 14:44:56 +00:00
|
|
|
/* 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);
|
2009-12-16 23:31:10 +00:00
|
|
|
if (!new_bts) {
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGP(DHODEC, LOGL_NOTICE, "unable to determine neighbor BTS "
|
2009-12-17 22:10:46 +00:00
|
|
|
"for ARFCN %u BSIC %u ?!?\n", arfcn, bsic);
|
2009-12-16 23:31:10 +00:00
|
|
|
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);
|
2009-12-16 23:31:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
/* 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,
|
2011-04-18 15:04:00 +00:00
|
|
|
uint16_t arfcn, uint8_t bsic)
|
2009-12-16 23:31:10 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
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;
|
2009-12-18 10:49:20 +00:00
|
|
|
}
|
2009-12-21 12:30:17 +00:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
2009-12-18 10:49:20 +00:00
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
/* 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;
|
2009-12-16 23:31:10 +00:00
|
|
|
|
2013-06-01 15:00:59 +00:00
|
|
|
/* reduce window to the actual number of existing measurements */
|
2017-12-05 00:03:39 +00:00
|
|
|
if (window > nmp->rxlev_cnt)
|
2013-06-01 15:00:59 +00:00
|
|
|
window = nmp->rxlev_cnt;
|
|
|
|
/* this should never happen */
|
2017-12-05 00:01:38 +00:00
|
|
|
if (window <= 0) {
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGP(DHODEC, LOGL_ERROR, "Requested Neighbor RxLev for invalid window size of %d\n", window);
|
2013-06-01 15:00:59 +00:00
|
|
|
return 0;
|
2017-12-05 00:01:38 +00:00
|
|
|
}
|
2013-06-01 15:00:59 +00:00
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
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;
|
2011-04-18 15:16:56 +00:00
|
|
|
struct neigh_meas_proc *nmp_worst = NULL;
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* 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);
|
2011-04-18 15:16:56 +00:00
|
|
|
if (!nmp_worst || avg < worst) {
|
2009-12-21 12:30:17 +00:00
|
|
|
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;
|
|
|
|
|
2013-06-01 15:00:59 +00:00
|
|
|
nmp->rxlev_cnt = 0;
|
2009-12-21 12:30:17 +00:00
|
|
|
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;
|
2009-12-21 12:30:17 +00:00
|
|
|
struct neigh_meas_proc *best_cell = NULL;
|
|
|
|
unsigned int best_better_db = 0;
|
|
|
|
int i, rc;
|
2009-12-19 20:29:19 +00:00
|
|
|
|
2009-12-16 23:31:10 +00:00
|
|
|
/* find the best cell in this report that is at least RXLEV_HYST
|
|
|
|
* better than the current serving cell */
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
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)
|
2009-12-16 23:31:10 +00:00
|
|
|
continue;
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
/* caculate average rxlev for this cell over the window */
|
2018-02-14 18:56:23 +00:00
|
|
|
avg = neigh_meas_avg(nmp, ho_get_hodec1_rxlev_neigh_avg_win(bts->ho));
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* check if hysteresis is fulfilled */
|
2018-02-14 18:56:23 +00:00
|
|
|
if (avg < mr->dl.full.rx_lev + ho_get_hodec1_pwr_hysteresis(bts->ho))
|
2009-12-21 12:30:17 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
better = avg - mr->dl.full.rx_lev;
|
2009-12-16 23:31:10 +00:00
|
|
|
if (better > best_better_db) {
|
2009-12-21 12:30:17 +00:00
|
|
|
best_cell = nmp;
|
2009-12-16 23:31:10 +00:00
|
|
|
best_better_db = better;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
if (!best_cell)
|
2009-12-19 20:41:52 +00:00
|
|
|
return 0;
|
2009-12-16 23:31:10 +00:00
|
|
|
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGP(DHODEC, LOGL_INFO, "%s: Cell on ARFCN %u is better: ",
|
2009-12-21 12:30:17 +00:00
|
|
|
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)) {
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGPC(DHODEC, LOGL_INFO, "Skipping, Handover disabled\n");
|
2009-12-19 20:41:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
rc = handover_to_arfcn_bsic(mr->lchan, best_cell->arfcn, best_cell->bsic);
|
|
|
|
switch (rc) {
|
|
|
|
case 0:
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGPC(DHODEC, LOGL_INFO, "Starting handover: meas report number %d \n", mr->nr);
|
2009-12-21 12:30:17 +00:00
|
|
|
break;
|
|
|
|
case -ENOSPC:
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGPC(DHODEC, LOGL_INFO, "No channel available\n");
|
2009-12-21 12:30:17 +00:00
|
|
|
break;
|
|
|
|
case -EBUSY:
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGPC(DHODEC, LOGL_INFO, "Handover already active\n");
|
2009-12-21 12:30:17 +00:00
|
|
|
break;
|
|
|
|
default:
|
2013-07-07 07:12:17 +00:00
|
|
|
LOGPC(DHODEC, LOGL_ERROR, "Unknown error\n");
|
2009-12-21 12:30:17 +00:00
|
|
|
}
|
|
|
|
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)
|
2009-12-21 12:30:17 +00:00
|
|
|
{
|
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;
|
2016-05-17 13:56:49 +00:00
|
|
|
enum meas_rep_field dlev, dqual;
|
2009-12-21 12:30:17 +00:00
|
|
|
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;
|
2009-12-21 12:30:17 +00:00
|
|
|
|
2017-12-07 00:55:58 +00:00
|
|
|
/* If this cell does not use handover algorithm 1, then we're not responsible. */
|
|
|
|
if (ho_get_algorithm(bts->ho) != 1)
|
2018-02-15 13:12:40 +00:00
|
|
|
return;
|
2017-12-07 00:55:58 +00:00
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
/* we currently only do handover for TCH channels */
|
|
|
|
switch (mr->lchan->type) {
|
|
|
|
case GSM_LCHAN_TCH_F:
|
|
|
|
case GSM_LCHAN_TCH_H:
|
|
|
|
break;
|
|
|
|
default:
|
2018-02-15 13:12:40 +00:00
|
|
|
return;
|
2009-12-21 12:30:17 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 13:56:49 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-12-21 12:30:17 +00:00
|
|
|
/* parse actual neighbor cell info */
|
|
|
|
if (mr->num_cell > 0 && mr->num_cell < 7)
|
|
|
|
process_meas_neigh(mr);
|
|
|
|
|
2016-05-17 13:56:49 +00:00
|
|
|
av_rxlev = get_meas_rep_avg(mr->lchan, dlev,
|
2018-02-14 18:56:23 +00:00
|
|
|
ho_get_hodec1_rxlev_avg_win(bts->ho));
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* Interference HO */
|
|
|
|
if (rxlev2dbm(av_rxlev) > -85 &&
|
2017-08-23 14:51:22 +00:00
|
|
|
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));
|
2018-02-15 13:12:40 +00:00
|
|
|
attempt_handover(mr);
|
|
|
|
return;
|
2017-08-23 14:51:22 +00:00
|
|
|
}
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* Bad Quality */
|
2017-08-23 14:51:22 +00:00
|
|
|
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));
|
2018-02-15 13:12:40 +00:00
|
|
|
attempt_handover(mr);
|
|
|
|
return;
|
2017-08-23 14:51:22 +00:00
|
|
|
}
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* Low Level */
|
2017-08-23 14:51:22 +00:00
|
|
|
if (rxlev2dbm(av_rxlev) <= -110) {
|
|
|
|
LOGPC(DHO, LOGL_INFO, "HO cause: Low Level av_rxlev=%d dBm\n", rxlev2dbm(av_rxlev));
|
2018-02-15 13:12:40 +00:00
|
|
|
attempt_handover(mr);
|
|
|
|
return;
|
2017-08-23 14:51:22 +00:00
|
|
|
}
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* Distance */
|
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);
|
2018-02-15 13:12:40 +00:00
|
|
|
attempt_handover(mr);
|
|
|
|
return;
|
2017-08-23 14:51:22 +00:00
|
|
|
}
|
2009-12-21 12:30:17 +00:00
|
|
|
|
|
|
|
/* Power Budget AKA Better Cell */
|
2018-02-14 18:56:23 +00:00
|
|
|
pwr_interval = ho_get_hodec1_pwr_interval(bts->ho);
|
2018-02-12 20:16:44 +00:00
|
|
|
/* 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)
|
2018-02-15 13:12:40 +00:00
|
|
|
attempt_handover(mr);
|
2009-12-16 23:31:10 +00:00
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
};
|
2009-12-16 23:31:10 +00:00
|
|
|
|
2017-12-07 00:57:01 +00:00
|
|
|
void handover_decision_1_init(void)
|
2009-12-16 23:31:10 +00:00
|
|
|
{
|
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);
|
2009-12-16 23:31:10 +00:00
|
|
|
}
|