fixeria has submitted this change. (
https://gerrit.osmocom.org/c/osmo-bsc/+/28328 )
Change subject: lchan_select: implement dynamic selection mode for assignment
......................................................................
lchan_select: implement dynamic selection mode for assignment
This change implements an additional channel allocation mode, which
can be employed during a TCH channel allocation for assignment.
Selection between ascending and descending order is performed
depending on pre-configured parameters:
* Uplink RxLev threshold and number of samples for averaging,
* C0 (BCCH carrier) channel load threshold.
This is useful in setups where Tx power of the RF carriers cannot be
adjusted +dynamically at run-time and thus BS Power Control cannot
be performed. In such setups the BCCH carrier is transmitting at
relatively higher power than the other RF carriers. The key idea
is to allocate channels in a smarter way, so that UEs with poor signal
would get channels on carriers with high Tx power, while UEs with good
signal could use carriers with lower Tx power.
Change-Id: I1b7a0d706976b73cc5c30a8714b830811addfe8d
Related: osmo-ttcn3-hacks.git Ia522f37c1c001b3a36f5145b8875fbb88311c2e5
Related: SYS#5460
---
M doc/manuals/chapters/chan_alloc.adoc
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/lchan_select.h
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/bsc_vty.c
M src/osmo-bsc/bts.c
M src/osmo-bsc/bts_vty.c
M src/osmo-bsc/handover_decision_2.c
M src/osmo-bsc/handover_fsm.c
M src/osmo-bsc/lchan_select.c
M tests/handover/handover_test.c
M tests/osmo-bsc.vty
13 files changed, 329 insertions(+), 33 deletions(-)
Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
fixeria: Looks good to me, approved
laforge: Looks good to me, but someone else must approve
diff --git a/doc/manuals/chapters/chan_alloc.adoc b/doc/manuals/chapters/chan_alloc.adoc
index b6b7b92..ae2ce21 100644
--- a/doc/manuals/chapters/chan_alloc.adoc
+++ b/doc/manuals/chapters/chan_alloc.adoc
@@ -28,12 +28,15 @@
==== Channel allocation modes
-Currently only the following two simple channel allocation modes are supported:
+Currently the following channel allocation modes are supported:
- ascending (default): allocates channels in ascending order,
starting from timeslot 0 of the first TRX (also called C0, the BCCH carrier);
- descending: allocates channels in descending order,
-starting from timeslot 7 of the last TRX.
+starting from timeslot 7 of the last TRX;
+- dynamic (only for assignment): dynamically choose between ascending
+and descending order depending on some additional parameters
+(see <<chan_alloc_dyn_mode>>).
NOTE: Regardless of the chosen mode, logical channels (sub-slots) are always
selected in ascending order. For example, if a timeslot is configured as SDCCH/8
@@ -52,12 +55,72 @@
OsmoBSC(config-net-bts)# channel allocator mode set-all ? <2>
ascending Allocate Timeslots and Transceivers in ascending order
descending Allocate Timeslots and Transceivers in descending order
+
+OsmoBSC(config-net-bts)# channel allocator mode assignment ? <3>
+ ascending Allocate Timeslots and Transceivers in ascending order
+ descending Allocate Timeslots and Transceivers in descending order
+ dynamic Dynamic lchan selection based on configured parameters <3>
----
<1> It's optionally possible to configure different allocation modes for
different allocation causes, e.g. `ascending` for `chan-req` and `descending`
for both `assignment` and `handover`.
<2> `set-all` is equivalent to the old (deprecated) command syntax:
`channel allocator (ascending|descending)`.
+<3> The `dynamic` mode can be selected only for `assignment`.
+
+[[chan_alloc_dyn_mode]]
+===== Dynamic channel allocation mode
+
+There exists an additional channel allocation mode, which can be employed
+during a TCH channel allocation for assignment. This mode selects between
+ascending and descending order depending on pre-configured parameters:
+
+- Uplink RxLev threshold and number of samples for averaging,
+- C0 (BCCH carrier) channel load threshold.
+
+This is useful in setups where Tx power of the RF carriers cannot be adjusted
+dynamically at run-time and thus no BS Power Control can be performed. In
+such setups the BCCH carrier is transmitting at relatively higher power than
+the other RF carriers. The key idea is to allocate channels in a smarter way,
+so that UEs with poor signal would get channels on carriers with high Tx power,
+while UEs with good signal could use carriers with lower Tx power.
+
+The configuration parameters for dynamic selection are listed below:
+
+----
+OsmoBSC(config-net-bts)# channel allocator dynamic-param ?
+ sort-by-trx-power Whether to sort TRX instances by their respective power levels
+ ul-rxlev Uplink RxLev
+ c0-chan-load C0 (BCCH carrier) channel load
+
+channel allocator dynamic-param sort-by-trx-power ?
+ 0 Do not sort, use the same order as in the configuration file
+ 1 Sort TRX instances by their power levels in descending order
+
+OsmoBSC(config-net-bts)# channel allocator dynamic-param ul-rxlev thresh ?
+ <0-63> Uplink RxLev threshold
+OsmoBSC(config-net-bts)# channel allocator dynamic-param ul-rxlev thresh 50 avg-num ?
+ <1-10> Minimum number of RxLev samples for averaging
+OsmoBSC(config-net-bts)# channel allocator dynamic-param c0-chan-load thresh ?
+ <0-100> Channel load threshold (in %)
+----
+
+The default values are:
+
+----
+network
+ bts 0
+ channel allocator dynamic-param sort-by-trx-power 0 <1>
+ channel allocator dynamic-param ul-rxlev thresh 50 avg-num 2 <2>
+ channel allocator dynamic-param c0-chan-load thresh 60 <3>
+----
+<1> Assume that RF carriers are listed in descending order sorted by Tx power.
+<2> Use descending order if AVG of at least two Uplink RxLev samples >= 50 (-60
dBm).
+<3> Use descending order if more than 60% logical channels of C0 are occupied.
+
+NOTE: The final ascending/descending order decision is based on the two conditions.
+The descending order will be used only if *both conditions are met*, otherwise the
+allocator will use ascending order.
==== Interference aware channel allocation
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index 76945a1..752a00a 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -521,6 +521,16 @@
bool chan_alloc_assignment_reverse;
bool chan_alloc_handover_reverse;
+ /* Whether to use dynamic allocation mode for assignment */
+ bool chan_alloc_assignment_dynamic;
+ /* Parameters used for dynamic mode of allocation */
+ struct {
+ bool sort_by_trx_power;
+ uint8_t ul_rxlev_thresh;
+ uint8_t ul_rxlev_avg_num;
+ uint8_t c0_chan_load_thresh;
+ } chan_alloc_dyn_params;
+
/* When true, interference measurements from the BTS are used in the channel allocator
to favor lchans with less
* interference reported in RSL Resource Indication. */
bool chan_alloc_avoid_interf;
diff --git a/include/osmocom/bsc/lchan_select.h b/include/osmocom/bsc/lchan_select.h
index b5eb078..8f1dc62 100644
--- a/include/osmocom/bsc/lchan_select.h
+++ b/include/osmocom/bsc/lchan_select.h
@@ -13,12 +13,16 @@
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts,
enum gsm_chan_t type,
- enum lchan_select_reason reason);
+ enum lchan_select_reason reason,
+ void *ctx);
enum gsm_chan_t chan_mode_to_chan_type(enum gsm48_chan_mode chan_mode, enum channel_rate
chan_rate);
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
enum gsm48_chan_mode chan_mode,
enum channel_rate chan_rate,
- enum lchan_select_reason reason);
-struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type,
- enum lchan_select_reason reason, bool log);
+ enum lchan_select_reason reason,
+ void *ctx);
+struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts,
+ enum gsm_chan_t type,
+ enum lchan_select_reason reason,
+ void *ctx, bool log);
void lchan_select_set_type(struct gsm_lchan *lchan, enum gsm_chan_t type);
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 7f88096..527706a 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -2007,12 +2007,12 @@
/* First check the situation on the BTS, if we have TCH/H or TCH/F resources available
for another (EMERGENCY)
* call. If yes, then no (further) action has to be carried out. */
- if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, SELECT_FOR_MS_CHAN_REQ, true)) {
+ if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, SELECT_FOR_MS_CHAN_REQ, NULL,
true)) {
LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
"CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/F is (now) available!\n");
return false;
}
- if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, SELECT_FOR_MS_CHAN_REQ, true)) {
+ if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, SELECT_FOR_MS_CHAN_REQ, NULL,
true)) {
LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
"CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/H is (now) available!\n");
return false;
@@ -2083,7 +2083,7 @@
int free_tchf, free_tchh;
bool needs_dyn_switch;
- lchan = lchan_avail_by_type(bts, GSM_LCHAN_SDCCH, SELECT_FOR_MS_CHAN_REQ, false);
+ lchan = lchan_avail_by_type(bts, GSM_LCHAN_SDCCH, SELECT_FOR_MS_CHAN_REQ, NULL, false);
if (!lchan)
return NULL;
@@ -2173,7 +2173,8 @@
lchan = _select_sdcch_for_call(bts, rqd, lctype);
} else if (rqd->reason != GSM_CHREQ_REASON_EMERG) {
lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH,
- SELECT_FOR_MS_CHAN_REQ);
+ SELECT_FOR_MS_CHAN_REQ,
+ NULL);
}
/* else: Emergency calls will be put on a free TCH/H or TCH/F directly
* in the code below, all other channel requests will get an SDCCH first
@@ -2189,14 +2190,16 @@
get_value_string(gsm_chreq_descs, rqd->reason), gsm_lchant_name(GSM_LCHAN_SDCCH),
rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_H));
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H,
- SELECT_FOR_MS_CHAN_REQ);
+ SELECT_FOR_MS_CHAN_REQ,
+ NULL);
}
if (!lchan) {
LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD[%s]: no resources for %s 0x%x, retrying
with %s\n",
get_value_string(gsm_chreq_descs, rqd->reason), gsm_lchant_name(GSM_LCHAN_SDCCH),
rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_F));
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F,
- SELECT_FOR_MS_CHAN_REQ);
+ SELECT_FOR_MS_CHAN_REQ,
+ NULL);
}
}
if (!lchan) {
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 209545f..84f8b38 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -606,7 +606,7 @@
conn->assignment.new_lchan = lchan_select_by_chan_mode(bts,
req->ch_mode_rate_list[i].chan_mode,
req->ch_mode_rate_list[i].chan_rate,
- SELECT_FOR_ASSIGNMENT);
+ SELECT_FOR_ASSIGNMENT, conn->lchan);
if (!conn->assignment.new_lchan)
continue;
LOG_ASSIGNMENT(conn, LOGL_DEBUG, "selected new lchan %s for mode[%d] = %s
channel_rate=%d\n",
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index 0df5712..13ec8fb 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -772,7 +772,8 @@
if (!to_lchan) {
struct gsm_bts *bts = from_lchan->ts->trx->bts;
to_lchan = lchan_select_by_type(bts, from_lchan->type,
- SELECT_FOR_ASSIGNMENT);
+ SELECT_FOR_ASSIGNMENT,
+ from_lchan);
vty_out(vty, "Error: cannot find free lchan of type %s%s",
gsm_lchant_name(from_lchan->type), VTY_NEWLINE);
}
@@ -958,7 +959,8 @@
llist_for_each_entry(trx, &bts->trx_list, list) {
struct gsm_lchan *lchan = lchan_select_by_type(bts, free_type,
- SELECT_FOR_HANDOVER);
+ SELECT_FOR_HANDOVER,
+ NULL);
if (!lchan)
continue;
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index 2f66611..4976fe6 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -292,6 +292,9 @@
bts->early_classmark_allowed_3g = true; /* 3g Early Classmark Sending controlled by
bts->early_classmark_allowed param */
bts->si_unused_send_empty = true;
bts->chan_alloc_tch_signalling_policy = BTS_TCH_SIGNALLING_ALWAYS;
+ bts->chan_alloc_dyn_params.ul_rxlev_thresh = 50; /* >= -60 dBm */
+ bts->chan_alloc_dyn_params.ul_rxlev_avg_num = 2; /* at least 2 samples */
+ bts->chan_alloc_dyn_params.c0_chan_load_thresh = 60; /* >= 60% */
bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */
bts->si_common.cell_sel_par.rxlev_acc_min = 0;
bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
diff --git a/src/osmo-bsc/bts_vty.c b/src/osmo-bsc/bts_vty.c
index 1a9b1e3..492cb9a 100644
--- a/src/osmo-bsc/bts_vty.c
+++ b/src/osmo-bsc/bts_vty.c
@@ -550,6 +550,7 @@
bts->chan_alloc_chan_req_reverse = reverse;
bts->chan_alloc_assignment_reverse = reverse;
bts->chan_alloc_handover_reverse = reverse;
+ bts->chan_alloc_assignment_dynamic = false;
return CMD_SUCCESS;
}
@@ -574,14 +575,89 @@
if (set_all || !strcmp(argv[0], "chan-req"))
bts->chan_alloc_chan_req_reverse = reverse;
- if (set_all || !strcmp(argv[0], "assignment"))
+ if (set_all || !strcmp(argv[0], "assignment")) {
bts->chan_alloc_assignment_reverse = reverse;
+ bts->chan_alloc_assignment_dynamic = false;
+ }
if (set_all || !strcmp(argv[0], "handover"))
bts->chan_alloc_handover_reverse = reverse;
return CMD_SUCCESS;
}
+DEFUN_ATTR(cfg_bts_challoc_mode_ass_dynamic,
+ cfg_bts_challoc_mode_ass_dynamic_cmd,
+ CHAN_ALLOC_CMD " mode assignment dynamic",
+ CHAN_ALLOC_DESC
+ "Channel allocation mode\n"
+ "Channel allocation for assignment\n"
+ "Dynamic lchan selection based on configured parameters\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->chan_alloc_assignment_dynamic = true;
+
+ return CMD_SUCCESS;
+}
+
+#define CHAN_ALLOC_DYN_PARAM_CMD \
+ CHAN_ALLOC_CMD " dynamic-param"
+#define CHAN_ALLOC_DYN_PARAM_DESC \
+ CHAN_ALLOC_DESC \
+ "Parameters for dynamic channel allocation mode\n"
+
+DEFUN_ATTR(cfg_bts_challoc_dynamic_param_sort_by_trx_power,
+ cfg_bts_challoc_dynamic_param_sort_by_trx_power_cmd,
+ CHAN_ALLOC_DYN_PARAM_CMD " sort-by-trx-power (0|1)",
+ CHAN_ALLOC_DYN_PARAM_DESC
+ "Whether to sort TRX instances by their respective power levels\n"
+ "Do not sort, use the same order as in the configuration file\n"
+ "Sort TRX instances by their power levels in descending order\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->chan_alloc_dyn_params.sort_by_trx_power = (argv[0][0] == '1');
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bts_challoc_dynamic_param_ul_rxlev,
+ cfg_bts_challoc_dynamic_param_ul_rxlev_cmd,
+ CHAN_ALLOC_DYN_PARAM_CMD " ul-rxlev thresh <0-63> avg-num
<1-10>",
+ CHAN_ALLOC_DYN_PARAM_DESC
+ "Uplink RxLev\n"
+ "Uplink RxLev threshold\n"
+ "Uplink RxLev threshold\n"
+ "Minimum number of RxLev samples for averaging\n"
+ "Minimum number of RxLev samples for averaging\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->chan_alloc_dyn_params.ul_rxlev_thresh = atoi(argv[0]);
+ bts->chan_alloc_dyn_params.ul_rxlev_avg_num = atoi(argv[1]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bts_challoc_dynamic_param_c0_chan_load,
+ cfg_bts_challoc_dynamic_param_c0_chan_load_cmd,
+ CHAN_ALLOC_DYN_PARAM_CMD " c0-chan-load thresh <0-100>",
+ CHAN_ALLOC_DYN_PARAM_DESC
+ "C0 (BCCH carrier) channel load\n"
+ "Channel load threshold\n"
+ "Channel load threshold (in %)\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->chan_alloc_dyn_params.c0_chan_load_thresh = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN_ATTR(cfg_bts_chan_alloc_interf,
cfg_bts_chan_alloc_interf_cmd,
CHAN_ALLOC_CMD " avoid-interference (0|1)",
@@ -4246,9 +4322,24 @@
vty_out(vty, " channel allocator mode chan-req %s%s",
bts->chan_alloc_chan_req_reverse ? "descending" : "ascending",
VTY_NEWLINE);
- vty_out(vty, " channel allocator mode assignment %s%s",
- bts->chan_alloc_assignment_reverse ? "descending" :
"ascending",
- VTY_NEWLINE);
+ if (bts->chan_alloc_assignment_dynamic) {
+ vty_out(vty, " channel allocator mode assignment dynamic%s",
+ VTY_NEWLINE);
+ vty_out(vty, " channel allocator dynamic-param sort-by-trx-power %c%s",
+ bts->chan_alloc_dyn_params.sort_by_trx_power ? '1' : '0',
+ VTY_NEWLINE);
+ vty_out(vty, " channel allocator dynamic-param ul-rxlev thresh %u avg-num
%u%s",
+ bts->chan_alloc_dyn_params.ul_rxlev_thresh,
+ bts->chan_alloc_dyn_params.ul_rxlev_avg_num,
+ VTY_NEWLINE);
+ vty_out(vty, " channel allocator dynamic-param c0-chan-load thresh %u%s",
+ bts->chan_alloc_dyn_params.c0_chan_load_thresh,
+ VTY_NEWLINE);
+ } else {
+ vty_out(vty, " channel allocator mode assignment %s%s",
+ bts->chan_alloc_assignment_reverse ? "descending" :
"ascending",
+ VTY_NEWLINE);
+ }
vty_out(vty, " channel allocator mode handover %s%s",
bts->chan_alloc_handover_reverse ? "descending" : "ascending",
VTY_NEWLINE);
@@ -4582,6 +4673,10 @@
install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
install_element(BTS_NODE, &cfg_bts_challoc_mode_cmd);
install_element(BTS_NODE, &cfg_bts_challoc_mode_all_cmd);
+ install_element(BTS_NODE, &cfg_bts_challoc_mode_ass_dynamic_cmd);
+ install_element(BTS_NODE, &cfg_bts_challoc_dynamic_param_sort_by_trx_power_cmd);
+ install_element(BTS_NODE, &cfg_bts_challoc_dynamic_param_ul_rxlev_cmd);
+ install_element(BTS_NODE, &cfg_bts_challoc_dynamic_param_c0_chan_load_cmd);
install_element(BTS_NODE, &cfg_bts_chan_alloc_interf_cmd);
install_element(BTS_NODE, &cfg_bts_chan_alloc_tch_signalling_policy_cmd);
install_element(BTS_NODE, &cfg_bts_chan_alloc_allow_tch_for_signalling_cmd);
diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c
index 3c4b3ba..a472089 100644
--- a/src/osmo-bsc/handover_decision_2.c
+++ b/src/osmo-bsc/handover_decision_2.c
@@ -1050,7 +1050,8 @@
/* Would the next TCH/F lchan occupy a dynamic timeslot that currently counts for free
TCH/H timeslots?
*/
- next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F,
SELECT_FOR_HANDOVER, false);
+ next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F,
+ SELECT_FOR_HANDOVER, NULL, false);
if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN)
c->target.next_tchf_reduces_tchh = 2;
else
@@ -1058,7 +1059,8 @@
/* Would the next TCH/H lchan occupy a dynamic timeslot that currently counts for free
TCH/F timeslots?
* Note that a dyn TS already in TCH/H mode (half occupied) would not reduce free
TCH/F. */
- next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H,
SELECT_FOR_HANDOVER, false);
+ next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H,
+ SELECT_FOR_HANDOVER, NULL, false);
if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN
&& next_lchan->ts->pchan_is != GSM_PCHAN_TCH_H)
c->target.next_tchh_reduces_tchf = 1;
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index 0797bf3..2f45243 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -381,7 +381,8 @@
ho->new_lchan = lchan_select_by_type(ho->new_bts,
ho->new_lchan_type,
- SELECT_FOR_HANDOVER);
+ SELECT_FOR_HANDOVER,
+ NULL);
if (ho->scope & HO_INTRA_CELL) {
ho_count(bts, CTR_INTRA_CELL_HO_ATTEMPTED);
@@ -701,7 +702,7 @@
lchan = lchan_select_by_chan_mode(bts,
ch_mode_rate.chan_mode,
ch_mode_rate.chan_rate,
- SELECT_FOR_HANDOVER);
+ SELECT_FOR_HANDOVER, NULL);
if (!lchan) {
LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free channels\n",
bts->nr);
continue;
diff --git a/src/osmo-bsc/lchan_select.c b/src/osmo-bsc/lchan_select.c
index 8b6da40..ebc7ede 100644
--- a/src/osmo-bsc/lchan_select.c
+++ b/src/osmo-bsc/lchan_select.c
@@ -21,6 +21,8 @@
*
*/
+#include <stdlib.h>
+
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/gsm_data.h>
@@ -195,15 +197,41 @@
}
}
+static int qsort_func(const void *_a, const void *_b)
+{
+ const struct gsm_bts_trx *trx_a = *(const struct gsm_bts_trx **)_a;
+ const struct gsm_bts_trx *trx_b = *(const struct gsm_bts_trx **)_b;
+
+ int pwr_a = trx_a->nominal_power - trx_a->max_power_red;
+ int pwr_b = trx_b->nominal_power - trx_b->max_power_red;
+
+ /* Sort in descending order */
+ return pwr_b - pwr_a;
+}
+
static void populate_ts_list(struct lchan_select_ts_list *ts_list,
struct gsm_bts *bts,
bool chan_alloc_reverse,
+ bool sort_by_trx_power,
bool log)
{
+ struct gsm_bts_trx **trx_list;
struct gsm_bts_trx *trx;
unsigned int num = 0;
- llist_for_each_entry(trx, &bts->trx_list, list) {
+ /* Allocate an array with pointers to all TRX instances of a BTS */
+ trx_list = talloc_array_ptrtype(bts, trx_list, bts->num_trx);
+ OSMO_ASSERT(trx_list != NULL);
+
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ trx_list[trx->nr] = trx;
+
+ /* Sort by TRX power in descending order (if needed) */
+ if (sort_by_trx_power)
+ qsort(&trx_list[0], bts->num_trx, sizeof(trx), &qsort_func);
+
+ for (unsigned int trxn = 0; trxn < bts->num_trx; trxn++) {
+ trx = trx_list[trxn];
for (unsigned int tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
struct gsm_bts_trx_ts *ts = &trx->ts[tn];
if (ts_is_usable(ts))
@@ -213,6 +241,7 @@
}
}
+ talloc_free(trx_list);
ts_list->num = num;
/* Reverse the timeslot list if required */
@@ -225,23 +254,75 @@
}
}
+static bool chan_alloc_ass_dynamic_reverse(struct gsm_bts *bts,
+ void *ctx, bool log)
+{
+ const struct load_counter *ll = &bts->c0->lchan_load;
+ const struct gsm_lchan *old_lchan = ctx;
+ unsigned int lchan_load;
+ int avg_ul_rxlev;
+
+ OSMO_ASSERT(old_lchan != NULL);
+ OSMO_ASSERT(old_lchan->ts->trx->bts == bts);
+
+#define LOG_COND(fmt, args...) do { \
+ if (log) \
+ LOG_LCHAN(old_lchan, LOGL_DEBUG, fmt, ## args); \
+ } while (0)
+
+ /* Condition a) Channel load on the C0 (BCCH carrier) */
+ lchan_load = ll->total ? ll->used * 100 / ll->total : 0;
+ if (lchan_load < bts->chan_alloc_dyn_params.c0_chan_load_thresh) {
+ LOG_COND("C0 Channel Load %u%% < thresh %u%% => using ascending
order\n",
+ lchan_load, bts->chan_alloc_dyn_params.c0_chan_load_thresh);
+ return false;
+ }
+
+ /* Condition b) average Uplink RxLev */
+ avg_ul_rxlev = get_meas_rep_avg(old_lchan, TDMA_MEAS_FIELD_RXLEV,
+ TDMA_MEAS_DIR_UL, TDMA_MEAS_SET_AUTO,
+ bts->chan_alloc_dyn_params.ul_rxlev_avg_num);
+ if (avg_ul_rxlev < 0) {
+ LOG_COND("Unknown AVG UL RxLev => using ascending order\n");
+ return false;
+ }
+ if (avg_ul_rxlev < bts->chan_alloc_dyn_params.ul_rxlev_thresh) {
+ LOG_COND("AVG UL RxLev %u < thresh %u => using ascending order\n",
+ avg_ul_rxlev, bts->chan_alloc_dyn_params.ul_rxlev_thresh);
+ return false;
+ }
+
+ LOG_COND("C0 Channel Load %u%% >= thresh %u%% and "
+ "AVG UL RxLev %u >= thresh %u => using descending order\n",
+ lchan_load, bts->chan_alloc_dyn_params.c0_chan_load_thresh,
+ avg_ul_rxlev, bts->chan_alloc_dyn_params.ul_rxlev_thresh);
+
+#undef LOG_COND
+
+ return true;
+}
+
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
enum gsm48_chan_mode chan_mode,
enum channel_rate chan_rate,
- enum lchan_select_reason reason)
+ enum lchan_select_reason reason,
+ void *ctx)
{
enum gsm_chan_t type = chan_mode_to_chan_type(chan_mode, chan_rate);
if (type == GSM_LCHAN_NONE)
return NULL;
- return lchan_select_by_type(bts, type, reason);
+ return lchan_select_by_type(bts, type, reason, ctx);
}
-struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type,
- enum lchan_select_reason reason, bool log)
+struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts,
+ enum gsm_chan_t type,
+ enum lchan_select_reason reason,
+ void *ctx, bool log)
{
struct gsm_lchan *lchan = NULL;
enum gsm_phys_chan_config first, first_cbch, second, second_cbch;
struct lchan_select_ts_list ts_list;
+ bool sort_by_trx_power = false;
bool chan_alloc_reverse;
if (log) {
@@ -254,7 +335,12 @@
chan_alloc_reverse = bts->chan_alloc_chan_req_reverse;
break;
case SELECT_FOR_ASSIGNMENT:
- chan_alloc_reverse = bts->chan_alloc_assignment_reverse;
+ if (bts->chan_alloc_assignment_dynamic) {
+ chan_alloc_reverse = chan_alloc_ass_dynamic_reverse(bts, ctx, log);
+ sort_by_trx_power = bts->chan_alloc_dyn_params.sort_by_trx_power;
+ } else {
+ chan_alloc_reverse = bts->chan_alloc_assignment_reverse;
+ }
break;
case SELECT_FOR_HANDOVER:
chan_alloc_reverse = bts->chan_alloc_handover_reverse;
@@ -267,7 +353,7 @@
return NULL;
/* Populate this array with the actual pointers */
- populate_ts_list(&ts_list, bts, chan_alloc_reverse, log);
+ populate_ts_list(&ts_list, bts, chan_alloc_reverse, sort_by_trx_power, log);
switch (type) {
case GSM_LCHAN_SDCCH:
@@ -330,14 +416,15 @@
* the lchan and timeslot FSMs. */
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts,
enum gsm_chan_t type,
- enum lchan_select_reason reason)
+ enum lchan_select_reason reason,
+ void *ctx)
{
struct gsm_lchan *lchan = NULL;
LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_by_type(type=%s, reason=%s)\n",
gsm_lchant_name(type), lchan_select_reason_name(reason));
- lchan = lchan_avail_by_type(bts, type, reason, true);
+ lchan = lchan_avail_by_type(bts, type, reason, ctx, true);
if (!lchan) {
LOG_BTS(bts, DRLL, LOGL_NOTICE, "Failed to select %s channel (%s)\n",
diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c
index 77fa371..26c72ab 100644
--- a/tests/handover/handover_test.c
+++ b/tests/handover/handover_test.c
@@ -489,7 +489,7 @@
struct gsm_lchan *lchan;
lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H,
- SELECT_FOR_HANDOVER);
+ SELECT_FOR_HANDOVER, NULL);
if (!lchan) {
fprintf(stderr, "No resource for lchan\n");
exit(EXIT_FAILURE);
diff --git a/tests/osmo-bsc.vty b/tests/osmo-bsc.vty
index e0b9bdc..4be3d56 100644
--- a/tests/osmo-bsc.vty
+++ b/tests/osmo-bsc.vty
@@ -167,6 +167,7 @@
OsmoBSC(config-net-bts)# channel allocator ?
mode Channel allocation mode
+ dynamic-param Parameters for dynamic channel allocation mode
avoid-interference Configure whether reported interference levels from RES IND are
used in channel allocation
tch-signalling-policy Configure when TCH/H or TCH/F channels can be used to serve
signalling if SDCCHs are exhausted
@@ -180,6 +181,31 @@
ascending Allocate Timeslots and Transceivers in ascending order
descending Allocate Timeslots and Transceivers in descending order
+OsmoBSC(config-net-bts)# channel allocator mode handover ?
+ ascending Allocate Timeslots and Transceivers in ascending order
+ descending Allocate Timeslots and Transceivers in descending order
+
+OsmoBSC(config-net-bts)# channel allocator mode assignment ?
+ ascending Allocate Timeslots and Transceivers in ascending order
+ descending Allocate Timeslots and Transceivers in descending order
+ dynamic Dynamic lchan selection based on configured parameters
+
+OsmoBSC(config-net-bts)# channel allocator dynamic-param ?
+ sort-by-trx-power Whether to sort TRX instances by their respective power levels
+ ul-rxlev Uplink RxLev
+ c0-chan-load C0 (BCCH carrier) channel load
+
+OsmoBSC(config-net-bts)# channel allocator dynamic-param sort-by-trx-power ?
+ 0 Do not sort, use the same order as in the configuration file
+ 1 Sort TRX instances by their power levels in descending order
+
+OsmoBSC(config-net-bts)# channel allocator dynamic-param ul-rxlev thresh ?
+ <0-63> Uplink RxLev threshold
+OsmoBSC(config-net-bts)# channel allocator dynamic-param ul-rxlev thresh 50 avg-num ?
+ <1-10> Minimum number of RxLev samples for averaging
+OsmoBSC(config-net-bts)# channel allocator dynamic-param c0-chan-load thresh ?
+ <0-100> Channel load threshold (in %)
+
OsmoBSC(config-net-bts)# channel allocator avoid-interference ?
0 Ignore interference levels (default). Always assign lchans in a deterministic
order.
1 In channel allocation, prefer lchans with less interference.
--
To view, visit
https://gerrit.osmocom.org/c/osmo-bsc/+/28328
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I1b7a0d706976b73cc5c30a8714b830811addfe8d
Gerrit-Change-Number: 28328
Gerrit-PatchSet: 6
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-CC: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged