From 6321015c6cd78a2e63f2c9246df98f43a734ee54 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 30 May 2013 13:40:18 +0200 Subject: HO: Add new configuration parameters to VTY and data structure of BTS --- include/osmocom/bsc/gsm_data.h | 4 + include/osmocom/bsc/gsm_data_shared.h | 43 +++++- src/libbsc/bsc_vty.c | 264 ++++++++++++++++++++++++++++++---- src/libbsc/handover_decision.c | 2 +- src/libcommon/gsm_data_shared.c | 12 +- 5 files changed, 286 insertions(+), 39 deletions(-) diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index de31e37a9..8ec08ecb0 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -263,6 +263,10 @@ struct gsm_network { /* control interface */ struct ctrl_handle *ctrl; + + /* congestion check timer */ + int ho_congest_timeout; + struct osmo_timer_list ho_congest_timer; }; struct osmo_esme; diff --git a/include/osmocom/bsc/gsm_data_shared.h b/include/osmocom/bsc/gsm_data_shared.h index 0639c81e0..2d8562092 100644 --- a/include/osmocom/bsc/gsm_data_shared.h +++ b/include/osmocom/bsc/gsm_data_shared.h @@ -721,22 +721,51 @@ struct gsm_bts { struct amr_multirate_conf mr_full; struct amr_multirate_conf mr_half; - /* handover config */ + /* handover/assignment config */ struct { - int active; + /* enable handover for this cell */ + int ho_active; + /* enable assignment for this cell */ + int as_active; + + /* use FULL instead of SUB measurements */ + int8_t full; + /* minimum RXLEV before forcing handover */ + int8_t min_rxlev; /* dBm */ /* Window RXLEV averaging */ unsigned int win_rxlev_avg; /* number of SACCH frames */ - /* Window RXQUAL averaging */ - unsigned int win_rxqual_avg; /* number of SACCH frames */ /* Window RXLEV neighbouring cells averaging */ unsigned int win_rxlev_avg_neigh; /* number of SACCH frames */ - - /* how often should we check for power budget HO */ - unsigned int pwr_interval; /* SACCH frames */ /* how much better does a neighbor cell have to be ? */ unsigned int pwr_hysteresis; /* dBm */ + /* how often should we check for power budget HO */ + unsigned int pwr_interval; /* SACCH frames */ + /* how mucht improvement of RXLEV do we get when using AFS */ + int8_t afs_rxlev_improve; /* dB */ + + /* minimum RXQUAL before forcing handover */ + int8_t min_rxqual; /* dB */ + /* Window RXQUAL averaging */ + unsigned int win_rxqual_avg; /* number of SACCH frames */ + /* how mucht improvement of RXQUAL do we get when using AFS */ + int8_t afs_rxqual_improve; /* dB */ + /* maximum distacne before we try a handover */ unsigned int max_distance; /* TA values */ + + /* minimum number of free TCH/F slots trying to maintain */ + unsigned int min_free_tchf; + /* minimum number of free TCH/H slots trying to maintain */ + unsigned int min_free_tchh; + /* maximum number of unsynchronized handovers at a time */ + unsigned int max_unsync_ho; + + /* penalty time for a cell that exceed maximum distance */ + unsigned int penalty_max_dist; /* seconds */ + /* penalty time for a cell after handover failure */ + unsigned int penalty_ho_fail; /* seconds */ + /* penalty time for a cell after assignment failure */ + unsigned int penalty_as_fail; /* seconds */ } handover; #endif /* ROLE_BSC */ void *role; diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c index 8fbe7e502..d9b8cebef 100644 --- a/src/libbsc/bsc_vty.c +++ b/src/libbsc/bsc_vty.c @@ -299,7 +299,9 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); e1isl_dump_vty(vty, bts->oml_link); } - vty_out(vty, " Handover: %s%s", bts->handover.active ? "On" : "Off", + vty_out(vty, " Handover: %s%s", bts->handover.ho_active ? "On" : "Off", + VTY_NEWLINE); + vty_out(vty, " Assignment: %s%s", bts->handover.as_active ? "On" : "Off", VTY_NEWLINE); /* FIXME: chan_desc */ @@ -711,19 +713,44 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, "auto%s", VTY_NEWLINE); } - vty_out(vty, " handover %u%s", bts->handover.active, VTY_NEWLINE); + vty_out(vty, " handover enable handover %u%s", + bts->handover.ho_active, VTY_NEWLINE); + vty_out(vty, " handover enable assignment %u%s", + bts->handover.as_active, VTY_NEWLINE); + vty_out(vty, " handover set %s%s", + (bts->handover.full) ? "full" : "sub", VTY_NEWLINE); + vty_out(vty, " handover min rxlev %d%s", + bts->handover.min_rxlev, VTY_NEWLINE); vty_out(vty, " handover window rxlev averaging %u%s", bts->handover.win_rxlev_avg, VTY_NEWLINE); - vty_out(vty, " handover window rxqual averaging %u%s", - bts->handover.win_rxqual_avg, VTY_NEWLINE); vty_out(vty, " handover window rxlev neighbor averaging %u%s", bts->handover.win_rxlev_avg_neigh, VTY_NEWLINE); - vty_out(vty, " handover power budget interval %u%s", - bts->handover.pwr_interval, VTY_NEWLINE); vty_out(vty, " handover power budget hysteresis %u%s", bts->handover.pwr_hysteresis, VTY_NEWLINE); + vty_out(vty, " handover power budget interval %u%s", + bts->handover.pwr_interval, VTY_NEWLINE); + vty_out(vty, " handover afs rxlev improvement %u%s", + bts->handover.afs_rxlev_improve, VTY_NEWLINE); + vty_out(vty, " handover min rxqual %u%s", + bts->handover.min_rxqual, VTY_NEWLINE); + vty_out(vty, " handover window rxqual averaging %u%s", + bts->handover.win_rxqual_avg, VTY_NEWLINE); + vty_out(vty, " handover afs rxqual improvement %u%s", + bts->handover.afs_rxqual_improve, VTY_NEWLINE); vty_out(vty, " handover maximum distance %u%s", bts->handover.max_distance, VTY_NEWLINE); + vty_out(vty, " handover min free tch-f %u%s", + bts->handover.min_free_tchf, VTY_NEWLINE); + vty_out(vty, " handover min free tch-h %u%s", + bts->handover.min_free_tchh, VTY_NEWLINE); + vty_out(vty, " handover max unsync handovers %u%s", + bts->handover.max_unsync_ho, VTY_NEWLINE); + vty_out(vty, " handover penalty max distance %u%s", + bts->handover.penalty_max_dist, VTY_NEWLINE); + vty_out(vty, " handover penalty handover failure %u%s", + bts->handover.penalty_ho_fail, VTY_NEWLINE); + vty_out(vty, " handover penalty assignment failure %u%s", + bts->handover.penalty_as_fail, VTY_NEWLINE); config_write_bts_gprs(vty, bts); @@ -781,6 +808,8 @@ static int config_write_net(struct vty *vty) vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE); vty_out(vty, " subscriber-keep-in-ram %d%s", gsmnet->keep_subscr, VTY_NEWLINE); + vty_out(vty, " handover congestion-check-timer %u%s", + gsmnet->ho_congest_timeout, VTY_NEWLINE); return CMD_SUCCESS; } @@ -1462,6 +1491,18 @@ DEFUN(cfg_net_subscr_keep, return CMD_SUCCESS; } +DEFUN(cfg_net_ho_congest_timer, + cfg_net_ho_congest_timer_cmd, + "handover congestion-check-timer <0-60>", + "Global handover settings.\n" + "Handover congestion check timer\n" + "Time in seconds for congestion check interval (0 to disable)\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->ho_congest_timeout = atoi(argv[0]); + return CMD_SUCCESS; +} + /* per-BTS configuration */ DEFUN(cfg_bts, cfg_bts_cmd, @@ -3181,10 +3222,12 @@ DEFUN(cfg_bts_amr_hr_hyst3, cfg_bts_amr_hr_hyst3_cmd, } #define HANDOVER_STR "Handover Options\n" +#define HO_ENABLE_STR HANDOVER_STR "Enable or disable handover/assignment\n" -DEFUN(cfg_bts_handover, cfg_bts_handover_cmd, - "handover (0|1)", - HANDOVER_STR +DEFUN(cfg_bts_ho_handover, cfg_bts_ho_handover_cmd, + "handover enable handover (0|1)", + HO_ENABLE_STR + "Enable or disable handover\n" "Don't perform in-call handover\n" "Perform in-call handover\n") { @@ -3197,17 +3240,66 @@ DEFUN(cfg_bts_handover, cfg_bts_handover_cmd, VTY_NEWLINE); return CMD_WARNING; } - bts->handover.active = enable; + bts->handover.ho_active = enable; + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_assignment, cfg_bts_ho_assignment_cmd, + "handover enable assignment (0|1)", + HO_ENABLE_STR + "Enable or disable assignment\n" + "Don't perform in-call assignment\n" + "Perform in-call assignment\n") +{ + int enable = atoi(argv[0]); + struct gsm_bts *bts = vty->index; + + if (enable && ipacc_rtp_direct) { + vty_out(vty, "%% Cannot enable assignment unless RTP Proxy mode " + "is enabled by using the -P command line option%s", + VTY_NEWLINE); + return CMD_WARNING; + } + bts->handover.as_active = enable; + + return CMD_SUCCESS; +} +DEFUN(cfg_bts_ho_set, cfg_bts_ho_set_cmd, + "handover set (full|sub)", + HANDOVER_STR + "Define measuement set of TDMA frames\n" + "Full set of 102/104 TDMA frames\n" + "Sub set of 4 TDMA frames (SACCH)") +{ + struct gsm_bts *bts = vty->index; + bts->handover.full = (argv[0][0]=='f'); return CMD_SUCCESS; } +#define HO_MIN_STR HANDOVER_STR "Minimum Values\n" +#define HO_MAX_STR HANDOVER_STR "Maximum Values\n" +#define HO_MIN_FREE_STR HO_MIN_STR "Minimum free Slots\n" #define HO_WIN_STR HANDOVER_STR "Measurement Window\n" #define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n" #define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n" #define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n" +#define HO_AFS_STR HANDOVER_STR "AMR on TCH/F\n" +#define HO_PENALTY_STR HANDOVER_STR "Penalty Time\n" #define HO_AVG_COUNT_STR "Amount to use for Averaging\n" +DEFUN(cfg_bts_ho_min_rxlev, cfg_bts_ho_min_rxlev_cmd, + "handover min rxlev <-110-50>", + HO_MIN_STR + "The minimum RxLev allowed in this cell\n" + "Minimum RxLev in dBm") +{ + struct gsm_bts *bts = vty->index; + bts->handover.min_rxlev = atoi(argv[0]); + return CMD_SUCCESS; +} + DEFUN(cfg_bts_ho_win_rxlev_avg, cfg_bts_ho_win_rxlev_avg_cmd, "handover window rxlev averaging <1-10>", HO_WIN_RXLEV_STR @@ -3219,25 +3311,25 @@ DEFUN(cfg_bts_ho_win_rxlev_avg, cfg_bts_ho_win_rxlev_avg_cmd, return CMD_SUCCESS; } -DEFUN(cfg_bts_ho_win_rxqual_avg, cfg_bts_ho_win_rxqual_avg_cmd, - "handover window rxqual averaging <1-10>", - HO_WIN_RXQUAL_STR +DEFUN(cfg_bts_ho_win_rxlev_neigh_avg, cfg_bts_ho_win_rxlev_avg_neigh_cmd, + "handover window rxlev neighbor averaging <1-10>", + HO_WIN_RXLEV_STR "Neighbor\n" "How many RxQual measurements are used for averaging\n" HO_AVG_COUNT_STR) { struct gsm_bts *bts = vty->index; - bts->handover.win_rxqual_avg = atoi(argv[0]); + bts->handover.win_rxlev_avg_neigh = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_bts_ho_win_rxlev_neigh_avg, cfg_bts_ho_win_rxlev_avg_neigh_cmd, - "handover window rxlev neighbor averaging <1-10>", - HO_WIN_RXLEV_STR "Neighbor\n" - "How many RxQual measurements are used for averaging\n" - HO_AVG_COUNT_STR) +DEFUN(cfg_bts_ho_pwr_hysteresis, cfg_bts_ho_pwr_hysteresis_cmd, + "handover power budget hysteresis <0-999>", + HO_PBUDGET_STR + "How many dB does a neighbor to be stronger to become a HO candidate\n" + "Hysteresis\n" "Number\n") { struct gsm_bts *bts = vty->index; - bts->handover.win_rxlev_avg_neigh = atoi(argv[0]); + bts->handover.pwr_hysteresis = atoi(argv[0]); return CMD_SUCCESS; } @@ -3252,14 +3344,49 @@ DEFUN(cfg_bts_ho_pwr_interval, cfg_bts_ho_pwr_interval_cmd, return CMD_SUCCESS; } -DEFUN(cfg_bts_ho_pwr_hysteresis, cfg_bts_ho_pwr_hysteresis_cmd, - "handover power budget hysteresis <0-999>", - HO_PBUDGET_STR - "How many dB does a neighbor to be stronger to become a HO candidate\n" - "Hysteresis\n" "Number\n") +DEFUN(cfg_bts_ho_afs_rxlev_improve, cfg_bts_ho_afs_rxlev_improve_cmd, + "handover afs rxlev improvement <0-20>", + HO_AFS_STR + "RxLev\n" + "Improvement of RxLev over other codecs\n" + "RxLev in dB") { struct gsm_bts *bts = vty->index; - bts->handover.pwr_hysteresis = atoi(argv[0]); + bts->handover.afs_rxlev_improve = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_min_rxqual, cfg_bts_ho_min_rxqual_cmd, + "handover min rxqual <0-7>", + HO_MIN_STR + "The minimum RxQual allowed in this cell\n" + "Minimum RxQual in dBm") +{ + struct gsm_bts *bts = vty->index; + bts->handover.min_rxqual = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_win_rxqual_avg, cfg_bts_ho_win_rxqual_avg_cmd, + "handover window rxqual averaging <1-10>", + HO_WIN_RXQUAL_STR + "How many RxQual measurements are used for averaging\n" + HO_AVG_COUNT_STR) +{ + struct gsm_bts *bts = vty->index; + bts->handover.win_rxqual_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_afs_rxqual_improve, cfg_bts_ho_afs_rxqual_improve_cmd, + "handover afs rxqual improvement <0-7>", + HO_AFS_STR + "RxQual\n" + "Improvement of RxQual over other codecs\n" + "RxQual in dB") +{ + struct gsm_bts *bts = vty->index; + bts->handover.afs_rxqual_improve = atoi(argv[0]); return CMD_SUCCESS; } @@ -3274,6 +3401,72 @@ DEFUN(cfg_bts_ho_max_distance, cfg_bts_ho_max_distance_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_ho_min_free_tchf, cfg_bts_ho_min_free_tchf_cmd, + "handover min free tch-f <0-9999>", + HO_MIN_FREE_STR + "Minimum free TCH/F timeslots before cell is congeted\n" + "Slots\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.min_free_tchf = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_min_free_tchh, cfg_bts_ho_min_free_tchh_cmd, + "handover min free tch-h <0-9999>", + HO_MIN_FREE_STR + "Minimum free TCH/H timeslots before cell is congeted\n" + "Slots\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.min_free_tchh = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_max_unsync_ho, cfg_bts_ho_max_unsync_ho_cmd, + "handover max unsync handovers <0-9999>", + HO_MAX_STR + "Maximum unsynchronous handovers\n" + "Handovers\nNumber\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.max_unsync_ho = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_penalty_max_dist, cfg_bts_ho_penalty_max_dist_cmd, + "handover penalty max distance <0-99999>", + HO_PENALTY_STR + "After leaving this cell due to exceeding the maximum allowed distance\n" + "Distance\nTime in Seconds\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.penalty_max_dist = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_penalty_ho_fail, cfg_bts_ho_penalty_ho_fail_cmd, + "handover penalty handover failure <0-99999>", + HO_PENALTY_STR + "After handover failure to this cell\n" + "Failure\nTime in Seconds\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.penalty_ho_fail = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_penalty_as_fail, cfg_bts_ho_penalty_as_fail_cmd, + "handover penalty assignment failure <0-99999>", + HO_PENALTY_STR + "After assignment failure in this cell\n" + "Failure\nTime in Seconds\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.penalty_as_fail = atoi(argv[0]); + return CMD_SUCCESS; +} + #define TRX_TEXT "Radio Transceiver\n" /* per TRX configuration */ @@ -3801,6 +3994,7 @@ int bsc_vty_init(const struct log_info *cat) install_element(GSMNET_NODE, &cfg_net_T3141_cmd); install_element(GSMNET_NODE, &cfg_net_dtx_cmd); install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_congest_timer_cmd); install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); @@ -3892,13 +4086,25 @@ int bsc_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_amr_hr_hyst2_cmd); install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd); install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd); - install_element(BTS_NODE, &cfg_bts_handover_cmd); + install_element(BTS_NODE, &cfg_bts_ho_handover_cmd); + install_element(BTS_NODE, &cfg_bts_ho_assignment_cmd); + install_element(BTS_NODE, &cfg_bts_ho_set_cmd); + install_element(BTS_NODE, &cfg_bts_ho_min_rxlev_cmd); install_element(BTS_NODE, &cfg_bts_ho_win_rxlev_avg_cmd); - install_element(BTS_NODE, &cfg_bts_ho_win_rxqual_avg_cmd); install_element(BTS_NODE, &cfg_bts_ho_win_rxlev_avg_neigh_cmd); - install_element(BTS_NODE, &cfg_bts_ho_pwr_interval_cmd); install_element(BTS_NODE, &cfg_bts_ho_pwr_hysteresis_cmd); + install_element(BTS_NODE, &cfg_bts_ho_pwr_interval_cmd); + install_element(BTS_NODE, &cfg_bts_ho_afs_rxlev_improve_cmd); + install_element(BTS_NODE, &cfg_bts_ho_min_rxqual_cmd); + install_element(BTS_NODE, &cfg_bts_ho_win_rxqual_avg_cmd); + install_element(BTS_NODE, &cfg_bts_ho_afs_rxqual_improve_cmd); install_element(BTS_NODE, &cfg_bts_ho_max_distance_cmd); + install_element(BTS_NODE, &cfg_bts_ho_min_free_tchf_cmd); + install_element(BTS_NODE, &cfg_bts_ho_min_free_tchh_cmd); + install_element(BTS_NODE, &cfg_bts_ho_max_unsync_ho_cmd); + install_element(BTS_NODE, &cfg_bts_ho_penalty_max_dist_cmd); + install_element(BTS_NODE, &cfg_bts_ho_penalty_ho_fail_cmd); + install_element(BTS_NODE, &cfg_bts_ho_penalty_as_fail_cmd); install_element(BTS_NODE, &cfg_trx_cmd); install_node(&trx_node, dummy_config_write); diff --git a/src/libbsc/handover_decision.c b/src/libbsc/handover_decision.c index 81e8b6e55..a66354423 100644 --- a/src/libbsc/handover_decision.c +++ b/src/libbsc/handover_decision.c @@ -201,7 +201,7 @@ static int attempt_handover(struct gsm_meas_rep *mr) LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ", gsm_ts_name(mr->lchan->ts), best_cell->arfcn); - if (!bts->handover.active) { + if (!bts->handover.ho_active) { LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); return 0; } diff --git a/src/libcommon/gsm_data_shared.c b/src/libcommon/gsm_data_shared.c index 616b58e7d..06fee95dd 100644 --- a/src/libcommon/gsm_data_shared.c +++ b/src/libcommon/gsm_data_shared.c @@ -263,12 +263,20 @@ struct gsm_bts *gsm_bts_alloc(void *ctx) #ifdef ROLE_BSC /* default set of handover parameters */ + bts->handover.min_rxlev = -100; bts->handover.win_rxlev_avg = 10; - bts->handover.win_rxqual_avg = 1; bts->handover.win_rxlev_avg_neigh = 10; - bts->handover.pwr_interval = 6; bts->handover.pwr_hysteresis = 3; + bts->handover.pwr_interval = 6; + bts->handover.afs_rxlev_improve = 0; + bts->handover.min_rxqual = 5; + bts->handover.win_rxqual_avg = 10; + bts->handover.afs_rxqual_improve = 0; bts->handover.max_distance = 9999; + bts->handover.max_unsync_ho = 9999; + bts->handover.penalty_max_dist = 300; + bts->handover.penalty_ho_fail = 60; + bts->handover.penalty_as_fail = 60; #endif return bts; -- cgit v1.2.3