fixeria has uploaded this change for review. ( 
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

Change-Id: I1b7a0d706976b73cc5c30a8714b830811addfe8d
Related: SYS#5460
---
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/lchan_select.h
M include/osmocom/bsc/meas_rep.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 src/osmo-bsc/meas_rep.c
M tests/osmo-bsc.vty
13 files changed, 270 insertions(+), 34 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/28/28328/1

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/include/osmocom/bsc/meas_rep.h b/include/osmocom/bsc/meas_rep.h
index 402a888..a01bb2f 100644
--- a/include/osmocom/bsc/meas_rep.h
+++ b/include/osmocom/bsc/meas_rep.h
@@ -88,4 +88,7 @@
                              unsigned int meas_rep_idx,
                              unsigned int num_values);

+int meas_get_field(const struct gsm_meas_rep *rep,
+                  enum meas_rep_field field);
+
 #endif /* _MEAS_REP_H */
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 4af7b6e..eaa4572 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 46866e0..741a0d7 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..dcea4fc 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 is 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...) \
+       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/src/osmo-bsc/meas_rep.c b/src/osmo-bsc/meas_rep.c
index 776c610..ae0cc64 100644
--- a/src/osmo-bsc/meas_rep.c
+++ b/src/osmo-bsc/meas_rep.c
@@ -24,8 +24,8 @@
 #include <osmocom/bsc/gsm_data.h>
 #include <osmocom/bsc/meas_rep.h>

-static int get_field(const struct gsm_meas_rep *rep,
-                    enum meas_rep_field field)
+int meas_get_field(const struct gsm_meas_rep *rep,
+                  enum meas_rep_field field)
 {
        switch (field) {
        case MEAS_REP_DL_RXLEV_FULL:
@@ -146,7 +146,7 @@
                int val;

                use_field = choose_meas_rep_field(field, dir, set, 
&lchan->meas_rep[j]);
-               val = get_field(&lchan->meas_rep[j], use_field);
+               val = meas_get_field(&lchan->meas_rep[j], use_field);

                if (val >= 0) {
                        avg += val;
@@ -177,7 +177,7 @@
                int val;

                use_field = choose_meas_rep_field(field, dir, set, 
&lchan->meas_rep[j]);
-               val = get_field(&lchan->meas_rep[j], use_field);
+               val = meas_get_field(&lchan->meas_rep[j], use_field);

                if (val >= be) /* implies that val < 0 will not count */
                        count++;
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: 1
Gerrit-Owner: fixeria <[email protected]>
Gerrit-MessageType: newchange

Reply via email to