Commit 80017f8c authored by Kirill Smelkov's avatar Kirill Smelkov

software/ors-amarisoft: enb/generic: Switch configuration of RU, cell, peer...

software/ors-amarisoft: enb/generic: Switch configuration of RU, cell, peer and peercell to shared instances

Previously we had cell_list, ncell_list and peers parameters and we now remove
them and rework the software release to accept configuration for said objects
via shared instances. In other words now it is possible to add Radio Units,
cells, peers and peer cells on on top of main eNB service.

Schema for parameters of those shared instances is based on what we just recently
generalized and established in ru/ cell/ peer/ and peer/cell/ input schemas. We
only add cell_kind=enb|enb_peer addition field to be able to distinguish a cell
from peercell object, and we add a way for cell to reference RU one way or another.

RU-CELL relation is no longer 1-1: one RU can be generally serving multiple
cells. For example transmission bandwidth of SDR100 board is ~ 100MHz while
bandwidth of one LTE cell is max 20MHz. This way it is possible to put several
cells whose frequencies are nearby each other to be run on the same SDR
board(*). And in general one Radio Unit can be serving transmission/reception in
multiple frequency ranges, thus providing ability for multiple cells to be
served by RU. This way RU is split off from CELL object and each CELL needs to
say which RU object it wants to use.

There are 3 ways to configure CELL->RU links:

1. CELL references a RU object. This is the most general.
2. CELL embeds definition of RU object. This variant is provided for simplicity
   of management for users that do not want to split CELL/RU relations.
3. CELL2 references another cell object and says to use the same RU as CELL1.
   Again, this variant is provided for simplicity of management when users want to
   add a cell on top of same RU when they already started with "2".

Full backward compatibility is provided for ORS. For this instance-ors-enb.jinja2.cfg
is adjusted to inject synthetic RU/CELL/PEER/PEERCELL shared instances instead
of translating to slapparameter_dict. As the result for ORS users it works
without visible change as parameters with original ORS schema are handled as expected.

Rendered files for ORS also stay practically the same as before this patch.

The main change is in slaplte.jinja2 - in the loading routines. The other
changes are mostly straightforward adaptation because details of how ru_dict,
cell_dict, peer_dict and peercell_dict are loaded were already localized to
slaplte and the rest of the code independent from that.

Now, once we switched to shared instances, we will be finally able to add tests
for updated enb. Please see a soon follow-up patch for that.

And for existing test_ors.py we also temporary workaround breakage of tests,
because currently generic code does not handle well special characters in
partition references. For example it currently breaks on spaces with buildout
complaining that sections with spaces in their name are invalid. We will fix
that in another soon-followup patch as well, but apply a workaround for now.

(*) see https://tech-academy.amarisoft.com/SDR_MultiCell_OneSdr.html for details.

--------

Appendix. Diff for rendered ORS enb.cfg and gnb.cfg before and after this patch:

```
$ ./pythonwitheggs slapos-render-config.py && xdiff config/{old,out}
```

```diff
diff --git a/config/old/ors/enb/enb.cfg b/config/out/ors/enb/enb.cfg
index 15f3b68e9..6046d366e 100644
--- a/config/old/ors/enb/enb.cfg
+++ b/config/out/ors/enb/enb.cfg
@@ -6,7 +6,7 @@

   // Radio Units
   rf_driver: {
-      // CELL-RU 2T2R  (sdr)
+      // RU 2T2R  (sdr)
       name: "sdr",
       args: "dev0=/dev/sdr0",
       rx_antenna:"tx_rx",
@@ -28,7 +28,7 @@
   // LTE cells
   cell_list: [

-    // CELL  (CELL-RU)
+    // CELL  (RU)
     {
       rf_port:      0,
       n_antenna_dl: 2,
@@ -46,7 +46,7 @@
         // Inter-ENB HO
         {
           rat:          "eutra",
-          cell_id:      0x12345,  // -> 1
+          cell_id:      0x12345,  // -> PEERCELL1
           n_id_cell:    35,
           dl_earfcn:    700,
           tac:          123,
diff --git a/config/old/ors/gnb/enb.cfg b/config/out/ors/gnb/enb.cfg
index ac564db6c..9473f3207 100644
--- a/config/old/ors/gnb/enb.cfg
+++ b/config/out/ors/gnb/enb.cfg
@@ -6,7 +6,7 @@

   // Radio Units
   rf_driver: {
-      // CELL-RU 2T2R  (sdr)
+      // RU 2T2R  (sdr)
       name: "sdr",
       args: "dev0=/dev/sdr0",
       rx_antenna:"tx_rx",
@@ -35,7 +35,7 @@
   // NR cells
   nr_cell_list: [

-      // CELL  (CELL-RU)
+      // CELL  (RU)
       {
         rf_port:      0,
         n_antenna_dl: 2,
@@ -58,7 +58,7 @@
         // Inter-ENB HO
         {
           rat:          "nr",
-          nr_cell_id:   0x77712, // -> 1
+          nr_cell_id:   0x77712, // -> PEERCELL2
           gnb_id_bits:  22,
           n_id_cell:    75,
           dl_nr_arfcn:  520000,
```
parent 69602afe
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
"type": "string", "type": "string",
"options": { "hidden": true } "options": { "hidden": true }
}, },
"cell_kind": {
"type": "string",
"const": "enb",
"template": "enb",
"options": { "hidden": true }
},
"rf_mode": { "rf_mode": {
"title": "RF mode", "title": "RF mode",
...@@ -52,8 +58,53 @@ ...@@ -52,8 +58,53 @@
"default": 10000 "default": 10000
}, },
"ru": { "ru": {
"$ref": "../ru/input-schema.json", "$ref": "#/$defs/ru-of-cell",
"propertyOrder": 9999 "propertyOrder": 9999
} }
},
"$defs": {
"ru-of-cell": {
"title": "Radio Unit",
"oneOf": [
{
"title": "Shared Radio Unit",
"description": "Use radio unit defined in separate shared instance",
"type": "object",
"required": ["ru_type", "ru_ref"],
"properties": {
"ru_type": {
"const": "ru_ref",
"template": "ru_ref",
"options": { "hidden": true }
},
"ru_ref": {
"title": "RU Reference",
"description": "Reference of shared radio unit instance",
"type": "string"
}
}
},
{
"title": "Shared Radio Unit of a Cell",
"description": "Use the same radio unit as referenced cell instance does",
"type": "object",
"required": ["ru_type", "ruincell_ref"],
"properties": {
"ru_type": {
"const": "ruincell_ref",
"template": "ruincell_ref",
"options": { "hidden": true }
},
"ruincell_ref": {
"title": "Cell Reference",
"description": "Reference of cell instance whose radio unit to share",
"type": "string"
}
}
},
{ "$ref": "../ru/input-schema.json" }
]
}
} }
} }
{%- import 'slaplte.jinja2' as slaplte with context %} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- set J = slaplte.J %} {%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set ierror = slaplte.ierror %} {%- set ierror = slaplte.ierror %}
{%- set bug = slaplte.bug %} {%- set bug = slaplte.bug %}
{#- for standalone testing via slapos-render-config.py {#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with instance-enb.jinja2.cfg and ru/libinstance.jinja2.cfg #} NOTE: keep in sync with instance-enb.jinja2.cfg and ru/libinstance.jinja2.cfg #}
{%- if _standalone is defined %} {%- if _standalone is defined %}
{%- set ru_dict = {} %} {%- set iru_dict = {} %}
{%- set cell_dict = {} %} {%- set icell_dict = {} %}
{%- set peer_dict = {} %} {%- set ipeer_dict = {} %}
{%- set peercell_dict = {} %} {%- set ipeercell_dict = {} %}
{%- do slaplte.load_ru_and_cell(ru_dict, cell_dict) %} {%- do slaplte.load_iru_and_icell(iru_dict, icell_dict) %}
{%- do slaplte.load_peer(peer_dict) %} {%- do slaplte.load_ipeer(ipeer_dict) %}
{%- do slaplte.load_peercell(peercell_dict) %} {%- do slaplte.load_ipeercell(ipeercell_dict) %}
{%- do slaplte.check_loaded_everything() %}
{%- endif %} {%- endif %}
{#- do_lte/do_nr indicate whether we have LTE and/or NR cells {#- do_lte/do_nr indicate whether we have LTE and/or NR cells
cell_dict_lte/cell_dict_nr keep LTE/NR parts of cell_dict registry #} icell_dict_lte/icell_dict_nr keep LTE/NR parts of icell_dict registry #}
{%- set cell_dict_lte = dict(cell_dict|dictsort | selectattr('1.cell_type', '==', 'lte')) %} {%- set icell_dict_lte = dict(icell_dict|dictsort | selectattr('1._.cell_type', '==', 'lte')) %}
{%- set cell_dict_nr = dict(cell_dict|dictsort | selectattr('1.cell_type', '==', 'nr' )) %} {%- set icell_dict_nr = dict(icell_dict|dictsort | selectattr('1._.cell_type', '==', 'nr' )) %}
{%- set do_lte = len(cell_dict_lte) > 0 %} {%- set do_lte = len(icell_dict_lte) > 0 %}
{%- set do_nr = len(cell_dict_nr) > 0 %} {%- set do_nr = len(icell_dict_nr) > 0 %}
{#- handover_config emits handover configuration #} {#- handover_config emits handover configuration #}
...@@ -31,7 +33,8 @@ ...@@ -31,7 +33,8 @@
{#- TODO: add info about peers as shared instances - one instance per peer *ENB*. {#- TODO: add info about peers as shared instances - one instance per peer *ENB*.
then query SlapOS Master about cells configured on that peer ENB and then query SlapOS Master about cells configured on that peer ENB and
put them as peers here #} put them as peers here #}
{%- for peercell_ref, ncell in peercell_dict|dictsort %} {%- for peercell_ref, ipeercell in ipeercell_dict|dictsort %}
{%- set ncell = ipeercell['_'] %}
{ {
{%- if ncell.cell_type == 'lte' %} {%- if ncell.cell_type == 'lte' %}
rat: "eutra", rat: "eutra",
...@@ -107,7 +110,7 @@ ...@@ -107,7 +110,7 @@
log_filename: "{{ directory['log'] }}/enb.log", log_filename: "{{ directory['log'] }}/enb.log",
{# instantiate radio units #} {# instantiate radio units #}
{{ slaplte.ru_config(ru_dict, slapparameter_dict) }} {{ slaplte.ru_config(iru_dict, slapparameter_dict) }}
{%- if slapparameter_dict.get('websocket_password', '') %} {%- if slapparameter_dict.get('websocket_password', '') %}
com_addr: "[{{ gtp_addr_v6 }}]:{{ slapparameter_dict.com_ws_port }}", com_addr: "[{{ gtp_addr_v6 }}]:{{ slapparameter_dict.com_ws_port }}",
...@@ -177,13 +180,13 @@ ...@@ -177,13 +180,13 @@
then query SlapOS Master about cells configured on that peer ENB and then query SlapOS Master about cells configured on that peer ENB and
depending on whether LTE and/or NR cells are there add X2 and/or Xn peers #} depending on whether LTE and/or NR cells are there add X2 and/or Xn peers #}
{%- if do_lte %} {%- if do_lte %}
x2_peers: {{ peer_dict|dictsort | selectattr('1.peer_type', '==', 'lte') x2_peers: {{ ipeer_dict|dictsort | selectattr('1._.peer_type', '==', 'lte')
| map(attribute='1.x2_addr') | map(attribute='1._.x2_addr')
| list | tojson }}, | list | tojson }},
{%- endif %} {%- endif %}
{%- if do_nr %} {%- if do_nr %}
xn_peers: {{ peer_dict|dictsort | selectattr('1.peer_type', '==', 'nr') xn_peers: {{ ipeer_dict|dictsort | selectattr('1._.peer_type', '==', 'nr')
| map(attribute='1.xn_addr') | map(attribute='1._.xn_addr')
| list | tojson }}, | list | tojson }},
{%- endif %} {%- endif %}
...@@ -200,9 +203,11 @@ ...@@ -200,9 +203,11 @@
// LTE cells // LTE cells
cell_list: [ cell_list: [
{%- if do_lte %} {%- if do_lte %}
{%- for cell_ref, cell in cell_dict_lte|dictsort %} {%- for cell_ref, icell in icell_dict_lte|dictsort %}
{%- set ru_ref = cell.ru_ref %} {%- set cell = icell['_'] %}
{%- set ru = ru_dict[ru_ref] %} {%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ cell_ref }} ({{ ru_ref }}) // {{ cell_ref }} ({{ ru_ref }})
{ {
...@@ -222,7 +227,8 @@ ...@@ -222,7 +227,8 @@
// Carrier Aggregation // Carrier Aggregation
scell_list: [ scell_list: [
{%- for cell2_ref, cell2 in cell_dict_lte|dictsort %} {%- for cell2_ref, icell2 in icell_dict_lte|dictsort %}
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref %} {%- if cell2_ref != cell_ref %}
{ {
cell_id: {{ cell2.cell_id }}, // + {{ cell2_ref }} cell_id: {{ cell2.cell_id }}, // + {{ cell2_ref }}
...@@ -264,11 +270,11 @@ ...@@ -264,11 +270,11 @@
n1_pucch_sr_count: 11, n1_pucch_sr_count: 11,
cqi_pucch_n_rb: 1, cqi_pucch_n_rb: 1,
{#- for CA with 2 cells it is possible to use PUCCH 1b CS ack/nack #} {#- for CA with 2 cells it is possible to use PUCCH 1b CS ack/nack #}
{%- if len(cell_dict_lte) == 2 %} {%- if len(icell_dict_lte) == 2 %}
ack_nack_feedback_mode_ca: "cs", ack_nack_feedback_mode_ca: "cs",
n1_pucch_an_cs_count: 8, n1_pucch_an_cs_count: 8,
{#- starting from 3 cells it is always PUCCH 3 for ack/nack in CA #} {#- starting from 3 cells it is always PUCCH 3 for ack/nack in CA #}
{%- elif len(cell_dict_lte) >= 3 %} {%- elif len(icell_dict_lte) >= 3 %}
ack_nack_feedback_mode_ca: "pucch3", ack_nack_feedback_mode_ca: "pucch3",
n3_pucch_an_n_rb: 3, n3_pucch_an_n_rb: 3,
{%- endif %} {%- endif %}
...@@ -417,9 +423,11 @@ ...@@ -417,9 +423,11 @@
{% if do_nr %} {% if do_nr %}
// NR cells // NR cells
nr_cell_list: [ nr_cell_list: [
{%- for cell_ref, cell in cell_dict_nr|dictsort %} {%- for cell_ref, icell in icell_dict_nr|dictsort %}
{%- set ru_ref = cell.ru_ref %} {%- set cell = icell['_'] %}
{%- set ru = ru_dict[ru_ref] %} {%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ cell_ref }} ({{ ru_ref }}) // {{ cell_ref }} ({{ ru_ref }})
{ {
...@@ -561,7 +569,7 @@ ...@@ -561,7 +569,7 @@
bitmap: "110011", bitmap: "110011",
cdm_type: "fd_cdm2", cdm_type: "fd_cdm2",
{%- else %} {%- else %}
{%- do error('n_antenna_dl=%d is not supported' % ru.n_antenna_dl) %} {%- do ierror(iru, 'n_antenna_dl=%d is not supported' % ru.n_antenna_dl) %}
{%- endif %} {%- endif %}
}, },
{%- if tdd_config != 3 %} {%- if tdd_config != 3 %}
......
...@@ -3,17 +3,6 @@ ...@@ -3,17 +3,6 @@
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"cell_list": {
"title": "Cell List",
"description": "Cell List",
"patternProperties": {
".*": {
"$ref": "cell/input-schema.json"
}
},
"type": "object",
"default": {}
},
"user-authorized-key": { "user-authorized-key": {
"title": "User Authorized Key", "title": "User Authorized Key",
"description": "SSH public key in order to connect to the SSH server of this instance.", "description": "SSH public key in order to connect to the SSH server of this instance.",
...@@ -161,28 +150,6 @@ ...@@ -161,28 +150,6 @@
"type": "object", "type": "object",
"default": {} "default": {}
}, },
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"$ref": "peer/cell/input-schema.json"
}
},
"type": "object",
"default": {}
},
"peers": {
"title": "Peers",
"description": "Peers",
"patternProperties": {
".*": {
"$ref": "peer/input-schema.json"
}
},
"type": "object",
"default": {}
},
"websocket_password": { "websocket_password": {
"title": "Websocket password", "title": "Websocket password",
"description": "Activates websocket for remote control and sets password", "description": "Activates websocket for remote control and sets password",
......
...@@ -8,8 +8,6 @@ ...@@ -8,8 +8,6 @@
'use_ipv4': False, 'use_ipv4': False,
'gnb_id_bits': 28, 'gnb_id_bits': 28,
'nssai': {'1': {'sst': 1}}, 'nssai': {'1': {'sst': 1}},
"ncell_list": {},
"peers": {},
} %} } %}
{%- set gtp_addr_lo = '127.0.1.1' %} {%- set gtp_addr_lo = '127.0.1.1' %}
{%- for k,v in enb_defaults|dictsort %} {%- for k,v in enb_defaults|dictsort %}
...@@ -37,10 +35,11 @@ offline = true ...@@ -37,10 +35,11 @@ offline = true
{%- import 'slaplte.jinja2' as slaplte with context %} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- import 'ru_libinstance.jinja2.cfg' as rulib with context %} {%- import 'ru_libinstance.jinja2.cfg' as rulib with context %}
{%- set peer_dict = {} %} {%- set ipeer_dict = {} %}
{%- set peercell_dict = {} %} {%- set ipeercell_dict = {} %}
{%- do slaplte.load_peer(peer_dict) %} {%- do slaplte.load_ipeer(ipeer_dict) %}
{%- do slaplte.load_peercell(peercell_dict) %} {%- do slaplte.load_ipeercell(ipeercell_dict) %}
{%- do slaplte.check_loaded_everything() %}
{{ rulib.buildout() }} {{ rulib.buildout() }}
...@@ -209,10 +208,10 @@ url = {{ enb_template }} ...@@ -209,10 +208,10 @@ url = {{ enb_template }}
output = ${directory:etc}/enb.cfg output = ${directory:etc}/enb.cfg
extra-context = extra-context =
import json_module json import json_module json
json ru_dict {{ rulib.ru_dict | tojson }} json iru_dict {{ rulib.iru_dict | tojson }}
json cell_dict {{ rulib.cell_dict | tojson }} json icell_dict {{ rulib.icell_dict | tojson }}
json peer_dict {{ peer_dict | tojson }} json ipeer_dict {{ ipeer_dict | tojson }}
json peercell_dict {{ peercell_dict | tojson }} json ipeercell_dict {{ ipeercell_dict | tojson }}
import-list = import-list =
rawfile slaplte.jinja2 {{ slaplte_template }} rawfile slaplte.jinja2 {{ slaplte_template }}
...@@ -228,6 +227,11 @@ enb-ipv4 = {{ lan_ipv4 }} ...@@ -228,6 +227,11 @@ enb-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }} amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }} license-expiration = {{ lte_expiration }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
ru-list = {{ dumps(rulib.iru_dict.keys() | sort) }}
cell-list = {{ dumps(rulib.icell_dict.keys() | sort) }}
peer-list = {{ dumps(ipeer_dict.keys() | sort) }}
peer-cell-list = {{ dumps(ipeercell_dict.keys() | sort) }}
[monitor-instance-parameter] [monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %} {% if slapparameter_dict.get("name", None) %}
......
...@@ -47,15 +47,24 @@ ...@@ -47,15 +47,24 @@
{%- endfor %} {%- endfor %}
{#- make real cell_list to be rejected in ORS mode #} {#- make real ru/cell/peer/... shared instances to be rejected in ORS mode #}
{%- set cell_list = slapparameter_dict.setdefault('cell_list', {}) %} {%- set ishared_list = slap_configuration.setdefault('slave-instance-list', []) %}
{%- if len(cell_list) > 0 %} {%- for ishared in ishared_list %}
{%- do error('ORS mode does not support cell_list parameter') %} {%- set _ = json_module.loads(ishared['_']) %}
{%- endif %} {%- if 'ru_type' in _ or 'cell_type' in _ %}
{%- do ishared.update({'_': {'REJECT': 1}|tojson}) %}
{%- endif %}
{%- endfor %}
{#- inject ru+cell synthesized from ORS-specific parameters #} {#- inject ru+cell synthesized from ORS-specific parameters #}
{%- set ru = { {%- macro iref(name) %}
{{- '%s.%s' % (slap_configuration['instance-title'], name) -}}
{%- endmacro %}
{%- do ishared_list.append({
'slave_title': iref('RU'),
'slave_reference': False,
'_': {
'ru_type': 'sdr', 'ru_type': 'sdr',
'ru_link_type': 'sdr', 'ru_link_type': 'sdr',
'sdr_dev': 0, 'sdr_dev': 0,
...@@ -63,7 +72,8 @@ ...@@ -63,7 +72,8 @@
'n_antenna_ul': slapparameter_dict.n_antenna_ul, 'n_antenna_ul': slapparameter_dict.n_antenna_ul,
'tx_gain': ors_version['current-tx-gain'], 'tx_gain': ors_version['current-tx-gain'],
'rx_gain': ors_version['current-rx-gain'], 'rx_gain': ors_version['current-rx-gain'],
} } |tojson
})
%} %}
{%- if enb_mode == 'enb' %} {%- if enb_mode == 'enb' %}
...@@ -88,24 +98,29 @@ ...@@ -88,24 +98,29 @@
{%- endif %} {%- endif %}
{%- do cell.update({ {%- do cell.update({
'cell_kind': 'enb',
'rf_mode': slapparameter_dict.rf_mode, 'rf_mode': slapparameter_dict.rf_mode,
'pci': slapparameter_dict.pci, 'pci': slapparameter_dict.pci,
'cell_id': slapparameter_dict.cell_id, 'cell_id': slapparameter_dict.cell_id,
'tdd_ul_dl_config': slapparameter_dict.tdd_ul_dl_config, 'tdd_ul_dl_config': slapparameter_dict.tdd_ul_dl_config,
'inactivity_timer': slapparameter_dict.inactivity_timer, 'inactivity_timer': slapparameter_dict.inactivity_timer,
'ru': ru,
'ru': { 'ru_type': 'ru_ref',
'ru_ref': iref('RU') }
}) })
%} %}
{%- do cell_list.update({'CELL': cell}) %} {%- do ishared_list.append({
'slave_title': iref('CELL'),
'slave_reference': False,
'_': cell | tojson
})
%}
{#- translate ORS ncell_list to generic ncell_list #} {#- inject synthesized peer cells #}
{%- set ncell_list_ors = slapparameter_dict.ncell_list %} {%- for k, ncell in slapparameter_dict.ncell_list|dictsort %}
{%- set ncell_list = {} %} {%- set peercell = {'cell_kind': 'enb_peer'} %}
{%- do slapparameter_dict.update({'ncell_list': ncell_list}) %}
{%- for k, ncell in ncell_list_ors|dictsort %}
{%- set peercell = {} %}
{%- macro _(name, default) %} {%- macro _(name, default) %}
{%- if default is defined %} {%- if default is defined %}
{%- do peercell.update({name: default}) %} {%- do peercell.update({name: default}) %}
...@@ -132,27 +147,37 @@ ...@@ -132,27 +147,37 @@
{%- do _('tac', 1) %} {%- do _('tac', 1) %}
{%- do _('nr_band') %} {%- do _('nr_band') %}
{%- endif %} {%- endif %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('PEERCELL'), k),
'slave_reference': False,
'_': peercell | tojson
})
%}
{%- endfor %} {%- endfor %}
{#- translate ORS x2_peers/xn_peers to generic peers #} {#- inject synthesized peers #}
{%- set peers = {} %}
{%- do slapparameter_dict.update({'peers': peers}) %}
{%- if enb_mode == 'lte' %} {%- if enb_mode == 'lte' %}
{%- for k, peer in slapparameter_dict.x2_peers|dictsort %} {%- for k, peer in slapparameter_dict.x2_peers|dictsort %}
{%- do peers.update({'X2_PEER%s' % k: { {%- do ishared_list.append({
'slave_title': '%s%s' % (iref('X2_PEER'), k),
'slave_reference': False,
'_': {
'peer_type': 'nr', 'peer_type': 'nr',
'x2_addr': peer.x2_addr, 'x2_addr': peer.x2_addr,
} } | tojson
}) })
%} %}
{%- endfor %} {%- endfor %}
{%- elif enb_mode == 'nr' %} {%- elif enb_mode == 'nr' %}
{%- for k, peer in slapparameter_dict.xn_peers|dictsort %} {%- for k, peer in slapparameter_dict.xn_peers|dictsort %}
{%- do peers.update({'XN_PEER%s' % k: { {%- do ishared_list.append({
'slave_title': '%s%s' % (iref('XN_PEER'), k),
'slave_reference': False,
'_': {
'peer_type': 'nr', 'peer_type': 'nr',
'xn_addr': peer.xn_addr 'xn_addr': peer.xn_addr
} } | tojson
}) })
%} %}
{%- endfor %} {%- endfor %}
...@@ -215,14 +240,14 @@ current-nr-band = {{ ors_version['current-nr-band'] }} ...@@ -215,14 +240,14 @@ current-nr-band = {{ ors_version['current-nr-band'] }}
{%- endif %} {%- endif %}
# hide <cell>-* from published information # hide ru-list, cell-list, peer-list and peer-cell-list from published information
[publish-connection-information] [publish-connection-information]
depends += ${publish-connection-information-ors-cleanup:recipe} depends += ${publish-connection-information-ors-cleanup:recipe}
[publish-connection-information-ors-cleanup] [publish-connection-information-ors-cleanup]
recipe = slapos.recipe.build recipe = slapos.recipe.build
init = init =
publish = self.buildout['publish-connection-information'] publish = self.buildout['publish-connection-information']
cell_ref = "CELL" del publish['ru-list']
for k in publish.keys(): del publish['cell-list']
if k.startswith('%s-' % cell_ref): del publish['peer-list']
del publish[k] del publish['peer-cell-list']
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"type": "object", "type": "object",
"required": [ "required": [
"cell_type", "cell_type",
"cell_kind",
"pci", "pci",
"tac" "tac"
], ],
...@@ -13,6 +14,12 @@ ...@@ -13,6 +14,12 @@
"cell_type": { "cell_type": {
"type": "string", "type": "string",
"options": { "hidden": true } "options": { "hidden": true }
},
"cell_kind": {
"type": "string",
"const": "enb_peer",
"template": "enb_peer",
"options": { "hidden": true }
} }
} }
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"required": [ "required": [
"cell_type", "cell_type",
"cell_kind",
"pci", "pci",
"tac", "tac",
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"required": [ "required": [
"cell_type", "cell_type",
"cell_kind",
"pci", "pci",
"tac", "tac",
......
dhcp-leasefile={{ directory['etc'] }}/dnsmasq.leases dhcp-leasefile={{ directory['etc'] }}/dnsmasq.leases
port=5354 port=5354
{%- for (ru_ref, ru) in ru_dict|dictsort | selectattr('1.cpri_link', 'defined') %} {%- for (ru_ref, iru) in iru_dict|dictsort | selectattr('1._.cpri_link', 'defined') %}
{%- set ru = iru['_'] %}
{%- set ru_tap = ru.cpri_link._tap %} {%- set ru_tap = ru.cpri_link._tap %}
{%- set vtap = json_module.loads(vtap_jdict[ru_tap]) %} {%- set vtap = json_module.loads(vtap_jdict[ru_tap]) %}
{%- set plen = netaddr.IPNetwork(vtap.network).prefixlen %} {%- set plen = netaddr.IPNetwork(vtap.network).prefixlen %}
......
...@@ -7,19 +7,20 @@ ...@@ -7,19 +7,20 @@
{%- import 'slaplte.jinja2' as slaplte with context %} {%- import 'slaplte.jinja2' as slaplte with context %}
NOTE: driver-specific logic is implemented in rudrv .buildout_ru() and .buildout() . NOTE: driver-specific logic is implemented in rudrv .buildout_iru() and .buildout() .
#} #}
{#- ru_dict and cell_dict keep RU and cell registries {#- iru_dict and icell_dict keep RU and cell registries
ru_dict: reference -> ru iru_dict: reference -> iru
cell_dict: reference -> cell icell_dict: reference -> icell
#} #}
{%- set ru_dict = {} %} {%- set iru_dict = {} %}
{%- set cell_dict = {} %} {%- set icell_dict = {} %}
{%- do slaplte.load_ru_and_cell(ru_dict, cell_dict) %} {%- do slaplte.load_iru_and_icell(iru_dict, icell_dict) %}
{%- macro buildout() %} {%- macro buildout() %}
{%- set root = slap_configuration['instance-title'] %}
{%- set testing = slapparameter_dict.get("testing", False) %} {%- set testing = slapparameter_dict.get("testing", False) %}
{#- part emits new buildout section and registers it into buildout.parts #} {#- part emits new buildout section and registers it into buildout.parts #}
...@@ -31,14 +32,20 @@ ...@@ -31,14 +32,20 @@
{#- promise emits new buildout section for a promise #} {#- promise emits new buildout section for a promise #}
{%- macro promise(name) %} {%- macro promise(name) %}
{#- show in monitor RU1-... instead of COMP-ENB/RU1- #}
{%- set pretty_name = name.removeprefix('%s.' % root) %}
{{ part('promise-'+name) }} {{ part('promise-'+name) }}
<= monitor-promise-base <= monitor-promise-base
name = {{ name }}.py name = {{ pretty_name }}.py
config-testing = {{ testing }} config-testing = {{ testing }}
config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- endmacro %} {%- endmacro %}
{#- import RU drivers #} {#- import RU drivers #}
{%- set J = slaplte.J %}
{%- set jref_of_shared = slaplte.jref_of_shared %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set ierror = slaplte.ierror %}
{%- import 'ru_sdr_libinstance.jinja2.cfg' as rudrv_sdr with context %} {%- import 'ru_sdr_libinstance.jinja2.cfg' as rudrv_sdr with context %}
{%- import 'ru_lopcomm_libinstance.jinja2.cfg' as rudrv_lopcomm with context %} {%- import 'ru_lopcomm_libinstance.jinja2.cfg' as rudrv_lopcomm with context %}
{%- import 'ru_sunwave_libinstance.jinja2.cfg' as rudrv_sunwave with context %} {%- import 'ru_sunwave_libinstance.jinja2.cfg' as rudrv_sunwave with context %}
...@@ -54,7 +61,7 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} ...@@ -54,7 +61,7 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
provide several TAP interfaces to instances. See discussion at provide several TAP interfaces to instances. See discussion at
https://lab.nexedi.com/nexedi/slapos/merge_requests/1471#note_194356 https://lab.nexedi.com/nexedi/slapos/merge_requests/1471#note_194356
for details. #} for details. #}
{%- set ntap = len(list(ru_dict|dictsort | selectattr('1.cpri_link', 'defined'))) %} {%- set ntap = len(list(iru_dict|dictsort | selectattr('1._.cpri_link', 'defined'))) %}
{%- set vtap_list = [] %} {%- set vtap_list = [] %}
[vtap] [vtap]
recipe = plone.recipe.command recipe = plone.recipe.command
...@@ -148,7 +155,7 @@ context = ...@@ -148,7 +155,7 @@ context =
import netaddr netaddr import netaddr netaddr
section directory directory section directory directory
section vtap_jdict vtap_jdict section vtap_jdict vtap_jdict
json ru_dict {{ ru_dict | tojson }} json iru_dict {{ iru_dict | tojson }}
{{ part('dnsmasq-service') }} {{ part('dnsmasq-service') }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
...@@ -167,7 +174,16 @@ hash-files = ...@@ -167,7 +174,16 @@ hash-files =
{#- go through all RUs and for each RU emit generic promises and invoke {#- go through all RUs and for each RU emit generic promises and invoke
RU-specific buildout handler #} RU-specific buildout handler #}
{%- for ru_ref, ru in ru_dict|dictsort %} {%- for ru_ref, iru in iru_dict|dictsort %}
{%- set ru = iru['_'] %}
{#- cells that are using iru #}
{%- set iru_icell_list = [] %}
{%- for cell_ref, icell in icell_dict|dictsort %}
{%- if ru_ref == J(jcell_ru_ref(icell, icell_dict)) %}
{%- do iru_icell_list.append(icell) %}
{%- endif %}
{%- endfor %}
# {{ ru_ref }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type}}) # {{ ru_ref }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type}})
{%- if ru.ru_link_type == 'sdr' %} {%- if ru.ru_link_type == 'sdr' %}
...@@ -206,13 +222,15 @@ config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }} ...@@ -206,13 +222,15 @@ config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }}
{{ rudrv.buildout() }} {{ rudrv.buildout() }}
{%- do rudrv_init.update({ru.ru_type: 1}) %} {%- do rudrv_init.update({ru.ru_type: 1}) %}
{%- endif %} {%- endif %}
{{ rudrv.buildout_ru(ru_ref, ru, ru.cell_ref, cell_dict[ru.cell_ref]) }} {{ rudrv.buildout_iru(iru, iru_icell_list) }}
{%- endfor %} {%- endfor %}
{#- handle configured cells #} {#- handle configured cells #}
{%- for cell_ref, cell in cell_dict|dictsort %} {%- for cell_ref, icell in icell_dict|dictsort %}
{%- set ru_ref = cell.ru_ref %} {%- set cell = icell['_'] %}
{%- set ru = ru_dict[ru_ref] %} {%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
{#- generate CELL-drb.cfg and CELL-sib23.asn #} {#- generate CELL-drb.cfg and CELL-sib23.asn #}
{{ part('drb-config-%s' % cell_ref) }} {{ part('drb-config-%s' % cell_ref) }}
...@@ -235,7 +253,8 @@ extra-context = ...@@ -235,7 +253,8 @@ extra-context =
json ru_ref {{ ru_ref | tojson }} json ru_ref {{ ru_ref | tojson }}
json ru {{ ru | tojson }} json ru {{ ru | tojson }}
{#- publish information about the cell #} {#- publish information about the cell (skipping synthetic) #}
{%- if icell.slave_reference %}
[publish-connection-information] [publish-connection-information]
{%- if cell.cell_type == 'lte' %} {%- if cell.cell_type == 'lte' %}
{{cell_ref}}-dl_earfcn = {{ dumps(cell.dl_earfcn) }} {{cell_ref}}-dl_earfcn = {{ dumps(cell.dl_earfcn) }}
...@@ -246,6 +265,8 @@ extra-context = ...@@ -246,6 +265,8 @@ extra-context =
{%- do bug('unreachable') %} {%- do bug('unreachable') %}
{%- endif %} {%- endif %}
{%- endif %}
{%- endfor %} {%- endfor %}
{#- retrieve rf and stats[rf,samples] data from amarisoft service for promises {#- retrieve rf and stats[rf,samples] data from amarisoft service for promises
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
<!-- TX/RX carriers --> <!-- TX/RX carriers -->
<!-- TODO support multiple cells over 1 RU -->
{%- if cell.cell_type == 'lte' %} {%- if cell.cell_type == 'lte' %}
{%- set dl_arfcn = cell.dl_earfcn %} {%- set dl_arfcn = cell.dl_earfcn %}
{%- elif cell.cell_type == 'nr' %} {%- elif cell.cell_type == 'nr' %}
......
{#- Package ru/lopcomm/libinstance provides instance code for handling Lopcomm ORAN Radio Units. #} {#- Package ru/lopcomm/libinstance provides instance code for handling Lopcomm ORAN Radio Units. #}
{%- macro buildout_ru(ru_ref, ru, cell_ref, cell) %} {%- macro buildout_iru(iru, icell_list) %}
{%- set ru_ref = J(jref_of_shared(iru)) %}
{%- set ru = iru['_'] %}
{%- if len(icell_list) != 1 %}
{%- do ierror(iru, 'ru/lopcomm supports only 1 cell ; requested %d' % len(icell_list)) %}
{%- endif %}
{%- set icell = icell_list[0] %}
{%- set cell = icell['_'] %}
{#- indicate whether RU is listening for netconf #} {#- indicate whether RU is listening for netconf #}
......
{#- Package ru/sdr/libinstance provides instance code for handling SDR Radio Units. #} {#- Package ru/sdr/libinstance provides instance code for handling SDR Radio Units. #}
{%- macro buildout_ru(ru_ref, ru, cell_ref, cell) %} {%- macro buildout_iru(iru, icell_list) %}
{#- nothing SDR-specific #} {#- nothing SDR-specific #}
{%- endmacro %} {%- endmacro %}
......
{#- Package ru/sunwave/libinstance provides instance code for handling SunWave Radio Units. #} {#- Package ru/sunwave/libinstance provides instance code for handling SunWave Radio Units. #}
{%- macro buildout_ru(ru_ref, ru, cell_ref, cell) %} {%- macro buildout_iru(iru, icell_list) %}
{#- nothing SunWave-specific #} {#- nothing SunWave-specific #}
{%- endmacro %} {%- endmacro %}
......
This diff is collapsed.
...@@ -11,13 +11,49 @@ ...@@ -11,13 +11,49 @@
"response": "instance-enb-schema.json", "response": "instance-enb-schema.json",
"index": 1 "index": 1
}, },
"ru": {
"title": "→ eNB/gNB | Radio Unit",
"description": "Configuration of Radio Unit attached to eNB/gNB",
"software-type": "enb",
"shared": true,
"request": "ru/input-schema.json",
"response": "ru/schema.json",
"index": 2
},
"cell": {
"title": "→ eNB/gNB | Cell",
"description": "Configuration of Cell served by eNB/gNB",
"software-type": "enb",
"shared": true,
"request": "cell/input-schema.json",
"response": "cell/schema.json",
"index": 3
},
"peer": {
"title": "→ eNB/gNB | Peer",
"description": "Handover information about nearby eNB/gNB",
"software-type": "enb",
"shared": true,
"request": "peer/input-schema.json",
"response": "peer/schema.json",
"index": 4
},
"peer/cell": {
"title": "→ eNB/gNB | Peer Cell",
"description": "Handover information about Peer Cell served by nearby eNB/gNB",
"software-type": "enb",
"shared": true,
"request": "peer/cell/input-schema.json",
"response": "peer/cell/schema.json",
"index": 5
},
"core-network": { "core-network": {
"title": "Core Network", "title": "Core Network",
"software-type": "core-network", "software-type": "core-network",
"description": "Core Network Configuration", "description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json", "request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json", "response": "instance-core-network-schema.json",
"index": 2 "index": 6
}, },
"core-network-slave": { "core-network-slave": {
"title": "→ Core Network | Sim Card", "title": "→ Core Network | Sim Card",
...@@ -26,7 +62,7 @@ ...@@ -26,7 +62,7 @@
"request": "sim/input-schema.json", "request": "sim/input-schema.json",
"response": "sim/schema.json", "response": "sim/schema.json",
"shared": true, "shared": true,
"index": 3 "index": 7
}, },
"ue": { "ue": {
"title": "UE", "title": "UE",
...@@ -34,7 +70,7 @@ ...@@ -34,7 +70,7 @@
"software-type": "ue", "software-type": "ue",
"request": "instance-ue-input-schema.json", "request": "instance-ue-input-schema.json",
"response": "instance-ue-schema.json", "response": "instance-ue-schema.json",
"index": 4 "index": 8
} }
} }
} }
...@@ -38,6 +38,9 @@ setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass( ...@@ -38,6 +38,9 @@ setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath( os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-ors.cfg'))) os.path.join(os.path.dirname(__file__), '..', 'software-ors.cfg')))
# XXX temporary workaround for breakage when partition reference contains space.
ORSTestCase.default_partition_reference = ORSTestCase.default_partition_reference.replace(' ','-')
param_dict = { param_dict = {
'testing': True, 'testing': True,
'sim_algo': 'milenage', 'sim_algo': 'milenage',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment