<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/11321">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">handover_decision_2.c: implement HO to remote BSS<br><br>Implement basic support for inter-BSC HO from handover_decision_2: do inter-BSC<br>handover only when rxlev / rxqual / ta drop below the minimum requirements.<br><br>I considered adding a vty config flag to disable/enable remote-BSS handover,<br>but to avoid inter-BSC HO the user can simply refrain from configuring<br>neighbors for a particular cell.<br><br>In collect_assignment_candidate(), it is important to clear out any new<br>candidate entry. Hence adopt the same pattern as below: first compose a new<br>(cleared) candidate, then write the entry into the list.<br><br>Related: OS#3638<br>Change-Id: Id78ac1b2016998a2931a23d62ec7a3f37bb764c6<br>---<br>M src/osmo-bsc/handover_decision_2.c<br>1 file changed, 185 insertions(+), 28 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c</span><br><span>index 457d57a..a8fff63 100644</span><br><span>--- a/src/osmo-bsc/handover_decision_2.c</span><br><span>+++ b/src/osmo-bsc/handover_decision_2.c</span><br><span>@@ -98,8 +98,9 @@</span><br><span> </span><br><span> struct ho_candidate {</span><br><span>        struct gsm_lchan *lchan;        /* candidate for whom */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct neighbor_ident_key nik;  /* neighbor ARFCN+BSIC */</span><br><span>    struct gsm_bts *bts;            /* target BTS in local BSS */</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gsm0808_cell_id_list2 *cil; /* target cells in remote BSS */</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct gsm0808_cell_id_list2 *cil; /* target cells in remote BSS */</span><br><span>    uint8_t requirements;           /* what is fulfilled */</span><br><span>      int avg;                        /* average RX level */</span><br><span> };</span><br><span>@@ -619,6 +620,75 @@</span><br><span>  return requirement;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t check_requirements_remote_bss(struct gsm_lchan *lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        const struct gsm0808_cell_id_list2 *cil)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t requirement = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int penalty_time;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Requirement A */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the handover penalty timer must not run for this bts */</span><br><span style="color: hsl(120, 100%, 40%);">+    penalty_time = conn_penalty_time_remaining(lchan->conn, cil);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (penalty_time) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPHOLCHANTOREMOTE(lchan, cil, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "not a candidate, target BSS still in penalty time"</span><br><span style="color: hsl(120, 100%, 40%);">+                                 " (%u seconds left)\n", penalty_time);</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* compatibility check for codecs -- we have no notion of what the remote BSS supports. We can</span><br><span style="color: hsl(120, 100%, 40%);">+         * only assume that a handover would work, and use only the local requirements. */</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (lchan->tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1:</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (lchan->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+             case GSM_LCHAN_TCH_F: /* mandatory */</span><br><span style="color: hsl(120, 100%, 40%);">+                 requirement |= REQUIREMENT_A_TCHF;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GSM_LCHAN_TCH_H:</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (codec_type_is_supported(lchan->conn, GSM0808_SCT_HR1))</span><br><span style="color: hsl(120, 100%, 40%);">+                         requirement |= REQUIREMENT_A_TCHH;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPHOLCHAN(lchan, LOGL_ERROR, "Unexpected channel type: neither TCH/F nor TCH/H for %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             get_value_string(gsm48_chan_mode_names, lchan->tch_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SPEECH_EFR:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (codec_type_is_supported(lchan->conn, GSM0808_SCT_FR2))</span><br><span style="color: hsl(120, 100%, 40%);">+                 requirement |= REQUIREMENT_A_TCHF;</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (codec_type_is_supported(lchan->conn, GSM0808_SCT_FR3))</span><br><span style="color: hsl(120, 100%, 40%);">+                 requirement |= REQUIREMENT_A_TCHF;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (codec_type_is_supported(lchan->conn, GSM0808_SCT_HR3))</span><br><span style="color: hsl(120, 100%, 40%);">+                 requirement |= REQUIREMENT_A_TCHH;</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPHOLCHAN(lchan, LOGL_DEBUG, "Not even considering: src is not a SPEECH mode lchan\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           /* FIXME: should allow handover of non-speech lchans */</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!requirement) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPHOLCHAN(lchan, LOGL_ERROR, "lchan doesn't fit its own requirements??\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Requirement B and C */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We don't know how many timeslots are free in the remote BSS. We can only indicate that it</span><br><span style="color: hsl(120, 100%, 40%);">+       * would work out and hope for the best. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (requirement & REQUIREMENT_A_TCHF)</span><br><span style="color: hsl(120, 100%, 40%);">+             requirement |= REQUIREMENT_B_TCHF | REQUIREMENT_C_TCHF;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (requirement & REQUIREMENT_A_TCHH)</span><br><span style="color: hsl(120, 100%, 40%);">+             requirement |= REQUIREMENT_B_TCHH | REQUIREMENT_C_TCHH;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* return mask of fulfilled requirements */</span><br><span style="color: hsl(120, 100%, 40%);">+   return requirement;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Trigger handover or assignment depending on the target BTS */</span><br><span> static int trigger_local_ho_or_as(struct ho_candidate *c, uint8_t requirements)</span><br><span> {</span><br><span>@@ -701,12 +771,29 @@</span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int trigger_remote_bss_ho(struct ho_candidate *c, uint8_t requirements)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct handover_out_req req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGPHOLCHANTOREMOTE(c->lchan, c->cil, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "Triggering inter-BSC handover, due to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ho_reason_name(global_ho_reason));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      req = (struct handover_out_req){</span><br><span style="color: hsl(120, 100%, 40%);">+              .from_hodec_id = HODEC2,</span><br><span style="color: hsl(120, 100%, 40%);">+              .old_lchan = c->lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+             .target_nik = c->nik,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+    handover_request(&req);</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int trigger_ho(struct ho_candidate *c, uint8_t requirements)</span><br><span> {</span><br><span>   if (c->bts)</span><br><span>               return trigger_local_ho_or_as(c, requirements);</span><br><span>      else</span><br><span style="color: hsl(0, 100%, 40%);">-            return 0; /* TODO: remote candidates */</span><br><span style="color: hsl(120, 100%, 40%);">+               return trigger_remote_bss_ho(c, requirements);</span><br><span> }</span><br><span> </span><br><span> /* verbosely log about a handover candidate */</span><br><span>@@ -730,6 +817,16 @@</span><br><span>               /* now has to be candidate->requirements & REQUIREMENT_C_TCHX != 0: */ \</span><br><span>              " less-or-equal congestion"))</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!candidate->bts && !candidate->cil)</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPHOLCHAN(lchan, LOGL_DEBUG, "Empty candidate\n");</span><br><span style="color: hsl(120, 100%, 40%);">+        if (candidate->bts && candidate->cil)</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPHOLCHAN(lchan, LOGL_ERROR, "Invalid candidate: both local- and remote-BSS target\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (candidate->cil)</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPHOLCHANTOREMOTE(lchan, candidate->cil, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 "RX level %d -> %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                   rxlev2dbm(rxlev), rxlev2dbm(candidate->avg));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       if (candidate->bts == lchan->ts->trx->bts)</span><br><span>               LOGPHOLCHANTOBTS(lchan, candidate->bts, LOGL_DEBUG,</span><br><span>                    "RX level %d; "</span><br><span>@@ -750,17 +847,20 @@</span><br><span> {</span><br><span>  struct gsm_bts *bts = lchan->ts->trx->bts;</span><br><span>  int tchf_count, tchh_count;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct ho_candidate *c;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ho_candidate c;</span><br><span> </span><br><span>   tchf_count = bts_count_free_ts(bts, GSM_PCHAN_TCH_F);</span><br><span>        tchh_count = bts_count_free_ts(bts, GSM_PCHAN_TCH_H);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       c = &clist[*candidates];</span><br><span style="color: hsl(0, 100%, 40%);">-    c->lchan = lchan;</span><br><span style="color: hsl(0, 100%, 40%);">-    c->bts = bts;</span><br><span style="color: hsl(0, 100%, 40%);">-        c->requirements = check_requirements(lchan, bts, tchf_count, tchh_count);</span><br><span style="color: hsl(0, 100%, 40%);">-    c->avg = av_rxlev;</span><br><span style="color: hsl(0, 100%, 40%);">-   debug_candidate(c, 0, tchf_count, tchh_count);</span><br><span style="color: hsl(120, 100%, 40%);">+        c = (struct ho_candidate){</span><br><span style="color: hsl(120, 100%, 40%);">+            .lchan = lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+               .bts = bts,</span><br><span style="color: hsl(120, 100%, 40%);">+           .requirements = check_requirements(lchan, bts, tchf_count, tchh_count),</span><br><span style="color: hsl(120, 100%, 40%);">+               .avg = av_rxlev,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  debug_candidate(&c, 0, tchf_count, tchh_count);</span><br><span style="color: hsl(120, 100%, 40%);">+   clist[*candidates] = c;</span><br><span>      (*candidates)++;</span><br><span> }</span><br><span> </span><br><span>@@ -771,7 +871,8 @@</span><br><span>                                     int *neighbors_count)</span><br><span> {</span><br><span>    struct gsm_bts *bts = lchan->ts->trx->bts;</span><br><span style="color: hsl(0, 100%, 40%);">-     int tchf_count, tchh_count;</span><br><span style="color: hsl(120, 100%, 40%);">+   int tchf_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int tchh_count = 0;</span><br><span>  struct gsm_bts *neighbor_bts;</span><br><span>        const struct gsm0808_cell_id_list2 *neighbor_cil;</span><br><span>    struct neighbor_ident_key ni = {</span><br><span>@@ -782,6 +883,7 @@</span><br><span>       int avg;</span><br><span>     struct ho_candidate c;</span><br><span>       int min_rxlev;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct handover_cfg *neigh_cfg;</span><br><span> </span><br><span>  /* skip empty slots */</span><br><span>       if (nmp->arfcn == 0)</span><br><span>@@ -799,15 +901,19 @@</span><br><span>      }</span><br><span> </span><br><span>        neighbor_bts = bts_by_neighbor_ident(bts->network, &ni);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!neighbor_bts) {</span><br><span style="color: hsl(0, 100%, 40%);">-            neighbor_cil = neighbor_ident_get(bts->network->neighbor_bss_cells, &ni);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (neighbor_cil) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     LOGPHOBTS(bts, LOGL_ERROR, "would inter-BSC handover to ARFCN %u BSIC %u,"</span><br><span style="color: hsl(0, 100%, 40%);">-                              " but inter-BSC handover not implemented for ho decision 2\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                nmp->arfcn, nmp->bsic);</span><br><span style="color: hsl(0, 100%, 40%);">-                 return;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ neighbor_cil = neighbor_ident_get(bts->network->neighbor_bss_cells, &ni);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (neighbor_bts && neighbor_cil) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPHOBTS(bts, LOGL_ERROR, "Configuration error: %s exists as both local"</span><br><span style="color: hsl(120, 100%, 40%);">+                     " neighbor (bts %u) and remote-BSS neighbor (%s). Will consider only"</span><br><span style="color: hsl(120, 100%, 40%);">+                       " the local-BSS neighbor.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       neighbor_ident_key_name(&ni),</span><br><span style="color: hsl(120, 100%, 40%);">+                     neighbor_bts->nr, gsm0808_cell_id_list_name(neighbor_cil));</span><br><span style="color: hsl(120, 100%, 40%);">+              neighbor_cil = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!neighbor_bts && !neighbor_cil) {</span><br><span>                LOGPHOBTS(bts, LOGL_DEBUG, "no neighbor ARFCN %u BSIC %u configured for this cell\n",</span><br><span>                        nmp->arfcn, nmp->bsic);</span><br><span>              return;</span><br><span>@@ -819,13 +925,19 @@</span><br><span>              return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* For cells in a remote BSS, we cannot query the target cell's handover config, and hence</span><br><span style="color: hsl(120, 100%, 40%);">+         * instead assume the local BTS' config to apply. */</span><br><span style="color: hsl(120, 100%, 40%);">+      neigh_cfg = (neighbor_bts ? : bts)->ho;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         /* calculate average rxlev for this cell over the window */</span><br><span>  avg = neigh_meas_avg(nmp, ho_get_hodec2_rxlev_neigh_avg_win(bts->ho));</span><br><span> </span><br><span>        c = (struct ho_candidate){</span><br><span>           .lchan = lchan,</span><br><span>              .avg = avg,</span><br><span style="color: hsl(120, 100%, 40%);">+           .nik = ni,</span><br><span>           .bts = neighbor_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+          .cil = neighbor_cil,</span><br><span>         };</span><br><span> </span><br><span>       /* Heed rxlev hysteresis only if the RXLEV/RXQUAL/TA levels of the MS aren't critically bad and</span><br><span>@@ -842,8 +954,9 @@</span><br><span>            }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* if the minimum level is not reached */</span><br><span style="color: hsl(0, 100%, 40%);">-       min_rxlev = ho_get_hodec2_min_rxlev(neighbor_bts->ho);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* if the minimum level is not reached.</span><br><span style="color: hsl(120, 100%, 40%);">+        * In case of a remote-BSS, use the current BTS' configuration. */</span><br><span style="color: hsl(120, 100%, 40%);">+        min_rxlev = ho_get_hodec2_min_rxlev(neigh_cfg);</span><br><span>      if (rxlev2dbm(avg) < min_rxlev) {</span><br><span>                 LOGPHOCAND(&c, LOGL_DEBUG,</span><br><span>                          "Not a candidate, because RX level (%d) is lower"</span><br><span>@@ -852,9 +965,13 @@</span><br><span>                return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   tchf_count = bts_count_free_ts(neighbor_bts, GSM_PCHAN_TCH_F);</span><br><span style="color: hsl(0, 100%, 40%);">-  tchh_count = bts_count_free_ts(neighbor_bts, GSM_PCHAN_TCH_H);</span><br><span style="color: hsl(0, 100%, 40%);">-  c.requirements = check_requirements(lchan, neighbor_bts, tchf_count, tchh_count);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (neighbor_bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+           tchf_count = bts_count_free_ts(neighbor_bts, GSM_PCHAN_TCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+                tchh_count = bts_count_free_ts(neighbor_bts, GSM_PCHAN_TCH_H);</span><br><span style="color: hsl(120, 100%, 40%);">+                c.requirements = check_requirements(lchan, neighbor_bts, tchf_count,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              tchh_count);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else</span><br><span style="color: hsl(120, 100%, 40%);">+                c.requirements = check_requirements_remote_bss(lchan, neighbor_cil);</span><br><span> </span><br><span>     debug_candidate(&c, av_rxlev, tchf_count, tchh_count);</span><br><span> </span><br><span>@@ -988,13 +1105,19 @@</span><br><span>              return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* select best candidate that fulfills requirement B: no congestion after HO */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* select best candidate that fulfills requirement B: no congestion after HO.</span><br><span style="color: hsl(120, 100%, 40%);">+  * Exclude remote-BSS neighbors: to avoid oscillation between neighboring BSS,</span><br><span style="color: hsl(120, 100%, 40%);">+         * rather keep subscribers in the local BSS unless there is critical RXLEV/TA. */</span><br><span>    best_better_db = 0;</span><br><span>  for (i = 0; i < candidates; i++) {</span><br><span>                int afs_bias;</span><br><span>                if (!(clist[i].requirements & REQUIREMENT_B_MASK))</span><br><span>                       continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         /* Only consider Local-BSS cells */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!clist[i].bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          better = clist[i].avg - av_rxlev;</span><br><span>            /* Apply AFS bias? */</span><br><span>                afs_bias = 0;</span><br><span>@@ -1016,13 +1139,18 @@</span><br><span>              return trigger_ho(best_cand, best_cand->requirements & REQUIREMENT_B_MASK);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* select best candidate that fulfills requirement C: less or equal congestion after HO */</span><br><span style="color: hsl(120, 100%, 40%);">+    /* select best candidate that fulfills requirement C: less or equal congestion after HO,</span><br><span style="color: hsl(120, 100%, 40%);">+       * again excluding remote-BSS neighbors. */</span><br><span>  best_better_db = 0;</span><br><span>  for (i = 0; i < candidates; i++) {</span><br><span>                int afs_bias;</span><br><span>                if (!(clist[i].requirements & REQUIREMENT_C_MASK))</span><br><span>                       continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         /* Only consider Local-BSS cells */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!clist[i].bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          better = clist[i].avg - av_rxlev;</span><br><span>            /* Apply AFS bias? */</span><br><span>                afs_bias = 0;</span><br><span>@@ -1052,7 +1180,8 @@</span><br><span> </span><br><span>    /* Select best candidate that fulfills requirement A: can service the call.</span><br><span>   * From above we know that there are no options that avoid congestion. Here we're trying to find</span><br><span style="color: hsl(0, 100%, 40%);">-     * *any* free lchan that has no critically low RXLEV and is able to handle the MS. */</span><br><span style="color: hsl(120, 100%, 40%);">+  * *any* free lchan that has no critically low RXLEV and is able to handle the MS.</span><br><span style="color: hsl(120, 100%, 40%);">+     * We're also prepared to handover to remote BSS. */</span><br><span>     best_better_db = 0;</span><br><span>  for (i = 0; i < candidates; i++) {</span><br><span>                int afs_bias;</span><br><span>@@ -1060,9 +1189,11 @@</span><br><span>                       continue;</span><br><span> </span><br><span>                better = clist[i].avg - av_rxlev;</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Apply AFS bias? */</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Apply AFS bias?</span><br><span style="color: hsl(120, 100%, 40%);">+             * (never to remote-BSS neighbors, since we will not change the lchan type for those.) */</span><br><span>            afs_bias = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-           if (ahs && (clist[i].requirements & REQUIREMENT_A_TCHF))</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ahs && (clist[i].requirements & REQUIREMENT_A_TCHF)</span><br><span style="color: hsl(120, 100%, 40%);">+               && clist[i].bts)</span><br><span>                         afs_bias = ho_get_hodec2_afs_bias_rxlev(clist[i].bts->ho);</span><br><span>                better += afs_bias;</span><br><span>          if (better > best_better_db) {</span><br><span>@@ -1385,6 +1516,14 @@</span><br><span>           if (!clist[i].lchan)</span><br><span>                         continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         /* Do not resolve congestion towards remote BSS, which would cause oscillation if the</span><br><span style="color: hsl(120, 100%, 40%);">+          * remote BSS is also congested. */</span><br><span style="color: hsl(120, 100%, 40%);">+           /* TODO: attempt inter-BSC HO if no local cells qualify, and rely on the remote BSS to</span><br><span style="color: hsl(120, 100%, 40%);">+                 * deny receiving the handover if it also considers itself congested. Maybe do that only</span><br><span style="color: hsl(120, 100%, 40%);">+               * when the cell is absolutely full, i.e. not only min-free-slots. (x) */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!clist[i].bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          if (!(clist[i].requirements & REQUIREMENT_B_MASK))</span><br><span>                       continue;</span><br><span>            /* omit assignment from AHS to AFS */</span><br><span>@@ -1462,6 +1601,12 @@</span><br><span>                       if (!clist[i].lchan)</span><br><span>                                 continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                 /* Do not resolve congestion towards remote BSS, which would cause oscillation if</span><br><span style="color: hsl(120, 100%, 40%);">+                      * the remote BSS is also congested. */</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* TODO: see (x) above */</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!clist[i].bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                            continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  if (!(clist[i].requirements & REQUIREMENT_B_MASK))</span><br><span>                               continue;</span><br><span>                    /* omit all but assignment from AHS to AFS */</span><br><span>@@ -1524,6 +1669,12 @@</span><br><span>               if (!clist[i].lchan)</span><br><span>                         continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         /* Do not resolve congestion towards remote BSS, which would cause oscillation if</span><br><span style="color: hsl(120, 100%, 40%);">+              * the remote BSS is also congested. */</span><br><span style="color: hsl(120, 100%, 40%);">+               /* TODO: see (x) above */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!clist[i].bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          if (!(clist[i].requirements & REQUIREMENT_C_MASK))</span><br><span>                       continue;</span><br><span>            /* omit assignment from AHS to AFS */</span><br><span>@@ -1602,6 +1753,12 @@</span><br><span>                       if (!clist[i].lchan)</span><br><span>                                 continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                 /* Do not resolve congestion towards remote BSS, which would cause oscillation if</span><br><span style="color: hsl(120, 100%, 40%);">+                      * the remote BSS is also congested. */</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* TODO: see (x) above */</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!clist[i].bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                            continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  if (!(clist[i].requirements & REQUIREMENT_C_MASK))</span><br><span>                               continue;</span><br><span>                    /* omit all but assignment from AHS to AFS */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/11321">change 11321</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/11321"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Id78ac1b2016998a2931a23d62ec7a3f37bb764c6 </div>
<div style="display:none"> Gerrit-Change-Number: 11321 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>