lchan_select: allow different alloc order for assignment and handover

A follow-up patch implements a special channel allocation mode, which is
only working for assignment (basically TCH selection for a voice call).
This mode cannot be employed for initial CHANNEL REQUEST or handover due
to the absence of an already established lchan.

Adding this mode to the existing VTY command syntax would be confusing:

  channel allocator (ascending|desscending|dynamic)
                                           ^^^^^^^

so this patch extends the VTY syntax in a way that it becomes possible
to configure different channel allocator modes for different cases:

  OsmoBSC(config-net-bts)# channel allocator mode ?
    set-all     Set a single mode for all variants
    chan-req    Channel allocation for CHANNEL REQUEST (RACH)
    assignment  Channel allocation for assignment
    handover    Channel allocation for handover

The old command syntax, which is basically 'set-all', is kept for
backwards compatibility, but marked as deprecated.

Change-Id: I3ae73b36ee9433cc768376b56f0765e5f416162f
Related: SYS#5460
This commit is contained in:
Vadim Yanitskiy 2022-06-06 01:43:28 +06:00 committed by fixeria
parent ff9d3a64dc
commit c2928ac269
23 changed files with 187 additions and 67 deletions

View File

@ -39,7 +39,7 @@ network
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator descending
channel allocator mode set-all descending
rach tx integer 9
rach max transmission 7
oml e1 line 0 timeslot 1 sub-slot full

View File

@ -39,7 +39,7 @@ network
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator descending
channel allocator mode set-all descending
rach tx integer 9
rach max transmission 7
oml e1 line 0 timeslot 1 sub-slot full

View File

@ -39,7 +39,7 @@ network
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator descending
channel allocator mode set-all descending
rach tx integer 9
rach max transmission 7
oml e1 line 0 timeslot 1 sub-slot full

View File

@ -45,7 +45,7 @@ network
ms max power 33
cell reselection hysteresis 4
rxlev access min 0
channel allocator descending
channel allocator mode set-all descending
rach tx integer 9
rach max transmission 7
oml e1 line 0 timeslot 1 sub-slot full

View File

@ -17,7 +17,7 @@ network
cell reselection hysteresis 4
rxlev access min 0
radio-link-timeout 32
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
channel-description attach 1

View File

@ -29,7 +29,7 @@ network
cell reselection hysteresis 4
rxlev access min 0
radio-link-timeout 32
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
channel-description attach 1

View File

@ -28,7 +28,7 @@ network
cell reselection hysteresis 4
rxlev access min 0
radio-link-timeout 32
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
channel-description attach 1

View File

@ -32,7 +32,7 @@ network
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
ipa unit-id 1801 0 <4>
@ -110,7 +110,7 @@ network
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
ipa unit-id 1800 0 <1>
@ -203,7 +203,7 @@ network
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
oml e1 line 0 timeslot 1 sub-slot full <3>

View File

@ -19,7 +19,9 @@ All parameters with their respective default values are listed below:
----
network
bts 0
channel allocator ascending
channel allocator mode chan-req ascending
channel allocator mode assignment ascending
channel allocator mode handover ascending
channel allocator avoid-interference 0
channel allocator tch-signalling-policy always
----
@ -41,10 +43,21 @@ selected in both ascending and descending modes.
The allocation mode to be used can be configured using the following VTY command:
----
OsmoBSC(config-net-bts)# channel allocator ?
ascending Allocate Timeslots and Transceivers in ascending order
descending Allocate Timeslots and Transceivers in descending order
OsmoBSC(config-net-bts)# channel allocator mode ? <1>
set-all Set a single mode for all variants
chan-req Channel allocation for CHANNEL REQUEST (RACH)
assignment Channel allocation for assignment
handover Channel allocation for handover
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
----
<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)`.
==== Interference aware channel allocation

View File

@ -517,7 +517,9 @@ struct gsm_bts {
/* should the channel allocator allocate channels from high TRX to TRX0,
* rather than starting from TRX0 and go upwards? */
int chan_alloc_reverse;
bool chan_alloc_chan_req_reverse;
bool chan_alloc_assignment_reverse;
bool chan_alloc_handover_reverse;
/* When true, interference measurements from the BTS are used in the channel allocator to favor lchans with less
* interference reported in RSL Resource Indication. */

View File

@ -1,9 +1,24 @@
/* Select a suitable lchan from a given cell. */
#pragma once
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type);
enum lchan_select_reason {
SELECT_FOR_MS_CHAN_REQ,
SELECT_FOR_ASSIGNMENT,
SELECT_FOR_HANDOVER,
};
extern const struct value_string lchan_select_reason_names[];
static inline const char *lchan_select_reason_name(enum lchan_select_reason reason)
{ return get_value_string(lchan_select_reason_names, reason); }
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts,
enum gsm_chan_t type,
enum lchan_select_reason reason);
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);
struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type, bool log);
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);
void lchan_select_set_type(struct gsm_lchan *lchan, enum gsm_chan_t type);

View File

@ -1978,10 +1978,10 @@ static struct gsm_lchan *get_any_lchan(struct gsm_bts *bts)
ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H) {
if (lchan->fi->state == LCHAN_ST_ESTABLISHED) {
if (!lchan_est || bts->chan_alloc_reverse)
if (!lchan_est || bts->chan_alloc_chan_req_reverse)
lchan_est = lchan;
} else {
if (!lchan_any || bts->chan_alloc_reverse)
if (!lchan_any || bts->chan_alloc_chan_req_reverse)
lchan_any = lchan;
}
}
@ -2007,12 +2007,12 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd)
/* 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, true)) {
if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, SELECT_FOR_MS_CHAN_REQ, 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, true)) {
if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, SELECT_FOR_MS_CHAN_REQ, 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 @@ struct gsm_lchan *_select_sdcch_for_call(struct gsm_bts *bts, const struct chan_
int free_tchf, free_tchh;
bool needs_dyn_switch;
lchan = lchan_avail_by_type(bts, GSM_LCHAN_SDCCH, false);
lchan = lchan_avail_by_type(bts, GSM_LCHAN_SDCCH, SELECT_FOR_MS_CHAN_REQ, false);
if (!lchan)
return NULL;
@ -2172,7 +2172,8 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts)
if (rqd->reason == GSM_CHREQ_REASON_CALL) {
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);
lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH,
SELECT_FOR_MS_CHAN_REQ);
}
/* 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
@ -2187,13 +2188,15 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts)
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_H));
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H);
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H,
SELECT_FOR_MS_CHAN_REQ);
}
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);
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F,
SELECT_FOR_MS_CHAN_REQ);
}
}
if (!lchan) {

View File

@ -604,7 +604,9 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
/* Try to allocate a new lchan in order of preference */
for (i = 0; i < req->n_ch_mode_rate; i++) {
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);
req->ch_mode_rate_list[i].chan_mode,
req->ch_mode_rate_list[i].chan_rate,
SELECT_FOR_ASSIGNMENT);
if (!conn->assignment.new_lchan)
continue;
LOG_ASSIGNMENT(conn, LOGL_DEBUG, "selected new lchan %s for mode[%d] = %s channel_rate=%d\n",

View File

@ -770,7 +770,9 @@ static int trigger_as(struct vty *vty, struct gsm_lchan *from_lchan, struct gsm_
{
LOG_LCHAN(from_lchan, LOGL_NOTICE, "Manually triggering Assignment from VTY\n");
if (!to_lchan) {
to_lchan = lchan_select_by_type(from_lchan->ts->trx->bts, from_lchan->type);
struct gsm_bts *bts = from_lchan->ts->trx->bts;
to_lchan = lchan_select_by_type(bts, from_lchan->type,
SELECT_FOR_ASSIGNMENT);
vty_out(vty, "Error: cannot find free lchan of type %s%s",
gsm_lchant_name(from_lchan->type), VTY_NEWLINE);
}
@ -955,7 +957,8 @@ static struct gsm_bts *find_other_bts_with_free_slots(struct vty *vty, struct gs
continue;
llist_for_each_entry(trx, &bts->trx_list, list) {
struct gsm_lchan *lchan = lchan_select_by_type(bts, free_type);
struct gsm_lchan *lchan = lchan_select_by_type(bts, free_type,
SELECT_FOR_HANDOVER);
if (!lchan)
continue;

View File

@ -533,20 +533,51 @@ DEFUN_USRATTR(cfg_bts_oml_e1_tei,
"Channel Allocator\n" \
"Channel Allocator\n"
DEFUN_ATTR(cfg_bts_challoc,
cfg_bts_challoc_cmd,
CHAN_ALLOC_CMD " (ascending|descending)",
CHAN_ALLOC_DESC
"Allocate Timeslots and Transceivers in ascending order\n"
"Allocate Timeslots and Transceivers in descending order\n",
CMD_ATTR_IMMEDIATE)
#define CHAN_ALLOC_ASC_DSC "(ascending|descending)"
#define CHAN_ALLOC_ASC_DSC_DESC \
"Allocate Timeslots and Transceivers in ascending order\n" \
"Allocate Timeslots and Transceivers in descending order\n"
DEFUN_ATTR(cfg_bts_challoc_mode_all,
cfg_bts_challoc_mode_all_cmd,
CHAN_ALLOC_CMD " " CHAN_ALLOC_ASC_DSC,
CHAN_ALLOC_DESC CHAN_ALLOC_ASC_DSC_DESC,
CMD_ATTR_IMMEDIATE | CMD_ATTR_DEPRECATED)
{
bool reverse = !strcmp(argv[0], "descending");
struct gsm_bts *bts = vty->index;
if (!strcmp(argv[0], "ascending"))
bts->chan_alloc_reverse = 0;
else
bts->chan_alloc_reverse = 1;
bts->chan_alloc_chan_req_reverse = reverse;
bts->chan_alloc_assignment_reverse = reverse;
bts->chan_alloc_handover_reverse = reverse;
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_bts_challoc_mode,
cfg_bts_challoc_mode_cmd,
CHAN_ALLOC_CMD
" mode (set-all|chan-req|assignment|handover) "
CHAN_ALLOC_ASC_DSC,
CHAN_ALLOC_DESC
"Channel allocation mode\n"
"Set a single mode for all variants\n"
"Channel allocation for CHANNEL REQUEST (RACH)\n"
"Channel allocation for assignment\n"
"Channel allocation for handover\n"
CHAN_ALLOC_ASC_DSC_DESC,
CMD_ATTR_IMMEDIATE)
{
bool reverse = !strcmp(argv[1], "descending");
bool set_all = !strcmp(argv[0], "set-all");
struct gsm_bts *bts = vty->index;
if (set_all || !strcmp(argv[0], "chan-req"))
bts->chan_alloc_chan_req_reverse = reverse;
if (set_all || !strcmp(argv[0], "assignment"))
bts->chan_alloc_assignment_reverse = reverse;
if (set_all || !strcmp(argv[0], "handover"))
bts->chan_alloc_handover_reverse = reverse;
return CMD_SUCCESS;
}
@ -4212,8 +4243,14 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " radio-link-timeout %d%s",
gsm_bts_get_radio_link_timeout(bts), VTY_NEWLINE);
vty_out(vty, " channel allocator %s%s",
bts->chan_alloc_reverse ? "descending" : "ascending",
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);
vty_out(vty, " channel allocator mode handover %s%s",
bts->chan_alloc_handover_reverse ? "descending" : "ascending",
VTY_NEWLINE);
if (bts->chan_alloc_avoid_interf)
vty_out(vty, " channel allocator avoid-interference 1%s", VTY_NEWLINE);
@ -4543,7 +4580,8 @@ int bts_vty_init(void)
install_element(BTS_NODE, &cfg_bts_deprecated_stream_id_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
install_element(BTS_NODE, &cfg_bts_challoc_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_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);

View File

@ -1050,7 +1050,7 @@ static void candidate_set_free_tch(struct ho_candidate *c)
/* 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, false);
next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F, SELECT_FOR_HANDOVER, false);
if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN)
c->target.next_tchf_reduces_tchh = 2;
else
@ -1058,7 +1058,7 @@ static void candidate_set_free_tch(struct ho_candidate *c)
/* 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, false);
next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H, SELECT_FOR_HANDOVER, 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;

View File

@ -379,7 +379,9 @@ static void handover_start_intra_bsc(struct gsm_subscriber_connection *conn)
ho->async = true;
gsm_bts_cell_id_list(&ho->target_cell_ids, ho->new_bts);
ho->new_lchan = lchan_select_by_type(ho->new_bts, ho->new_lchan_type);
ho->new_lchan = lchan_select_by_type(ho->new_bts,
ho->new_lchan_type,
SELECT_FOR_HANDOVER);
if (ho->scope & HO_INTRA_CELL) {
ho_count(bts, CTR_INTRA_CELL_HO_ATTEMPTED);
@ -696,7 +698,10 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
ch_mode_rate.chan_rate == CH_RATE_FULL ? "full-rate" : "half-rate",
gsm0808_channel_type_name(&req->ct));
lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, ch_mode_rate.chan_rate);
lchan = lchan_select_by_chan_mode(bts,
ch_mode_rate.chan_mode,
ch_mode_rate.chan_rate,
SELECT_FOR_HANDOVER);
if (!lchan) {
LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free channels\n", bts->nr);
continue;

View File

@ -35,6 +35,13 @@ struct lchan_select_ts_list {
unsigned int num;
};
const struct value_string lchan_select_reason_names[] = {
OSMO_VALUE_STRING(SELECT_FOR_MS_CHAN_REQ),
OSMO_VALUE_STRING(SELECT_FOR_ASSIGNMENT),
OSMO_VALUE_STRING(SELECT_FOR_HANDOVER),
{0, NULL}
};
static struct gsm_lchan *pick_better_lchan(struct gsm_lchan *a, struct gsm_lchan *b)
{
if (!a)
@ -190,6 +197,7 @@ enum gsm_chan_t chan_mode_to_chan_type(enum gsm48_chan_mode chan_mode, enum chan
static void populate_ts_list(struct lchan_select_ts_list *ts_list,
struct gsm_bts *bts,
bool chan_alloc_reverse,
bool log)
{
struct gsm_bts_trx *trx;
@ -208,7 +216,7 @@ static void populate_ts_list(struct lchan_select_ts_list *ts_list,
ts_list->num = num;
/* Reverse the timeslot list if required */
if (bts->chan_alloc_reverse) {
if (chan_alloc_reverse) {
for (unsigned int tn = 0; tn < num / 2; tn++) {
struct gsm_bts_trx_ts *temp = ts_list->list[tn];
ts_list->list[tn] = ts_list->list[num - tn - 1];
@ -218,22 +226,40 @@ static void populate_ts_list(struct lchan_select_ts_list *ts_list,
}
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate)
enum gsm48_chan_mode chan_mode,
enum channel_rate chan_rate,
enum lchan_select_reason reason)
{
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);
return lchan_select_by_type(bts, type, reason);
}
struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type, bool log)
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 = NULL;
enum gsm_phys_chan_config first, first_cbch, second, second_cbch;
struct lchan_select_ts_list ts_list;
bool chan_alloc_reverse;
if (log)
LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_avail_by_type(%s)\n", gsm_lchant_name(type));
if (log) {
LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_avail_by_type(type=%s, reason=%s)\n",
gsm_lchant_name(type), lchan_select_reason_name(reason));
}
switch (reason) {
case SELECT_FOR_MS_CHAN_REQ:
chan_alloc_reverse = bts->chan_alloc_chan_req_reverse;
break;
case SELECT_FOR_ASSIGNMENT:
chan_alloc_reverse = bts->chan_alloc_assignment_reverse;
break;
case SELECT_FOR_HANDOVER:
chan_alloc_reverse = bts->chan_alloc_handover_reverse;
break;
}
/* Allocate an array with pointers to all timeslots of a BTS */
ts_list.list = talloc_array_ptrtype(bts, ts_list.list, bts->num_trx * 8);
@ -241,11 +267,11 @@ struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type,
return NULL;
/* Populate this array with the actual pointers */
populate_ts_list(&ts_list, bts, log);
populate_ts_list(&ts_list, bts, chan_alloc_reverse, log);
switch (type) {
case GSM_LCHAN_SDCCH:
if (bts->chan_alloc_reverse) {
if (chan_alloc_reverse) {
first = GSM_PCHAN_SDCCH8_SACCH8C;
first_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH;
second = GSM_PCHAN_CCCH_SDCCH4;
@ -302,17 +328,20 @@ struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type,
/* Return a matching lchan from a specific BTS that is currently available. The next logical step is
* lchan_activate() on it, which would possibly cause dynamic timeslot pchan switching, taken care of by
* the lchan and timeslot FSMs. */
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type)
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts,
enum gsm_chan_t type,
enum lchan_select_reason reason)
{
struct gsm_lchan *lchan = NULL;
LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_by_type(%s)\n", gsm_lchant_name(type));
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, true);
lchan = lchan_avail_by_type(bts, type, reason, true);
if (!lchan) {
LOG_BTS(bts, DRLL, LOGL_NOTICE, "Failed to select %s channel\n",
gsm_lchant_name(type));
LOG_BTS(bts, DRLL, LOGL_NOTICE, "Failed to select %s channel (%s)\n",
gsm_lchant_name(type), lchan_select_reason_name(reason));
return NULL;
}

View File

@ -9,7 +9,7 @@ network
cell reselection hysteresis 4
rxlev access min 0
radio-link-timeout 32
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
channel-description attach 1

View File

@ -35,7 +35,7 @@ network
cell reselection hysteresis 4
rxlev access min 0
radio-link-timeout 32
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
channel-description attach 1
@ -92,7 +92,7 @@ network
cell reselection hysteresis 4
rxlev access min 0
radio-link-timeout 32
channel allocator ascending
channel allocator mode set-all ascending
rach tx integer 9
rach max transmission 7
channel-description attach 1

View File

@ -488,7 +488,8 @@ struct gsm_lchan *create_lchan(struct gsm_bts *bts, int full_rate, const char *c
{
struct gsm_lchan *lchan;
lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H);
lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H,
SELECT_FOR_HANDOVER);
if (!lchan) {
fprintf(stderr, "No resource for lchan\n");
exit(EXIT_FAILURE);

View File

@ -3,7 +3,7 @@ create-bts trx-count 1 timeslots c+s4 dyn TCH/H dyn TCH/H dyn TCH/H
network
bts 0
channel allocator ascending
channel allocator mode set-all ascending
set-ts-use trx 0 0 states * TCH/-H TCH/-H TCH/-H TCH/-H TCH/-H TCH/-H *

View File

@ -166,11 +166,20 @@ OsmoBSC(config-net-bts)# channel ?
allocator Channel Allocator
OsmoBSC(config-net-bts)# channel allocator ?
ascending Allocate Timeslots and Transceivers in ascending order
descending Allocate Timeslots and Transceivers in descending order
mode 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
OsmoBSC(config-net-bts)# channel allocator mode ?
set-all Set a single mode for all variants
chan-req Channel allocation for CHANNEL REQUEST (RACH)
assignment Channel allocation for assignment
handover Channel allocation for handover
OsmoBSC(config-net-bts)# channel allocator mode set-all ?
ascending Allocate Timeslots and Transceivers in ascending order
descending Allocate Timeslots and Transceivers in descending order
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.