<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/25996">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  pespin: Looks good to me, but someone else must approve
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">bsc_ctrl_commands: change neighbor-list mode/arfcn via control interface<br><br>It is possible to change the neighbor-list mode via the VTY from<br>automatic mode to manual neighbor-list configuration. In the manual<br>mode, the user can add ARFCN values manually. This command can be found<br>under the bts node. Lets add pendant of this command on the control<br>interface as well.<br><br>Change-Id: Id97bc0d31a358db6221c385761773fb48670c921<br>Related: SYS#5641<br>---<br>M doc/manuals/chapters/control.adoc<br>M src/osmo-bsc/bsc_ctrl_commands.c<br>M tests/ctrl_test_runner.py<br>3 files changed, 160 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/doc/manuals/chapters/control.adoc b/doc/manuals/chapters/control.adoc</span><br><span>index 091cdc6..695dd80 100644</span><br><span>--- a/doc/manuals/chapters/control.adoc</span><br><span>+++ b/doc/manuals/chapters/control.adoc</span><br><span>@@ -68,6 +68,9 @@</span><br><span> |[bts.N.]handover2.penalty-time.failed-assignment|RW|No|<0-99999>,"default"|Time to suspend handover for a subscriber after a failed re-assignment within this cell.</span><br><span> |[bts.N.]handover2.retries|RW|No|<0-9>,"default"|Number of times to immediately retry a failed handover/assignment, before a penalty time is applied.</span><br><span> |handover2.congestion-check|RW|No|"disabled",<1-999>,"now"|Congestion check interval in seconds, "now" triggers immediate congestion check.</span><br><span style="color: hsl(120, 100%, 40%);">+|bts.N.neighbor-list.mode|WO|No|"automatic","manual","manual-si5"|Mode of Neighbor List generation.</span><br><span style="color: hsl(120, 100%, 40%);">+|bts.N.neighbor-list.add|WO|No|<0-1023>|Add to manual neighbor list.</span><br><span style="color: hsl(120, 100%, 40%);">+|bts.N.neighbor-list.del|WO|No|<0-1023>|Delete from manual neighbor list.</span><br><span> |===</span><br><span> </span><br><span> [[notif]]</span><br><span>diff --git a/src/osmo-bsc/bsc_ctrl_commands.c b/src/osmo-bsc/bsc_ctrl_commands.c</span><br><span>index 0affee0..f379bd2 100644</span><br><span>--- a/src/osmo-bsc/bsc_ctrl_commands.c</span><br><span>+++ b/src/osmo-bsc/bsc_ctrl_commands.c</span><br><span>@@ -668,6 +668,120 @@</span><br><span> </span><br><span> CTRL_CMD_DEFINE(bts_c0_power_red, "c0-power-reduction");</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int verify_bts_neighbor_list_add_del(struct ctrl_cmd *cmd, const char *value, void *_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (osmo_str_to_int(&arfcn, value, 10, 0, 1023) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         cmd->reply = "Invalid ARFCN value";</span><br><span style="color: hsl(120, 100%, 40%);">+              return 1;</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%);">+   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%);">+static int set_bts_neighbor_list_add_del(struct ctrl_cmd *cmd, void *data, bool add)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *bts = cmd->node;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct bitvec *bv = &bts->si_common.neigh_list;</span><br><span style="color: hsl(120, 100%, 40%);">+        int arfcn_int;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum gsm_band unused;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (osmo_str_to_int(&arfcn_int, cmd->value, 10, 0, 1023) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             cmd->reply = "Failed to parse ARFCN value";</span><br><span style="color: hsl(120, 100%, 40%);">+              return CTRL_CMD_ERROR;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     arfcn = (uint16_t) arfcn_int;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bts->neigh_list_manual_mode == NL_MODE_AUTOMATIC) {</span><br><span style="color: hsl(120, 100%, 40%);">+            cmd->reply = "Neighbor list not in manual mode";</span><br><span style="color: hsl(120, 100%, 40%);">+         return CTRL_CMD_ERROR;</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 (gsm_arfcn2band_rc(arfcn, &unused) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           cmd->reply = "Invalid arfcn detected";</span><br><span style="color: hsl(120, 100%, 40%);">+           return CTRL_CMD_ERROR;</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 (add)</span><br><span style="color: hsl(120, 100%, 40%);">+              bitvec_set_bit_pos(bv, arfcn, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          bitvec_set_bit_pos(bv, arfcn, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   cmd->reply = "OK";</span><br><span style="color: hsl(120, 100%, 40%);">+       return CTRL_CMD_REPLY;</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%);">+static int verify_bts_neighbor_list_add(struct ctrl_cmd *cmd, const char *value, void *_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return verify_bts_neighbor_list_add_del(cmd, value, _data);</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%);">+static int set_bts_neighbor_list_add(struct ctrl_cmd *cmd, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return set_bts_neighbor_list_add_del(cmd, data, true);</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%);">+CTRL_CMD_DEFINE_WO(bts_neighbor_list_add, "neighbor-list add");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int verify_bts_neighbor_list_del(struct ctrl_cmd *cmd, const char *value, void *_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return verify_bts_neighbor_list_add_del(cmd, value, _data);</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%);">+static int set_bts_neighbor_list_del(struct ctrl_cmd *cmd, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return set_bts_neighbor_list_add_del(cmd, data, false);</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%);">+CTRL_CMD_DEFINE_WO(bts_neighbor_list_del, "neighbor-list del");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int verify_bts_neighbor_list_mode(struct ctrl_cmd *cmd, const char *value, void *_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!strcmp(value, "automatic"))</span><br><span style="color: hsl(120, 100%, 40%);">+            return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!strcmp(value, "manual"))</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!strcmp(value, "manual-si5"))</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%);">+   cmd->reply = "Invalid mode";</span><br><span style="color: hsl(120, 100%, 40%);">+     return 1;</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%);">+static int set_bts_neighbor_list_mode(struct ctrl_cmd *cmd, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm_bts *bts = cmd->node;</span><br><span style="color: hsl(120, 100%, 40%);">+   int mode;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!strcmp(cmd->value, "automatic"))</span><br><span style="color: hsl(120, 100%, 40%);">+            mode = NL_MODE_AUTOMATIC;</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (!strcmp(cmd->value, "manual"))</span><br><span style="color: hsl(120, 100%, 40%);">+          mode = NL_MODE_MANUAL;</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (!strcmp(cmd->value, "manual-si5"))</span><br><span style="color: hsl(120, 100%, 40%);">+              mode = NL_MODE_MANUAL_SI5SEP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case NL_MODE_MANUAL_SI5SEP:</span><br><span style="color: hsl(120, 100%, 40%);">+   case NL_MODE_MANUAL:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* make sure we clear the current list when switching to</span><br><span style="color: hsl(120, 100%, 40%);">+               * manual mode */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (bts->neigh_list_manual_mode == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                      memset(&bts->si_common.data.neigh_list, 0, sizeof(bts->si_common.data.neigh_list));</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%);">+              break;</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%);">+   bts->neigh_list_manual_mode = mode;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      cmd->reply = "OK";</span><br><span style="color: hsl(120, 100%, 40%);">+       return CTRL_CMD_REPLY;</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%);">+CTRL_CMD_DEFINE_WO(bts_neighbor_list_mode, "neighbor-list mode");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int bsc_base_ctrl_cmds_install(void)</span><br><span> {</span><br><span>      int rc = 0;</span><br><span>@@ -692,6 +806,9 @@</span><br><span>    rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_state);</span><br><span>        rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_states);</span><br><span>       rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_c0_power_red);</span><br><span style="color: hsl(120, 100%, 40%);">+     rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_neighbor_list_add);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_neighbor_list_del);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_neighbor_list_mode);</span><br><span> </span><br><span>  rc |= neighbor_ident_ctrl_init();</span><br><span> </span><br><span>diff --git a/tests/ctrl_test_runner.py b/tests/ctrl_test_runner.py</span><br><span>index 5e9bcef..4c07d5e 100755</span><br><span>--- a/tests/ctrl_test_runner.py</span><br><span>+++ b/tests/ctrl_test_runner.py</span><br><span>@@ -525,6 +525,46 @@</span><br><span>         self.assertEqual(r['var'], 'apply-config-file')</span><br><span>         self.assertEqual(r['value'], 'OK')</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    def testNeighborList(self):</span><br><span style="color: hsl(120, 100%, 40%);">+   # Enter manual neighbor-list mode</span><br><span style="color: hsl(120, 100%, 40%);">+        r = self.do_set('bts.0.neighbor-list.mode', 'manual')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('respose: ' + str(r))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['mtype'], 'SET_REPLY')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['var'], 'bts.0.neighbor-list.mode')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['value'], 'OK')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # Add an ARFCN</span><br><span style="color: hsl(120, 100%, 40%);">+        r = self.do_set('bts.0.neighbor-list.add', '123')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('respose: ' + str(r))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['mtype'], 'SET_REPLY')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['var'], 'bts.0.neighbor-list.add')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['value'], 'OK')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # Delete the ARFCN again</span><br><span style="color: hsl(120, 100%, 40%);">+        r = self.do_set('bts.0.neighbor-list.del', '123')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('respose: ' + str(r))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['mtype'], 'SET_REPLY')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['var'], 'bts.0.neighbor-list.del')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['value'], 'OK')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      # Go back to automatic neighbor-list mode</span><br><span style="color: hsl(120, 100%, 40%);">+        r = self.do_set('bts.0.neighbor-list.mode', 'automatic')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('respose: ' + str(r))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['mtype'], 'SET_REPLY')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['var'], 'bts.0.neighbor-list.mode')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['value'], 'OK')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     # This must not work as we are in automatic neighbor-list mode</span><br><span style="color: hsl(120, 100%, 40%);">+        r = self.do_set('bts.0.neighbor-list.add', '123')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('respose: ' + str(r))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['mtype'], 'ERROR')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['error'], 'Neighbor list not in manual mode')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     # Try an invalid neighbor-list mode</span><br><span style="color: hsl(120, 100%, 40%);">+        r = self.do_set('bts.0.neighbor-list.mode', 'qwertzuiop')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('respose: ' + str(r))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['mtype'], 'ERROR')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.assertEqual(r['error'], 'Invalid mode')</span><br><span> </span><br><span> class TestCtrlBSCNeighbor(TestCtrlBase):</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/25996">change 25996</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/c/osmo-bsc/+/25996"/><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-Change-Id: Id97bc0d31a358db6221c385761773fb48670c921 </div>
<div style="display:none"> Gerrit-Change-Number: 25996 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>